diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp')
-rw-r--r-- | protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp | 271 |
1 files changed, 165 insertions, 106 deletions
diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp b/protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp index 17403ff87b..563575bdba 100644 --- a/protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp +++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp @@ -1,19 +1,21 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/utils/logging.h" +#include "td/utils/ExitGuard.h" #include "td/utils/port/Clocks.h" -#include "td/utils/port/Fd.h" #include "td/utils/port/thread_local.h" #include "td/utils/Slice.h" -#include "td/utils/Time.h" +#include "td/utils/TsCerr.h" #include <atomic> #include <cstdlib> +#include <limits> +#include <mutex> #if TD_ANDROID #include <android/log.h> @@ -27,115 +29,129 @@ namespace td { -int VERBOSITY_NAME(level) = VERBOSITY_NAME(DEBUG) + 1; -int VERBOSITY_NAME(net_query) = VERBOSITY_NAME(INFO); -int VERBOSITY_NAME(td_requests) = VERBOSITY_NAME(INFO); -int VERBOSITY_NAME(dc) = VERBOSITY_NAME(DEBUG) + 2; -int VERBOSITY_NAME(files) = VERBOSITY_NAME(DEBUG) + 2; -int VERBOSITY_NAME(mtproto) = VERBOSITY_NAME(DEBUG) + 7; -int VERBOSITY_NAME(connections) = VERBOSITY_NAME(DEBUG) + 8; -int VERBOSITY_NAME(raw_mtproto) = VERBOSITY_NAME(DEBUG) + 10; -int VERBOSITY_NAME(fd) = VERBOSITY_NAME(DEBUG) + 9; -int VERBOSITY_NAME(actor) = VERBOSITY_NAME(DEBUG) + 10; -int VERBOSITY_NAME(buffer) = VERBOSITY_NAME(DEBUG) + 10; -int VERBOSITY_NAME(sqlite) = VERBOSITY_NAME(DEBUG) + 10; +LogOptions log_options; + +static std::atomic<int> max_callback_verbosity_level{-2}; +static std::atomic<OnLogMessageCallback> on_log_message_callback{nullptr}; + +void set_log_message_callback(int max_verbosity_level, OnLogMessageCallback callback) { + if (callback == nullptr) { + max_verbosity_level = -2; + } + + max_callback_verbosity_level = max_verbosity_level; + on_log_message_callback = callback; +} + +void LogInterface::append(int log_level, CSlice slice) { + do_append(log_level, slice); + if (log_level == VERBOSITY_NAME(FATAL)) { + process_fatal_error(slice); + } else if (log_level <= max_callback_verbosity_level.load(std::memory_order_relaxed)) { + auto callback = on_log_message_callback.load(std::memory_order_relaxed); + if (callback != nullptr) { + callback(log_level, slice); + } + } +} TD_THREAD_LOCAL const char *Logger::tag_ = nullptr; TD_THREAD_LOCAL const char *Logger::tag2_ = nullptr; -Logger::Logger(LogInterface &log, int log_level, Slice file_name, int line_num, Slice comment, bool simple_mode) - : Logger(log, log_level, simple_mode) { - if (simple_mode) { +Logger::Logger(LogInterface &log, const LogOptions &options, int log_level, Slice file_name, int line_num, + Slice comment) + : Logger(log, options, log_level) { + if (log_level == VERBOSITY_NAME(PLAIN) && &options == &log_options) { + return; + } + if (!options_.add_info) { + return; + } + if (ExitGuard::is_exited()) { return; } - auto last_slash_ = static_cast<int32>(file_name.size()) - 1; - while (last_slash_ >= 0 && file_name[last_slash_] != '/' && file_name[last_slash_] != '\\') { - last_slash_--; + // log level + sb_ << '['; + if (static_cast<uint32>(log_level) < 10) { + sb_ << ' ' << static_cast<char>('0' + log_level); + } else { + sb_ << log_level; } - file_name = file_name.substr(last_slash_ + 1); + sb_ << ']'; + // thread id auto thread_id = get_thread_id(); + sb_ << "[t"; + if (static_cast<uint32>(thread_id) < 10) { + sb_ << ' ' << static_cast<char>('0' + thread_id); + } else { + sb_ << thread_id; + } + sb_ << ']'; - (*this) << '['; - if (log_level < 10) { - (*this) << ' '; + // timestamp + auto time = Clocks::system(); + auto unix_time = static_cast<uint32>(time); + auto nanoseconds = static_cast<uint32>((time - unix_time) * 1e9); + sb_ << '[' << unix_time << '.'; + uint32 limit = 100000000; + while (nanoseconds < limit && limit > 1) { + sb_ << '0'; + limit /= 10; } - (*this) << log_level << "][t"; - if (thread_id < 10) { - (*this) << ' '; + sb_ << nanoseconds << ']'; + + // file : line + if (!file_name.empty()) { + auto last_slash_ = static_cast<int32>(file_name.size()) - 1; + while (last_slash_ >= 0 && file_name[last_slash_] != '/' && file_name[last_slash_] != '\\') { + last_slash_--; + } + file_name = file_name.substr(last_slash_ + 1); + sb_ << '[' << file_name << ':' << static_cast<uint32>(line_num) << ']'; } - (*this) << thread_id << "][" << StringBuilder::FixedDouble(Clocks::system(), 9) << "][" << file_name << ':' - << line_num << ']'; + + // context from tag_ if (tag_ != nullptr && *tag_) { - (*this) << "[#" << Slice(tag_) << "]"; + sb_ << "[#" << Slice(tag_) << ']'; } + + // context from tag2_ if (tag2_ != nullptr && *tag2_) { - (*this) << "[!" << Slice(tag2_) << "]"; + sb_ << "[!" << Slice(tag2_) << ']'; } + + // comment (e.g. condition in LOG_IF) if (!comment.empty()) { - (*this) << "[&" << comment << "]"; + sb_ << "[&" << comment << ']'; } - (*this) << "\t"; + + sb_ << '\t'; } Logger::~Logger() { - if (!simple_mode_) { + if (ExitGuard::is_exited()) { + return; + } + if (options_.fix_newlines) { sb_ << '\n'; auto slice = as_cslice(); if (slice.back() != '\n') { slice.back() = '\n'; } - } - - log_.append(as_cslice(), log_level_); -} - -TsCerr::TsCerr() { - enterCritical(); -} -TsCerr::~TsCerr() { - exitCritical(); -} -TsCerr &TsCerr::operator<<(Slice slice) { - auto &fd = Fd::Stderr(); - if (fd.empty()) { - return *this; - } - double end_time = 0; - while (!slice.empty()) { - auto res = fd.write(slice); - if (res.is_error()) { - if (res.error().code() == EPIPE) { - break; - } - // Resource temporary unavailable - if (end_time == 0) { - end_time = Time::now() + 0.01; - } else if (Time::now() > end_time) { - break; - } - continue; + while (slice.size() > 1 && slice[slice.size() - 2] == '\n') { + slice.back() = '\0'; + slice = MutableCSlice(slice.begin(), slice.begin() + slice.size() - 1); } - slice.remove_prefix(res.ok()); + log_.append(log_level_, slice); + } else { + log_.append(log_level_, as_cslice()); } - return *this; } -void TsCerr::enterCritical() { - while (lock_.test_and_set(std::memory_order_acquire)) { - // spin - } -} - -void TsCerr::exitCritical() { - lock_.clear(std::memory_order_release); -} -TsCerr::Lock TsCerr::lock_ = ATOMIC_FLAG_INIT; - -class DefaultLog : public LogInterface { - public: - void append(CSlice slice, int log_level) override { +class DefaultLog final : public LogInterface { + void do_append(int log_level, CSlice slice) final { #if TD_ANDROID switch (log_level) { case VERBOSITY_NAME(FATAL): @@ -157,27 +173,26 @@ class DefaultLog : public LogInterface { #elif TD_TIZEN switch (log_level) { case VERBOSITY_NAME(FATAL): - dlog_print(DLOG_ERROR, DLOG_TAG, slice.c_str()); + dlog_print(DLOG_ERROR, DLOG_TAG, "%s", slice.c_str()); break; case VERBOSITY_NAME(ERROR): - dlog_print(DLOG_ERROR, DLOG_TAG, slice.c_str()); + dlog_print(DLOG_ERROR, DLOG_TAG, "%s", slice.c_str()); break; case VERBOSITY_NAME(WARNING): - dlog_print(DLOG_WARN, DLOG_TAG, slice.c_str()); + dlog_print(DLOG_WARN, DLOG_TAG, "%s", slice.c_str()); break; case VERBOSITY_NAME(INFO): - dlog_print(DLOG_INFO, DLOG_TAG, slice.c_str()); + dlog_print(DLOG_INFO, DLOG_TAG, "%s", slice.c_str()); break; default: - dlog_print(DLOG_DEBUG, DLOG_TAG, slice.c_str()); + dlog_print(DLOG_DEBUG, DLOG_TAG, "%s", slice.c_str()); break; } #elif TD_EMSCRIPTEN switch (log_level) { case VERBOSITY_NAME(FATAL): - emscripten_log( - EM_LOG_ERROR | EM_LOG_CONSOLE | EM_LOG_C_STACK | EM_LOG_JS_STACK | EM_LOG_DEMANGLE | EM_LOG_FUNC_PARAMS, - "%s", slice.c_str()); + emscripten_log(EM_LOG_ERROR | EM_LOG_CONSOLE | EM_LOG_C_STACK | EM_LOG_JS_STACK | EM_LOG_FUNC_PARAMS, "%s", + slice.c_str()); EM_ASM(throw(UTF8ToString($0)), slice.c_str()); break; case VERBOSITY_NAME(ERROR): @@ -192,28 +207,31 @@ class DefaultLog : public LogInterface { } #elif !TD_WINDOWS Slice color; + Slice no_color("\x1b[0m"); switch (log_level) { case VERBOSITY_NAME(FATAL): case VERBOSITY_NAME(ERROR): - color = TC_RED; + color = Slice("\x1b[1;31m"); // red break; case VERBOSITY_NAME(WARNING): - color = TC_YELLOW; + color = Slice("\x1b[1;33m"); // yellow break; case VERBOSITY_NAME(INFO): - color = TC_CYAN; + color = Slice("\x1b[1;36m"); // cyan + break; + default: + no_color = Slice(); break; } - TsCerr() << color << slice << TC_EMPTY; + if (!slice.empty() && slice.back() == '\n') { + TsCerr() << color << slice.substr(0, slice.size() - 1) << no_color << "\n"; + } else { + TsCerr() << color << slice << no_color; + } #else // TODO: color TsCerr() << slice; #endif - if (log_level == VERBOSITY_NAME(FATAL)) { - process_fatal_error(slice); - } - } - void rotate() override { } }; static DefaultLog default_log; @@ -221,18 +239,59 @@ static DefaultLog default_log; LogInterface *const default_log_interface = &default_log; LogInterface *log_interface = default_log_interface; -static OnFatalErrorCallback on_fatal_error_callback = nullptr; +void process_fatal_error(CSlice message) { + if (0 <= max_callback_verbosity_level.load(std::memory_order_relaxed)) { + auto callback = on_log_message_callback.load(std::memory_order_relaxed); + if (callback != nullptr) { + callback(0, message); + } + } -void set_log_fatal_error_callback(OnFatalErrorCallback callback) { - on_fatal_error_callback = callback; + std::abort(); } -void process_fatal_error(CSlice message) { - auto callback = on_fatal_error_callback; - if (callback) { - callback(message); +static std::atomic<uint32> log_guard; + +LogGuard::LogGuard() { + uint32 expected = 0; + while (!log_guard.compare_exchange_strong(expected, 1, std::memory_order_relaxed, std::memory_order_relaxed)) { + // spin + CHECK(expected == 1); + expected = 0; } - std::abort(); } +LogGuard::~LogGuard() { + CHECK(log_guard.load(std::memory_order_relaxed) == 1); + log_guard.store(0, std::memory_order_relaxed); +} + +bool has_log_guard() { + return log_guard.load(std::memory_order_relaxed) == 1; +} + +namespace { +std::mutex sdl_mutex; +int sdl_cnt = 0; +int sdl_verbosity = 0; +} // namespace + +ScopedDisableLog::ScopedDisableLog() { + std::unique_lock<std::mutex> guard(sdl_mutex); + if (sdl_cnt == 0) { + sdl_verbosity = set_verbosity_level(std::numeric_limits<int>::min()); + } + sdl_cnt++; +} + +ScopedDisableLog::~ScopedDisableLog() { + std::unique_lock<std::mutex> guard(sdl_mutex); + sdl_cnt--; + if (sdl_cnt == 0) { + set_verbosity_level(sdl_verbosity); + } +} + +static ExitGuard exit_guard; + } // namespace td |