17 #include <string_view> 18 #include <system_error> 19 #include <type_traits> 20 #include <unordered_set> 25 #if defined(__cpp_lib_syncbuf) && __cpp_lib_syncbuf >= 201803L 26 #define FCITX_HAS_SYNCSTREAM 1 29 #define FCITX_HAS_SYNCSTREAM 0 38 FCITX_DEFINE_LOG_CATEGORY(defaultCategory,
"default");
40 using LogRule = std::pair<std::string, LogLevel>;
43 static std::ostream *defaultLogStream;
44 #if FCITX_HAS_SYNCSTREAM 45 static thread_local std::osyncstream localLogStream;
47 static bool showTimeDate;
50 std::ostream *LogConfig::defaultLogStream = &std::cerr;
51 #if FCITX_HAS_SYNCSTREAM 52 thread_local std::osyncstream LogConfig::localLogStream = []() {
53 std::osyncstream out(*LogConfig::defaultLogStream);
54 out.rdbuf()->set_emit_on_sync(
true);
58 bool LogConfig::showTimeDate =
true;
60 bool validateLogLevel(std::underlying_type_t<LogLevel> l) {
62 l <= std::underlying_type_t<LogLevel>(LogLevel::LastLogLevel));
67 static LogRegistry &instance() {
68 static LogRegistry instance_;
72 void registerCategory(LogCategory &category) {
73 std::lock_guard<std::mutex> lock(mutex_);
74 if (!categories_.contains(&category)) {
75 categories_.insert(&category);
80 void unregisterCategory(LogCategory &category) {
81 std::lock_guard<std::mutex> lock(mutex_);
82 categories_.erase(&category);
85 void setLogRules(
const std::vector<LogRule> &rules) {
86 std::lock_guard<std::mutex> lock(mutex_);
90 for (
auto *category : categories_) {
95 void applyRule(LogCategory *category) {
96 category->resetLogLevel();
97 for (
auto &rule : rules_) {
98 if (rule.first ==
"*" || rule.first == category->name()) {
99 category->setLogLevel(rule.second);
105 std::unordered_set<LogCategory *> categories_;
106 std::vector<LogRule> rules_;
114 : name_(name), level_(level), defaultLevel_(level) {}
121 LogCategory::LogCategory(
const char *name,
LogLevel level)
122 : d_ptr(std::make_unique<LogCategoryPrivate>(name, level)) {
123 LogRegistry::instance().registerCategory(*
this);
126 LogCategory::~LogCategory() {
127 LogRegistry::instance().unregisterCategory(*
this);
130 bool LogCategory::checkLogLevel(
LogLevel l)
const {
132 return l != LogLevel::NoLog &&
133 static_cast<std::underlying_type_t<LogLevel>
>(l) <=
134 static_cast<std::underlying_type_t<LogLevel>
>(d->level_);
137 void LogCategory::resetLogLevel() {
139 d->level_ = d->defaultLevel_;
142 void LogCategory::setLogLevel(std::underlying_type_t<LogLevel> l) {
143 if (validateLogLevel(l)) {
144 setLogLevel(static_cast<LogLevel>(l));
148 void LogCategory::setLogLevel(
LogLevel l) {
153 LogLevel LogCategory::logLevel()
const {
158 const std::string &LogCategory::name()
const {
163 bool LogCategory::fatalWrapper(
LogLevel level)
const {
165 bool needLog = checkLogLevel(level);
172 bool LogCategory::fatalWrapper2(
LogLevel level) {
179 const LogCategory &Log::defaultCategory() {
return fcitx::defaultCategory(); }
181 void Log::setLogRule(
const std::string &ruleString) {
182 std::vector<LogRule> parsedRules;
184 for (
const auto &rule : rules) {
185 if (rule ==
"notimedate") {
186 LogConfig::showTimeDate =
false;
191 if (ruleItem.size() != 2) {
194 auto &name = ruleItem[0];
196 if (std::from_chars(ruleItem[1].data(),
197 ruleItem[1].data() + ruleItem[1].size(), level)
198 .ec == std::errc()) {
199 if (validateLogLevel(level)) {
200 parsedRules.emplace_back(name, static_cast<LogLevel>(level));
204 LogRegistry::instance().setLogRules(parsedRules);
208 LogConfig::defaultLogStream = &stream;
212 #if FCITX_HAS_SYNCSTREAM 213 auto *buf = LogConfig::defaultLogStream->rdbuf();
214 if (LogConfig::localLogStream.get_wrapped() != buf) {
215 LogConfig::localLogStream = std::osyncstream(buf);
216 LogConfig::localLogStream.rdbuf()->set_emit_on_sync(
true);
218 return LogConfig::localLogStream;
220 return *LogConfig::defaultLogStream;
224 LogMessageBuilder::LogMessageBuilder(std::ostream &out,
LogLevel l,
225 const char *filename,
int lineNumber)
231 case LogLevel::Debug:
240 case LogLevel::Error:
247 if (LogConfig::showTimeDate) {
249 auto now = std::chrono::time_point_cast<std::chrono::microseconds>(
250 std::chrono::system_clock::now());
251 #if __cpp_lib_chrono >= 201907L 252 const auto *current_zone = std::chrono::current_zone();
253 std::chrono::zoned_time zoned_time{current_zone, now};
255 auto timeString = std::format(
"{:%F %T}", zoned_time);
257 auto timeString = std::format(
"{:%F %T}", now);
259 out_ << timeString <<
" ";
264 out_ << filename <<
":" << lineNumber <<
"] ";
267 LogMessageBuilder::~LogMessageBuilder() {
LogLevel
LogLevel from high to low.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
static void setLogStream(std::ostream &stream)
set the global log stream to be used by default.
static std::ostream & logStream()
Return the default log stream to be used.
Fatal will always abort regardless of log or not.