summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp')
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/td/utils/logging.cpp271
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