mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	https://howardhinnant.github.io/date/date.html All logs will display a datetime in format "2021-02-23 12:57:21.1023272" UTC, instead of simply displaying double formatted timestamp. Update ccpp-linux.yml Soon github actions will use ubuntu 20.04 as latest. Let's avoid surprised and stick to ubuntu-18.04 fow now.
		
			
				
	
	
		
			305 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     This file is part of TON Blockchain Library.
 | |
| 
 | |
|     TON Blockchain Library is free software: you can redistribute it and/or modify
 | |
|     it under the terms of the GNU Lesser General Public License as published by
 | |
|     the Free Software Foundation, either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     TON Blockchain Library is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU Lesser General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public License
 | |
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
|     Copyright 2017-2020 Telegram Systems LLP
 | |
| */
 | |
| #include "td/utils/logging.h"
 | |
| 
 | |
| #include "td/utils/port/Clocks.h"
 | |
| #include "td/utils/port/StdStreams.h"
 | |
| #include "td/utils/port/thread_local.h"
 | |
| #include "td/utils/Slice.h"
 | |
| #include "td/utils/Time.h"
 | |
| #include "td/utils/date.h"
 | |
| 
 | |
| #include <atomic>
 | |
| #include <cstdlib>
 | |
| #include <mutex>
 | |
| 
 | |
| #if TD_ANDROID
 | |
| #include <android/log.h>
 | |
| #define ALOG_TAG "DLTD"
 | |
| #elif TD_TIZEN
 | |
| #include <dlog.h>
 | |
| #define DLOG_TAG "DLTD"
 | |
| #elif TD_EMSCRIPTEN
 | |
| #include <emscripten.h>
 | |
| #endif
 | |
| 
 | |
| namespace td {
 | |
| 
 | |
| 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(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(sqlite) = VERBOSITY_NAME(DEBUG) + 10;
 | |
| 
 | |
| LogOptions log_options;
 | |
| 
 | |
| TD_THREAD_LOCAL const char *Logger::tag_ = nullptr;
 | |
| TD_THREAD_LOCAL const char *Logger::tag2_ = nullptr;
 | |
| 
 | |
| 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;
 | |
|   }
 | |
| 
 | |
|   using namespace date;
 | |
| 
 | |
|   // log level
 | |
|   sb_ << '[';
 | |
|   if (log_level < 10) {
 | |
|     sb_ << ' ';
 | |
|   }
 | |
|   sb_ << log_level << ']';
 | |
| 
 | |
|   // thread id
 | |
|   auto thread_id = get_thread_id();
 | |
|   sb_ << "[t";
 | |
|   if (thread_id < 10) {
 | |
|     sb_ << ' ';
 | |
|   }
 | |
|   sb_ << thread_id << ']';
 | |
| 
 | |
|   // timestamp
 | |
|   //sb_ << '[' << StringBuilder::FixedDouble(Clocks::system(), 9) << ']';
 | |
|   sb_ << '[' << date::format("%F %T", std::chrono::system_clock::now()) << ']';
 | |
| 
 | |
|   // 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 << ':' << line_num << ']';
 | |
|   }
 | |
| 
 | |
|   // context from tag_
 | |
|   if (tag_ != nullptr && *tag_) {
 | |
|     sb_ << "[#" << Slice(tag_) << ']';
 | |
|   }
 | |
| 
 | |
|   // context from tag2_
 | |
|   if (tag2_ != nullptr && *tag2_) {
 | |
|     sb_ << "[!" << Slice(tag2_) << ']';
 | |
|   }
 | |
| 
 | |
|   // comment (e.g. condition in LOG_IF)
 | |
|   if (!comment.empty()) {
 | |
|     sb_ << "[&" << comment << ']';
 | |
|   }
 | |
| 
 | |
|   sb_ << '\t';
 | |
| }
 | |
| 
 | |
| Logger::~Logger() {
 | |
|   if (options_.fix_newlines) {
 | |
|     sb_ << '\n';
 | |
|     auto slice = as_cslice();
 | |
|     if (slice.back() != '\n') {
 | |
|       slice.back() = '\n';
 | |
|     }
 | |
|     while (slice.size() > 1 && slice[slice.size() - 2] == '\n') {
 | |
|       slice.back() = '\0';
 | |
|       slice = MutableCSlice(slice.begin(), slice.begin() + slice.size() - 1);
 | |
|     }
 | |
|     log_.append(slice, log_level_);
 | |
|   } else {
 | |
|     log_.append(as_cslice(), log_level_);
 | |
|   }
 | |
| }
 | |
| 
 | |
| TsCerr::TsCerr() {
 | |
|   enterCritical();
 | |
| }
 | |
| TsCerr::~TsCerr() {
 | |
|   exitCritical();
 | |
| }
 | |
| TsCerr &TsCerr::operator<<(Slice slice) {
 | |
|   auto &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;
 | |
|     }
 | |
|     slice.remove_prefix(res.ok());
 | |
|   }
 | |
|   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 {
 | |
| #if TD_ANDROID
 | |
|     switch (log_level) {
 | |
|       case VERBOSITY_NAME(FATAL):
 | |
|         __android_log_write(ANDROID_LOG_FATAL, ALOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(ERROR):
 | |
|         __android_log_write(ANDROID_LOG_ERROR, ALOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(WARNING):
 | |
|         __android_log_write(ANDROID_LOG_WARN, ALOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(INFO):
 | |
|         __android_log_write(ANDROID_LOG_INFO, ALOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       default:
 | |
|         __android_log_write(ANDROID_LOG_DEBUG, ALOG_TAG, slice.c_str());
 | |
|         break;
 | |
|     }
 | |
| #elif TD_TIZEN
 | |
|     switch (log_level) {
 | |
|       case VERBOSITY_NAME(FATAL):
 | |
|         dlog_print(DLOG_ERROR, DLOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(ERROR):
 | |
|         dlog_print(DLOG_ERROR, DLOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(WARNING):
 | |
|         dlog_print(DLOG_WARN, DLOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(INFO):
 | |
|         dlog_print(DLOG_INFO, DLOG_TAG, slice.c_str());
 | |
|         break;
 | |
|       default:
 | |
|         dlog_print(DLOG_DEBUG, DLOG_TAG, 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());
 | |
|         EM_ASM(throw(UTF8ToString($0)), slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(ERROR):
 | |
|         emscripten_log(EM_LOG_ERROR | EM_LOG_CONSOLE, "%s", slice.c_str());
 | |
|         break;
 | |
|       case VERBOSITY_NAME(WARNING):
 | |
|         emscripten_log(EM_LOG_WARN | EM_LOG_CONSOLE, "%s", slice.c_str());
 | |
|         break;
 | |
|       default:
 | |
|         emscripten_log(EM_LOG_CONSOLE, "%s", slice.c_str());
 | |
|         break;
 | |
|     }
 | |
| #elif !TD_WINDOWS
 | |
|     Slice color;
 | |
|     switch (log_level) {
 | |
|       case VERBOSITY_NAME(FATAL):
 | |
|       case VERBOSITY_NAME(ERROR):
 | |
|         color = Slice(TC_RED);
 | |
|         break;
 | |
|       case VERBOSITY_NAME(WARNING):
 | |
|         color = Slice(TC_YELLOW);
 | |
|         break;
 | |
|       case VERBOSITY_NAME(INFO):
 | |
|         color = Slice(TC_CYAN);
 | |
|         break;
 | |
|     }
 | |
|     if (!slice.empty() && slice.back() == '\n') {
 | |
|       TsCerr() << color << slice.substr(0, slice.size() - 1) << TC_EMPTY "\n";
 | |
|     } else {
 | |
|       TsCerr() << color << slice << TC_EMPTY;
 | |
|     }
 | |
| #else
 | |
|     // TODO: color
 | |
|     TsCerr() << slice;
 | |
| #endif
 | |
|     if (log_level == VERBOSITY_NAME(FATAL)) {
 | |
|       process_fatal_error(slice);
 | |
|     }
 | |
|   }
 | |
|   void rotate() override {
 | |
|   }
 | |
| };
 | |
| 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 set_log_fatal_error_callback(OnFatalErrorCallback callback) {
 | |
|   on_fatal_error_callback = callback;
 | |
| }
 | |
| 
 | |
| void process_fatal_error(CSlice message) {
 | |
|   auto callback = on_fatal_error_callback;
 | |
|   if (callback) {
 | |
|     callback(message);
 | |
|   }
 | |
|   std::abort();
 | |
| }
 | |
| 
 | |
| 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);
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace td
 |