diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bf3766df..c01a9423e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,6 +377,7 @@ set(TDLIB_SOURCE td/telegram/InputMessageText.cpp td/telegram/LanguagePackManager.cpp td/telegram/Location.cpp + td/telegram/Logging.cpp td/telegram/MessageContent.cpp td/telegram/MessageEntity.cpp td/telegram/MessagesDb.cpp @@ -500,6 +501,7 @@ set(TDLIB_SOURCE td/telegram/logevent/LogEvent.h td/telegram/logevent/LogEventHelper.h td/telegram/logevent/SecretChatEvent.h + td/telegram/Logging.h td/telegram/MessageContent.h td/telegram/MessageEntity.h td/telegram/MessageId.h diff --git a/SplitSource.php b/SplitSource.php index 826826449..c6d9dde0c 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -147,7 +147,6 @@ function split_file($file, $chunks, $undo) { '(CREATE_REQUEST|CREATE_NO_ARGS_REQUEST)[(](?[A-Z][A-Za-z]*)|'. '(?complete_pending_preauthentication_requests)|'. '(Up|Down)load[a-zA-Z]*C(?allback)|(up|down)load_[a-z_]*_c(?allback)_|'. - '(?V)(LOG.td_init|ERBOSITY_NAME)|'. '(?LogEvent)[^sA]|'. '(?parse)[(]|'. '(?store)[(]/', $f, $matches, PREG_SET_ORDER)) { diff --git a/td/generate/DotnetTlDocumentationGenerator.php b/td/generate/DotnetTlDocumentationGenerator.php index fd99c0c42..6f44cf6ef 100644 --- a/td/generate/DotnetTlDocumentationGenerator.php +++ b/td/generate/DotnetTlDocumentationGenerator.php @@ -8,7 +8,7 @@ class DotnetTlDocumentationGenerator extends TlDocumentationGenerator { $doc = htmlspecialchars($doc, ENT_XML1); $doc = str_replace('*/', '*/', $doc); - $doc = preg_replace_callback('/_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc); + $doc = preg_replace_callback('/(? = Updates; +//@class LogStream @description Describes a stream to which TDLib internal log is written + +//@description The log is written to stderr or an OS specific log +logStreamDefault = LogStream; + +//@description TDLib needs TdlibParameters for initialization @path Path to the file to where the internal TDLib log will be written @max_file_size Maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated +logStreamFile path:string max_file_size:int53 = LogStream; + +//@description The log is written nowhere +logStreamEmpty = LogStream; + + +//@description Contains a TDLib internal log verbosity level @verbosity_level Log verbosity level +logVerbosityLevel verbosity_level:int32 = LogVerbosityLevel; + +//@description Contains a list of available TDLib internal log tags @tags List of log tags +logTags tags:vector = LogTags; + + //@description A simple object containing a number; for testing only @value Number testInt value:int32 = TestInt; //@description A simple object containing a string; for testing only @value String @@ -3378,6 +3397,30 @@ getProxyLink proxy_id:int32 = Text; pingProxy proxy_id:int32 = Seconds; +//@description Sets new log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously @log_stream New log stream +setLogStream log_stream:LogStream = Ok; + +//@description Returns information about currently used log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +getLogStream = LogStream; + +//@description Sets the verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +//@new_verbosity_level New value of the verbosity level for logging. Value 0 corresponds to fatal errors, value 1 corresponds to errors, value 2 corresponds to warnings and debug warnings, value 3 corresponds to informational, value 4 corresponds to debug, value 5 corresponds to verbose debug, value greater than 5 and up to 1023 can be used to enable even more logging +setLogVerbosityLevel new_verbosity_level:int32 = Ok; + +//@description Returns current verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +getLogVerbosityLevel = LogVerbosityLevel; + +//@description Returns list of available TDLib internal log tags. Currently returns ["td_init", "update_file", "connections", "binlog", "proxy", "net_query", "td_requests", "dc", "files", "mtproto", "raw_mtproto", "fd", "actor", "buffer", "sqlite"] +getLogTags = LogTags; + +//@description Sets the verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously +//@tag Logging tag to change verbosity level @new_verbosity_level New verbosity level; 1-1024 +setLogTagVerbosityLevel tag:string new_verbosity_level:int32 = Ok; + +//@description Returns current verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously @tag Logging tag to change verbosity level +getLogTagVerbosityLevel tag:string = LogVerbosityLevel; + + //@description Does nothing; for testing only testCallEmpty = Ok; //@description Returns the received string; for testing only @x String to return @@ -3402,7 +3445,3 @@ testGetDifference = Ok; testUseUpdate = Update; //@description Does nothing and ensures that the Error object is used; for testing only testUseError = Error; -//@description Changes verbosity level for a specified log tag; for testing only. This is an offline method. Can be called before authorization. Can be called synchronously -//@tag Logging tag to change verbosity level (one of "td_init", "update_file", "connections", "binlog", "proxy", "net_query", "td_requests", "dc", "files", "mtproto", "raw_mtproto", "fd", "actor", "buffer", "sqlite") -//@new_verbosity_level New verbosity level; 1-1024 -testSetLogTagVerbosityLevel tag:string new_verbosity_level:int32 = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 1604efac6..ca3a51b0e 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/Log.cpp b/td/telegram/Log.cpp index b712b8217..26bcd31fc 100644 --- a/td/telegram/Log.cpp +++ b/td/telegram/Log.cpp @@ -6,8 +6,9 @@ // #include "td/telegram/Log.h" +#include "td/telegram/Logging.h" + #include "td/utils/common.h" -#include "td/utils/FileLog.h" #include "td/utils/logging.h" #include "td/utils/Slice.h" @@ -16,8 +17,7 @@ namespace td { static std::mutex log_mutex; -static FileLog file_log; -static TsLog ts_log(&file_log); +static string log_file_path; static int64 max_log_file_size = 10 << 20; static Log::FatalErrorCallbackPtr fatal_error_callback; @@ -29,12 +29,12 @@ static void fatal_error_callback_wrapper(CSlice message) { bool Log::set_file_path(string file_path) { std::lock_guard lock(log_mutex); if (file_path.empty()) { - log_interface = default_log_interface; - return true; + log_file_path.clear(); + return Logging::set_current_stream(td_api::make_object()).is_ok(); } - if (file_log.init(file_path, max_log_file_size)) { - log_interface = &ts_log; + if (Logging::set_current_stream(td_api::make_object(file_path, max_log_file_size)).is_ok()) { + log_file_path = std::move(file_path); return true; } @@ -43,15 +43,13 @@ bool Log::set_file_path(string file_path) { void Log::set_max_file_size(int64 max_file_size) { std::lock_guard lock(log_mutex); - max_log_file_size = max(max_file_size, static_cast(0)); - file_log.set_rotate_threshold(max_log_file_size); + max_log_file_size = max(max_file_size, static_cast(1)); + Logging::set_current_stream(td_api::make_object(log_file_path, max_log_file_size)).ignore(); } void Log::set_verbosity_level(int new_verbosity_level) { std::lock_guard lock(log_mutex); - if (0 <= new_verbosity_level && new_verbosity_level <= 1024) { - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + new_verbosity_level); - } + Logging::set_verbosity_level(new_verbosity_level).ignore(); } void Log::set_fatal_error_callback(FatalErrorCallbackPtr callback) { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 596d8397b..18e5410b5 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -39,6 +39,7 @@ #include "td/telegram/HashtagHints.h" #include "td/telegram/InlineQueriesManager.h" #include "td/telegram/LanguagePackManager.h" +#include "td/telegram/Logging.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesManager.h" @@ -76,8 +77,6 @@ #include "td/mtproto/utils.h" // for create_storer, fetch_result, etc, TODO -#include "tdnet/td/net/TransparentProxy.h" - #include "td/utils/buffer.h" #include "td/utils/filesystem.h" #include "td/utils/format.h" @@ -3116,7 +3115,13 @@ bool Td::is_synchronous_request(int32 id) { case td_api::getFileExtension::ID: case td_api::cleanFileName::ID: case td_api::getLanguagePackString::ID: - case td_api::testSetLogTagVerbosityLevel::ID: + case td_api::setLogStream::ID: + case td_api::getLogStream::ID: + case td_api::setLogVerbosityLevel::ID: + case td_api::getLogVerbosityLevel::ID: + case td_api::getLogTags::ID: + case td_api::setLogTagVerbosityLevel::ID: + case td_api::getLogTagVerbosityLevel::ID: return true; default: return false; @@ -6715,6 +6720,34 @@ void Td::on_request(uint64 id, const td_api::getLanguagePackString &request) { UNREACHABLE(); } +void Td::on_request(uint64 id, const td_api::setLogStream &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::getLogStream &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::setLogVerbosityLevel &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::getLogVerbosityLevel &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::getLogTags &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request) { + UNREACHABLE(); +} + +void Td::on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request) { + UNREACHABLE(); +} + td_api::object_ptr Td::do_static_request(const td_api::getTextEntities &request) { if (!check_utf8(request.text_)) { return make_error(400, "Text must be encoded in UTF-8"); @@ -6769,6 +6802,59 @@ td_api::object_ptr Td::do_static_request(const td_api::getLangua request.language_pack_database_path_, request.localization_target_, request.language_pack_id_, request.key_); } +td_api::object_ptr Td::do_static_request(td_api::setLogStream &request) { + auto result = Logging::set_current_stream(std::move(request.log_stream_)); + if (result.is_ok()) { + return td_api::make_object(); + } else { + return make_error(400, result.message()); + } +} + +td_api::object_ptr Td::do_static_request(const td_api::getLogStream &request) { + auto result = Logging::get_current_stream(); + if (result.is_ok()) { + return result.move_as_ok(); + } else { + return make_error(400, result.error().message()); + } +} + +td_api::object_ptr Td::do_static_request(const td_api::setLogVerbosityLevel &request) { + auto result = Logging::set_verbosity_level(static_cast(request.new_verbosity_level_)); + if (result.is_ok()) { + return td_api::make_object(); + } else { + return make_error(400, result.message()); + } +} + +td_api::object_ptr Td::do_static_request(const td_api::getLogVerbosityLevel &request) { + return td_api::make_object(Logging::get_verbosity_level()); +} + +td_api::object_ptr Td::do_static_request(const td_api::getLogTags &request) { + return td_api::make_object(Logging::get_tags()); +} + +td_api::object_ptr Td::do_static_request(const td_api::setLogTagVerbosityLevel &request) { + auto result = Logging::set_tag_verbosity_level(request.tag_, static_cast(request.new_verbosity_level_)); + if (result.is_ok()) { + return td_api::make_object(); + } else { + return make_error(400, result.message()); + } +} + +td_api::object_ptr Td::do_static_request(const td_api::getLogTagVerbosityLevel &request) { + auto result = Logging::get_tag_verbosity_level(request.tag_); + if (result.is_ok()) { + return td_api::make_object(result.ok()); + } else { + return make_error(400, result.error().message()); + } +} + // test void Td::on_request(uint64 id, td_api::testNetwork &request) { create_handler(id)->send(); @@ -6779,69 +6865,6 @@ void Td::on_request(uint64 id, td_api::testGetDifference &request) { send_closure(actor_id(this), &Td::send_result, id, make_tl_object()); } -int *Td::get_log_verbosity_level(Slice name) { - if (name == "td_init") { - return &VERBOSITY_NAME(td_init); - } - if (name == "update_file") { - return &VERBOSITY_NAME(update_file); - } - if (name == "connections") { - return &VERBOSITY_NAME(connections); - } - if (name == "binlog") { - return &VERBOSITY_NAME(binlog); - } - if (name == "proxy") { - return &VERBOSITY_NAME(proxy); - } - if (name == "net_query") { - return &VERBOSITY_NAME(net_query); - } - if (name == "td_requests") { - return &VERBOSITY_NAME(td_requests); - } - if (name == "dc") { - return &VERBOSITY_NAME(dc); - } - if (name == "files") { - return &VERBOSITY_NAME(files); - } - if (name == "mtproto") { - return &VERBOSITY_NAME(mtproto); - } - if (name == "raw_mtproto") { - return &VERBOSITY_NAME(raw_mtproto); - } - if (name == "fd") { - return &VERBOSITY_NAME(fd); - } - if (name == "actor") { - return &VERBOSITY_NAME(actor); - } - if (name == "buffer") { - return &VERBOSITY_NAME(buffer); - } - if (name == "sqlite") { - return &VERBOSITY_NAME(sqlite); - } - return nullptr; -} - -void Td::on_request(uint64 id, td_api::testSetLogTagVerbosityLevel &request) { - UNREACHABLE(); -} - -td_api::object_ptr Td::do_static_request(const td_api::testSetLogTagVerbosityLevel &request) { - int *level = get_log_verbosity_level(request.tag_); - if (level == nullptr) { - return td_api::make_object(400, "Log tag is not found"); - } - *level = clamp(static_cast(request.new_verbosity_level_), 1, VERBOSITY_NAME(NEVER)); - - return td_api::make_object(); -} - void Td::on_request(uint64 id, td_api::testUseUpdate &request) { send_closure(actor_id(this), &Td::send_result, id, nullptr); } diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 22b4b0cd4..e8a10ee14 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -67,6 +67,8 @@ class WebPagesManager; namespace td { +extern int VERBOSITY_NAME(td_init); + // Td may start closing after explicit "close" or "destroy" query. // Or it may start closing by itself, because authorization is lost. // It any case the parent will be notified via updateAuthorizationState. @@ -912,10 +914,23 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getLanguagePackString &request); + void on_request(uint64 id, const td_api::setLogStream &request); + + void on_request(uint64 id, const td_api::getLogStream &request); + + void on_request(uint64 id, const td_api::setLogVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogTags &request); + + void on_request(uint64 id, const td_api::setLogTagVerbosityLevel &request); + + void on_request(uint64 id, const td_api::getLogTagVerbosityLevel &request); + // test void on_request(uint64 id, td_api::testNetwork &request); void on_request(uint64 id, td_api::testGetDifference &request); - void on_request(uint64 id, td_api::testSetLogTagVerbosityLevel &request); void on_request(uint64 id, td_api::testUseUpdate &request); void on_request(uint64 id, td_api::testUseError &request); void on_request(uint64 id, td_api::testCallEmpty &request); @@ -937,7 +952,13 @@ class Td final : public NetQueryCallback { static td_api::object_ptr do_static_request(const td_api::getFileExtension &request); static td_api::object_ptr do_static_request(const td_api::cleanFileName &request); static td_api::object_ptr do_static_request(const td_api::getLanguagePackString &request); - static td_api::object_ptr do_static_request(const td_api::testSetLogTagVerbosityLevel &request); + static td_api::object_ptr do_static_request(td_api::setLogStream &request); + static td_api::object_ptr do_static_request(const td_api::getLogStream &request); + static td_api::object_ptr do_static_request(const td_api::setLogVerbosityLevel &request); + static td_api::object_ptr do_static_request(const td_api::getLogVerbosityLevel &request); + static td_api::object_ptr do_static_request(const td_api::getLogTags &request); + static td_api::object_ptr do_static_request(const td_api::setLogTagVerbosityLevel &request); + static td_api::object_ptr do_static_request(const td_api::getLogTagVerbosityLevel &request); static DbKey as_db_key(string key); Status init(DbKey key) TD_WARN_UNUSED_RESULT; diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 8bd4bbd06..1bccfbef4 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1130,9 +1130,13 @@ class CliClient final : public Actor { } static td_api::object_ptr execute(tl_object_ptr f) { - LOG(INFO) << "Execute request: " << to_string(f); + if (GET_VERBOSITY_LEVEL() < VERBOSITY_NAME(td_requests)) { + LOG(ERROR) << "Execute request: " << to_string(f); + } auto res = ClientActor::execute(std::move(f)); - LOG(INFO) << "Execute response: " << to_string(res); + if (GET_VERBOSITY_LEVEL() < VERBOSITY_NAME(td_requests)) { + LOG(ERROR) << "Execute response: " << to_string(res); + } return res; } @@ -3384,16 +3388,36 @@ class CliClient final : public Actor { td::Log::set_verbosity_level(static_cast(op.size())); } else if (op[0] == 'v' && ('0' <= op[1] && op[1] <= '9')) { td::Log::set_verbosity_level(to_integer(op.substr(1))); + } else if (op == "slse") { + execute(td_api::make_object(td_api::make_object())); + } else if (op == "slsd") { + execute(td_api::make_object(td_api::make_object())); + } else if (op == "gls") { + execute(td_api::make_object()); + } else if (op == "slvl") { + execute(td_api::make_object(to_integer(args))); + } else if (op == "glvl") { + execute(td_api::make_object()); + } else if (op == "gtags" || op == "glt") { + execute(td_api::make_object()); } else if (op == "sltvl" || op == "sltvle" || op == "tag") { string tag; string level; std::tie(tag, level) = split(args); - auto request = make_tl_object(tag, to_integer(level)); + auto request = td_api::make_object(tag, to_integer(level)); if (op == "sltvl") { send_request(std::move(request)); } else { execute(std::move(request)); } + } else if (op == "gltvl" || op == "gltvle" || op == "gtag") { + string tag = args; + auto request = make_tl_object(tag); + if (op == "gltvl") { + send_request(std::move(request)); + } else { + execute(std::move(request)); + } } else if (op == "q" || op == "Quit") { quit(); } else if (op == "dnq" || op == "DumpNetQueries") { @@ -3606,7 +3630,7 @@ void main(int argc, char **argv) { if (*arg == '\0' && i + 1 < argc) { arg = argv[++i]; } - if (file_log.init(arg) && file_log.init(arg) && file_log.init(arg, 1000 << 20)) { + if (file_log.init(arg).is_ok() && file_log.init(arg).is_ok() && file_log.init(arg, 1000 << 20).is_ok()) { log_interface = &ts_log; } } else if (!std::strcmp(argv[i], "-W")) { diff --git a/td/telegram/td_emscripten.cpp b/td/telegram/td_emscripten.cpp index d259711fb..2535c4f6c 100644 --- a/td/telegram/td_emscripten.cpp +++ b/td/telegram/td_emscripten.cpp @@ -31,9 +31,6 @@ EMSCRIPTEN_KEEPALIVE const char *td_execute(void *client, const char *query) { EMSCRIPTEN_KEEPALIVE void td_destroy(void *client) { td_json_client_destroy(client); } -EMSCRIPTEN_KEEPALIVE void td_set_verbosity(int verbosity) { - td_set_log_verbosity_level(verbosity); -} EMSCRIPTEN_KEEPALIVE double td_get_timeout() { return td::ConcurrentScheduler::emscripten_get_main_timeout(); } diff --git a/tdutils/td/utils/FileLog.cpp b/tdutils/td/utils/FileLog.cpp index b0672c77d..4e22ebbbd 100644 --- a/tdutils/td/utils/FileLog.cpp +++ b/tdutils/td/utils/FileLog.cpp @@ -17,20 +17,16 @@ namespace td { -bool FileLog::init(string path, int64 rotate_threshold) { +Status FileLog::init(string path, int64 rotate_threshold) { if (path == path_) { set_rotate_threshold(rotate_threshold); - return true; + return Status::OK(); } - auto r_fd = FileFd::open(path, FileFd::Create | FileFd::Write | FileFd::Append); - if (r_fd.is_error()) { - LOG(ERROR) << "Can't open log: " << r_fd.error(); - return false; - } + TRY_RESULT(fd, FileFd::open(path, FileFd::Create | FileFd::Write | FileFd::Append)); fd_.close(); - fd_ = r_fd.move_as_ok(); + fd_ = std::move(fd); if (!Stderr().empty()) { fd_.get_native_fd().duplicate(Stderr().get_native_fd()).ignore(); } @@ -38,13 +34,21 @@ bool FileLog::init(string path, int64 rotate_threshold) { path_ = std::move(path); size_ = fd_.get_size(); rotate_threshold_ = rotate_threshold; - return true; + return Status::OK(); +} + +Slice FileLog::get_path() const { + return path_; } void FileLog::set_rotate_threshold(int64 rotate_threshold) { rotate_threshold_ = rotate_threshold; } +int64 FileLog::get_rotate_threshold() const { + return rotate_threshold_; +} + void FileLog::append(CSlice cslice, int log_level) { Slice slice = cslice; while (!slice.empty()) { diff --git a/tdutils/td/utils/FileLog.h b/tdutils/td/utils/FileLog.h index 12e9d1479..0f3ccccfb 100644 --- a/tdutils/td/utils/FileLog.h +++ b/tdutils/td/utils/FileLog.h @@ -10,6 +10,7 @@ #include "td/utils/logging.h" #include "td/utils/port/FileFd.h" #include "td/utils/Slice.h" +#include "td/utils/Status.h" namespace td { @@ -17,10 +18,14 @@ class FileLog : public LogInterface { static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); public: - bool init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD); + Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD); + + Slice get_path() const; void set_rotate_threshold(int64 rotate_threshold); + int64 get_rotate_threshold() const; + void append(CSlice cslice, int log_level) override; void rotate() override; diff --git a/test/TestsRunner.cpp b/test/TestsRunner.cpp index 081c6bf14..72b1290fe 100644 --- a/test/TestsRunner.cpp +++ b/test/TestsRunner.cpp @@ -55,7 +55,7 @@ void TestsRunner::init(string dir) { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); chdir(dir).ensure(); LOG(WARNING) << "Redirect log into " << tag("file", dir + TD_DIR_SLASH + "log.txt"); - if (file_log.init("log.txt", std::numeric_limits::max())) { + if (file_log.init("log.txt", std::numeric_limits::max()).is_ok()) { log_interface = &ts_log; } }