New API for managing TDLib logs.

GitOrigin-RevId: 60f520027bf16f53b927c72d0151884fda64ebbc
This commit is contained in:
levlam 2018-10-24 18:42:40 +03:00
parent 4852e2940b
commit 44d21ecc4a
14 changed files with 217 additions and 105 deletions

View File

@ -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

View File

@ -147,7 +147,6 @@ function split_file($file, $chunks, $undo) {
'(CREATE_REQUEST|CREATE_NO_ARGS_REQUEST)[(](?<name>[A-Z][A-Za-z]*)|'.
'(?<name>complete_pending_preauthentication_requests)|'.
'(Up|Down)load[a-zA-Z]*C(?<name>allback)|(up|down)load_[a-z_]*_c(?<name>allback)_|'.
'(?<name>V)(LOG.td_init|ERBOSITY_NAME)|'.
'(?<name>LogEvent)[^sA]|'.
'(?<name>parse)[(]|'.
'(?<name>store)[(]/', $f, $matches, PREG_SET_ORDER)) {

View File

@ -8,7 +8,7 @@ class DotnetTlDocumentationGenerator extends TlDocumentationGenerator
{
$doc = htmlspecialchars($doc, ENT_XML1);
$doc = str_replace('*/', '*&#47;', $doc);
$doc = preg_replace_callback('/_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc);
$doc = preg_replace_callback('/(?<!")_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc);
return $doc;
}

View File

@ -12,7 +12,7 @@ class JavadocTlDocumentationGenerator extends TlDocumentationGenerator
{
$doc = htmlspecialchars($doc);
$doc = str_replace('*/', '*&#47;', $doc);
$doc = preg_replace_callback('/_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc);
$doc = preg_replace_callback('/(?<!")_([A-Za-z])/', function ($matches) {return strtoupper($matches[1]);}, $doc);
return $doc;
}

View File

@ -2317,6 +2317,25 @@ updateNewCustomQuery id:int64 data:string timeout:int32 = Update;
updates updates:vector<Update> = 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<string> = 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;

Binary file not shown.

View File

@ -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<std::mutex> 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<td_api::logStreamDefault>()).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<td_api::logStreamFile>(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<std::mutex> lock(log_mutex);
max_log_file_size = max(max_file_size, static_cast<int64>(0));
file_log.set_rotate_threshold(max_log_file_size);
max_log_file_size = max(max_file_size, static_cast<int64>(1));
Logging::set_current_stream(td_api::make_object<td_api::logStreamFile>(log_file_path, max_log_file_size)).ignore();
}
void Log::set_verbosity_level(int new_verbosity_level) {
std::lock_guard<std::mutex> 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) {

View File

@ -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_api::Object> 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_api::Object> 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_api::Object> 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<td_api::ok>();
} else {
return make_error(400, result.message());
}
}
td_api::object_ptr<td_api::Object> 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_api::Object> Td::do_static_request(const td_api::setLogVerbosityLevel &request) {
auto result = Logging::set_verbosity_level(static_cast<int>(request.new_verbosity_level_));
if (result.is_ok()) {
return td_api::make_object<td_api::ok>();
} else {
return make_error(400, result.message());
}
}
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getLogVerbosityLevel &request) {
return td_api::make_object<td_api::logVerbosityLevel>(Logging::get_verbosity_level());
}
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getLogTags &request) {
return td_api::make_object<td_api::logTags>(Logging::get_tags());
}
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::setLogTagVerbosityLevel &request) {
auto result = Logging::set_tag_verbosity_level(request.tag_, static_cast<int>(request.new_verbosity_level_));
if (result.is_ok()) {
return td_api::make_object<td_api::ok>();
} else {
return make_error(400, result.message());
}
}
td_api::object_ptr<td_api::Object> 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<td_api::logVerbosityLevel>(result.ok());
} else {
return make_error(400, result.error().message());
}
}
// test
void Td::on_request(uint64 id, td_api::testNetwork &request) {
create_handler<TestQuery>(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<td_api::ok>());
}
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_api::Object> 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<td_api::error>(400, "Log tag is not found");
}
*level = clamp(static_cast<int>(request.new_verbosity_level_), 1, VERBOSITY_NAME(NEVER));
return td_api::make_object<td_api::ok>();
}
void Td::on_request(uint64 id, td_api::testUseUpdate &request) {
send_closure(actor_id(this), &Td::send_result, id, nullptr);
}

View File

@ -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<td_api::Object> do_static_request(const td_api::getFileExtension &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::cleanFileName &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLanguagePackString &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::testSetLogTagVerbosityLevel &request);
static td_api::object_ptr<td_api::Object> do_static_request(td_api::setLogStream &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLogStream &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::setLogVerbosityLevel &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLogVerbosityLevel &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLogTags &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::setLogTagVerbosityLevel &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLogTagVerbosityLevel &request);
static DbKey as_db_key(string key);
Status init(DbKey key) TD_WARN_UNUSED_RESULT;

View File

@ -1130,9 +1130,13 @@ class CliClient final : public Actor {
}
static td_api::object_ptr<td_api::Object> execute(tl_object_ptr<td_api::Function> 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<int>(op.size()));
} else if (op[0] == 'v' && ('0' <= op[1] && op[1] <= '9')) {
td::Log::set_verbosity_level(to_integer<int>(op.substr(1)));
} else if (op == "slse") {
execute(td_api::make_object<td_api::setLogStream>(td_api::make_object<td_api::logStreamEmpty>()));
} else if (op == "slsd") {
execute(td_api::make_object<td_api::setLogStream>(td_api::make_object<td_api::logStreamDefault>()));
} else if (op == "gls") {
execute(td_api::make_object<td_api::getLogStream>());
} else if (op == "slvl") {
execute(td_api::make_object<td_api::setLogVerbosityLevel>(to_integer<int32>(args)));
} else if (op == "glvl") {
execute(td_api::make_object<td_api::getLogVerbosityLevel>());
} else if (op == "gtags" || op == "glt") {
execute(td_api::make_object<td_api::getLogTags>());
} else if (op == "sltvl" || op == "sltvle" || op == "tag") {
string tag;
string level;
std::tie(tag, level) = split(args);
auto request = make_tl_object<td_api::testSetLogTagVerbosityLevel>(tag, to_integer<int32>(level));
auto request = td_api::make_object<td_api::setLogTagVerbosityLevel>(tag, to_integer<int32>(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<td_api::getLogTagVerbosityLevel>(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")) {

View File

@ -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();
}

View File

@ -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()) {

View File

@ -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;

View File

@ -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<int64>::max())) {
if (file_log.init("log.txt", std::numeric_limits<int64>::max()).is_ok()) {
log_interface = &ts_log;
}
}