17 #include <string_view> 18 #include <system_error> 19 #include <type_traits> 20 #include <unordered_set> 32 FCITX_DEFINE_LOG_CATEGORY(defaultCategory,
"default");
34 using LogRule = std::pair<std::string, LogLevel>;
37 static std::ostream *defaultLogStream;
38 static thread_local std::osyncstream localLogStream;
39 static bool showTimeDate;
42 std::ostream *LogConfig::defaultLogStream = &std::cerr;
43 thread_local std::osyncstream LogConfig::localLogStream = []() {
44 std::osyncstream out(*LogConfig::defaultLogStream);
45 out.rdbuf()->set_emit_on_sync(
true);
48 bool LogConfig::showTimeDate =
true;
50 bool validateLogLevel(std::underlying_type_t<LogLevel> l) {
52 l <= std::underlying_type_t<LogLevel>(LogLevel::LastLogLevel));
57 static LogRegistry &instance() {
58 static LogRegistry instance_;
62 void registerCategory(LogCategory &category) {
63 std::lock_guard<std::mutex> lock(mutex_);
64 if (!categories_.contains(&category)) {
65 categories_.insert(&category);
70 void unregisterCategory(LogCategory &category) {
71 std::lock_guard<std::mutex> lock(mutex_);
72 categories_.erase(&category);
75 void setLogRules(
const std::vector<LogRule> &rules) {
76 std::lock_guard<std::mutex> lock(mutex_);
80 for (
auto *category : categories_) {
85 void applyRule(LogCategory *category) {
86 category->resetLogLevel();
87 for (
auto &rule : rules_) {
88 if (rule.first ==
"*" || rule.first == category->name()) {
89 category->setLogLevel(rule.second);
95 std::unordered_set<LogCategory *> categories_;
96 std::vector<LogRule> rules_;
104 : name_(name), level_(level), defaultLevel_(level) {}
111 LogCategory::LogCategory(
const char *name,
LogLevel level)
112 : d_ptr(std::make_unique<LogCategoryPrivate>(name, level)) {
113 LogRegistry::instance().registerCategory(*
this);
116 LogCategory::~LogCategory() {
117 LogRegistry::instance().unregisterCategory(*
this);
120 bool LogCategory::checkLogLevel(
LogLevel l)
const {
122 return l != LogLevel::NoLog &&
123 static_cast<std::underlying_type_t<LogLevel>
>(l) <=
124 static_cast<std::underlying_type_t<LogLevel>
>(d->level_);
127 void LogCategory::resetLogLevel() {
129 d->level_ = d->defaultLevel_;
132 void LogCategory::setLogLevel(std::underlying_type_t<LogLevel> l) {
133 if (validateLogLevel(l)) {
134 setLogLevel(static_cast<LogLevel>(l));
138 void LogCategory::setLogLevel(
LogLevel l) {
143 LogLevel LogCategory::logLevel()
const {
148 const std::string &LogCategory::name()
const {
153 bool LogCategory::fatalWrapper(
LogLevel level)
const {
155 bool needLog = checkLogLevel(level);
162 bool LogCategory::fatalWrapper2(
LogLevel level) {
169 const LogCategory &Log::defaultCategory() {
return fcitx::defaultCategory(); }
171 void Log::setLogRule(
const std::string &ruleString) {
172 std::vector<LogRule> parsedRules;
174 for (
const auto &rule : rules) {
175 if (rule ==
"notimedate") {
176 LogConfig::showTimeDate =
false;
181 if (ruleItem.size() != 2) {
184 auto &name = ruleItem[0];
186 if (std::from_chars(ruleItem[1].data(),
187 ruleItem[1].data() + ruleItem[1].size(), level)
188 .ec == std::errc()) {
189 if (validateLogLevel(level)) {
190 parsedRules.emplace_back(name, static_cast<LogLevel>(level));
194 LogRegistry::instance().setLogRules(parsedRules);
198 LogConfig::defaultLogStream = &stream;
202 auto *buf = LogConfig::defaultLogStream->rdbuf();
203 if (LogConfig::localLogStream.get_wrapped() != buf) {
204 LogConfig::localLogStream = std::osyncstream(buf);
205 LogConfig::localLogStream.rdbuf()->set_emit_on_sync(
true);
207 return LogConfig::localLogStream;
210 LogMessageBuilder::LogMessageBuilder(std::ostream &out,
LogLevel l,
211 const char *filename,
int lineNumber)
217 case LogLevel::Debug:
226 case LogLevel::Error:
233 if (LogConfig::showTimeDate) {
235 auto now = std::chrono::time_point_cast<std::chrono::microseconds>(
236 std::chrono::system_clock::now());
237 #if __cpp_lib_chrono >= 201907L 238 const auto *current_zone = std::chrono::current_zone();
239 std::chrono::zoned_time zoned_time{current_zone, now};
241 auto timeString = std::format(
"{:%F %T}", zoned_time);
243 auto timeString = std::format(
"{:%F %T}", now);
245 out_ << timeString <<
" ";
250 out_ << filename <<
":" << lineNumber <<
"] ";
253 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.