Add set_fatal_error_callback to public Log interface.
GitOrigin-RevId: 3e7c3bb97d86fa753deae864fdf574de1de1aee4
This commit is contained in:
parent
644a4ffbea
commit
18e7b0816d
@ -652,7 +652,7 @@ if (NOT CMAKE_CROSSCOMPILING)
|
|||||||
target_include_directories(tg_cli SYSTEM PRIVATE ${READLINE_INCLUDE_DIR})
|
target_include_directories(tg_cli SYSTEM PRIVATE ${READLINE_INCLUDE_DIR})
|
||||||
target_compile_definitions(tg_cli PRIVATE -DUSE_READLINE=1)
|
target_compile_definitions(tg_cli PRIVATE -DUSE_READLINE=1)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(tg_cli PRIVATE memprof tdcore tdtl)
|
target_link_libraries(tg_cli PRIVATE memprof tdclient tdcore tdtl)
|
||||||
add_dependencies(tg_cli tl_generate_json)
|
add_dependencies(tg_cli tl_generate_json)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -17,6 +17,12 @@ namespace td {
|
|||||||
static FileLog file_log;
|
static FileLog file_log;
|
||||||
static TsLog ts_log(&file_log);
|
static TsLog ts_log(&file_log);
|
||||||
static int64 max_log_file_size = 10 << 20;
|
static int64 max_log_file_size = 10 << 20;
|
||||||
|
static Log::FatalErrorCallbackPtr fatal_error_callback;
|
||||||
|
|
||||||
|
static void fatal_error_callback_wrapper(CSlice message) {
|
||||||
|
CHECK(fatal_error_callback != nullptr);
|
||||||
|
fatal_error_callback(message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void Log::set_file_path(string file_path) {
|
void Log::set_file_path(string file_path) {
|
||||||
if (file_path.empty()) {
|
if (file_path.empty()) {
|
||||||
@ -37,4 +43,14 @@ void Log::set_verbosity_level(int new_verbosity_level) {
|
|||||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + new_verbosity_level);
|
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + new_verbosity_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Log::set_fatal_error_callback(FatalErrorCallbackPtr callback) {
|
||||||
|
if (callback == nullptr) {
|
||||||
|
fatal_error_callback = nullptr;
|
||||||
|
set_log_fatal_error_callback(nullptr);
|
||||||
|
} else {
|
||||||
|
fatal_error_callback = callback;
|
||||||
|
set_log_fatal_error_callback(fatal_error_callback_wrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -56,6 +56,24 @@ class Log {
|
|||||||
* value greater than 5 and up to 1024 can be used to enable even more logging.
|
* value greater than 5 and up to 1024 can be used to enable even more logging.
|
||||||
*/
|
*/
|
||||||
static void set_verbosity_level(int new_verbosity_level);
|
static void set_verbosity_level(int new_verbosity_level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type of callback function that will be called when a fatal error happens.
|
||||||
|
*
|
||||||
|
* \param error_message Null-terminated string with a description of a happened fatal error.
|
||||||
|
*/
|
||||||
|
using FatalErrorCallbackPtr = void (*)(const char *error_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the callback that will be called when a fatal error happens.
|
||||||
|
* None of the TDLib methods can be called from the callback.
|
||||||
|
* The TDLib will crash as soon as callback returns.
|
||||||
|
* By default the callback is not set.
|
||||||
|
*
|
||||||
|
* \param[in] callback Callback that will be called when a fatal error happens.
|
||||||
|
* Pass nullptr to remove the callback.
|
||||||
|
*/
|
||||||
|
static void set_fatal_error_callback(FatalErrorCallbackPtr callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
#include "td/telegram/ClientActor.h"
|
#include "td/telegram/ClientActor.h"
|
||||||
|
#include "td/telegram/Log.h"
|
||||||
|
|
||||||
#include "td/telegram/td_api_json.h"
|
#include "td/telegram/td_api_json.h"
|
||||||
|
|
||||||
@ -42,6 +43,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring> // for strcmp
|
#include <cstring> // for strcmp
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@ -56,7 +58,7 @@
|
|||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
void dump_memory_usage() {
|
static void dump_memory_usage() {
|
||||||
if (is_memprof_on()) {
|
if (is_memprof_on()) {
|
||||||
LOG(WARNING) << "memory_dump";
|
LOG(WARNING) << "memory_dump";
|
||||||
clear_thread_locals();
|
clear_thread_locals();
|
||||||
@ -87,7 +89,7 @@ static int32 saved_point;
|
|||||||
static string saved_line;
|
static string saved_line;
|
||||||
static std::atomic_flag readline_lock = ATOMIC_FLAG_INIT;
|
static std::atomic_flag readline_lock = ATOMIC_FLAG_INIT;
|
||||||
|
|
||||||
void deactivate_readline() {
|
static void deactivate_readline() {
|
||||||
while (readline_lock.test_and_set(std::memory_order_acquire)) {
|
while (readline_lock.test_and_set(std::memory_order_acquire)) {
|
||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
@ -100,7 +102,7 @@ void deactivate_readline() {
|
|||||||
rl_redisplay();
|
rl_redisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reactivate_readline() {
|
static void reactivate_readline() {
|
||||||
rl_set_prompt(prompt);
|
rl_set_prompt(prompt);
|
||||||
rl_replace_line(saved_line.c_str(), 0);
|
rl_replace_line(saved_line.c_str(), 0);
|
||||||
rl_point = saved_point;
|
rl_point = saved_point;
|
||||||
@ -109,7 +111,7 @@ void reactivate_readline() {
|
|||||||
readline_lock.clear(std::memory_order_release);
|
readline_lock.clear(std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *command_generator(const char *text, int state) {
|
static char *command_generator(const char *text, int state) {
|
||||||
static vector<CSlice> commands{"GetContacts",
|
static vector<CSlice> commands{"GetContacts",
|
||||||
"GetChats",
|
"GetChats",
|
||||||
"GetHistory",
|
"GetHistory",
|
||||||
@ -162,7 +164,7 @@ char *command_generator(const char *text, int state) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **tg_cli_completion(const char *text, int start, int end) {
|
static char **tg_cli_completion(const char *text, int start, int end) {
|
||||||
char **matches = nullptr;
|
char **matches = nullptr;
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
matches = rl_completion_matches(text, command_generator);
|
matches = rl_completion_matches(text, command_generator);
|
||||||
@ -2751,6 +2753,10 @@ class CliClient final : public Actor {
|
|||||||
quit();
|
quit();
|
||||||
} else if (op == "dnq" || op == "DumpNetQueries") {
|
} else if (op == "dnq" || op == "DumpNetQueries") {
|
||||||
dump_pending_network_queries();
|
dump_pending_network_queries();
|
||||||
|
} else if (op == "fatal") {
|
||||||
|
LOG(FATAL) << "Fatal!";
|
||||||
|
} else if (op == "unreachable") {
|
||||||
|
UNREACHABLE();
|
||||||
} else {
|
} else {
|
||||||
op_not_found_count++;
|
op_not_found_count++;
|
||||||
}
|
}
|
||||||
@ -2864,26 +2870,31 @@ class CliClient final : public Actor {
|
|||||||
};
|
};
|
||||||
CliClient *CliClient::instance_ = nullptr;
|
CliClient *CliClient::instance_ = nullptr;
|
||||||
|
|
||||||
void quit() {
|
static void quit() {
|
||||||
CliClient::quit_instance();
|
CliClient::quit_instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fail_signal(int sig) {
|
static void fail_signal(int sig) {
|
||||||
signal_safe_write_signal_number(sig);
|
signal_safe_write_signal_number(sig);
|
||||||
while (true) {
|
while (true) {
|
||||||
// spin forever to allow debugger to attach
|
// spin forever to allow debugger to attach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage() {
|
static void usage() {
|
||||||
//TODO:
|
//TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void on_fatal_error(const char *error) {
|
||||||
|
std::cerr << "Fatal error: " << error << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
void main(int argc, char **argv) {
|
void main(int argc, char **argv) {
|
||||||
ignore_signal(SignalType::HangUp).ensure();
|
ignore_signal(SignalType::HangUp).ensure();
|
||||||
ignore_signal(SignalType::Pipe).ensure();
|
ignore_signal(SignalType::Pipe).ensure();
|
||||||
set_signal_handler(SignalType::Error, fail_signal).ensure();
|
set_signal_handler(SignalType::Error, fail_signal).ensure();
|
||||||
set_signal_handler(SignalType::Abort, fail_signal).ensure();
|
set_signal_handler(SignalType::Abort, fail_signal).ensure();
|
||||||
|
td::Log::set_fatal_error_callback(on_fatal_error);
|
||||||
|
|
||||||
CliLog cli_log;
|
CliLog cli_log;
|
||||||
log_interface = &cli_log;
|
log_interface = &cli_log;
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "td/telegram/Log.h"
|
#include "td/telegram/Log.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
void td_set_log_file_path(const char *file_path) {
|
void td_set_log_file_path(const char *file_path) {
|
||||||
td::Log::set_file_path(file_path == nullptr ? "" : file_path);
|
td::Log::set_file_path(file_path == nullptr ? "" : file_path);
|
||||||
}
|
}
|
||||||
@ -19,3 +21,7 @@ void td_set_log_max_file_size(long long max_file_size) {
|
|||||||
void td_set_log_verbosity_level(int new_verbosity_level) {
|
void td_set_log_verbosity_level(int new_verbosity_level) {
|
||||||
td::Log::set_verbosity_level(new_verbosity_level);
|
td::Log::set_verbosity_level(new_verbosity_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void td_set_log_fatal_error_callback(td_log_fatal_error_callback_ptr callback) {
|
||||||
|
td::Log::set_fatal_error_callback(callback);
|
||||||
|
}
|
||||||
|
@ -23,8 +23,8 @@ extern "C" {
|
|||||||
* By default TDLib writes logs to stderr or an OS specific log.
|
* By default TDLib writes logs to stderr or an OS specific log.
|
||||||
* Use this method to write the log to a file instead.
|
* Use this method to write the log to a file instead.
|
||||||
*
|
*
|
||||||
* \param[in] file_path Path to a file where the internal TDLib log will be written. Use an empty path to
|
* \param[in] file_path Null-terminated path to a file where the internal TDLib log will be written.
|
||||||
* switch back to the default logging behaviour.
|
* Use an empty path to switch back to the default logging behaviour.
|
||||||
*/
|
*/
|
||||||
TDJSON_EXPORT void td_set_log_file_path(const char *file_path);
|
TDJSON_EXPORT void td_set_log_file_path(const char *file_path);
|
||||||
|
|
||||||
@ -52,6 +52,24 @@ TDJSON_EXPORT void td_set_log_max_file_size(long long max_file_size);
|
|||||||
*/
|
*/
|
||||||
TDJSON_EXPORT void td_set_log_verbosity_level(int new_verbosity_level);
|
TDJSON_EXPORT void td_set_log_verbosity_level(int new_verbosity_level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type of callback function that will be called when a fatal error happens.
|
||||||
|
*
|
||||||
|
* \param error_message Null-terminated string with a description of a happened fatal error.
|
||||||
|
*/
|
||||||
|
using td_log_fatal_error_callback_ptr = void (*)(const char *error_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the callback that will be called when a fatal error happens.
|
||||||
|
* None of the TDLib methods can be called from the callback.
|
||||||
|
* The TDLib will crash as soon as callback returns.
|
||||||
|
* By default the callback is not set.
|
||||||
|
*
|
||||||
|
* \param[in] callback Callback that will be called when a fatal error happens.
|
||||||
|
* Pass NULL to remove the callback.
|
||||||
|
*/
|
||||||
|
TDJSON_EXPORT void td_set_log_fatal_error_callback(td_log_fatal_error_callback_ptr callback);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,3 +6,4 @@ _td_json_client_execute
|
|||||||
_td_set_log_file_path
|
_td_set_log_file_path
|
||||||
_td_set_log_max_file_size
|
_td_set_log_max_file_size
|
||||||
_td_set_log_verbosity_level
|
_td_set_log_verbosity_level
|
||||||
|
_td_set_log_fatal_error_callback
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
#include "td/utils/Slice.h"
|
#include "td/utils/Slice.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
@ -23,25 +22,25 @@ class FileLog : public LogInterface {
|
|||||||
static constexpr int DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
|
static constexpr int DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void append(CSlice xslice, int log_level) override {
|
void append(CSlice cslice, int log_level) override {
|
||||||
Slice slice = xslice;
|
Slice slice = cslice;
|
||||||
while (!slice.empty()) {
|
while (!slice.empty()) {
|
||||||
auto r_size = fd_.write(slice);
|
auto r_size = fd_.write(slice);
|
||||||
if (r_size.is_error()) {
|
if (r_size.is_error()) {
|
||||||
std::abort();
|
process_fatal_error(r_size.error().message());
|
||||||
}
|
}
|
||||||
auto written = r_size.ok();
|
auto written = r_size.ok();
|
||||||
size_ += static_cast<int64>(written);
|
size_ += static_cast<int64>(written);
|
||||||
slice.remove_prefix(written);
|
slice.remove_prefix(written);
|
||||||
}
|
}
|
||||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||||
std::abort();
|
process_fatal_error(cslice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size_ > rotate_threshold_) {
|
if (size_ > rotate_threshold_) {
|
||||||
auto status = rename(path_, path_ + ".old");
|
auto status = rename(path_, path_ + ".old");
|
||||||
if (status.is_error()) {
|
if (status.is_error()) {
|
||||||
std::abort();
|
process_fatal_error(status.message());
|
||||||
}
|
}
|
||||||
do_rotate();
|
do_rotate();
|
||||||
}
|
}
|
||||||
@ -83,7 +82,7 @@ class FileLog : public LogInterface {
|
|||||||
fd_.close();
|
fd_.close();
|
||||||
auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Truncate | FileFd::Write);
|
auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Truncate | FileFd::Write);
|
||||||
if (r_fd.is_error()) {
|
if (r_fd.is_error()) {
|
||||||
std::abort();
|
process_fatal_error(r_fd.error().message());
|
||||||
}
|
}
|
||||||
fd_ = r_fd.move_as_ok();
|
fd_ = r_fd.move_as_ok();
|
||||||
Fd::duplicate(fd_.get_fd(), Fd::Stderr()).ignore();
|
Fd::duplicate(fd_.get_fd(), Fd::Stderr()).ignore();
|
||||||
|
@ -57,6 +57,10 @@ class MemoryLog : public LogInterface {
|
|||||||
size_t printed = std::snprintf(&buffer_[start_pos + 1], magic_size - 1, "LOG:%08x: ", real_pos);
|
size_t printed = std::snprintf(&buffer_[start_pos + 1], magic_size - 1, "LOG:%08x: ", real_pos);
|
||||||
CHECK(printed == magic_size - 2);
|
CHECK(printed == magic_size - 2);
|
||||||
buffer_[start_pos + magic_size - 1] = ' ';
|
buffer_[start_pos + magic_size - 1] = ' ';
|
||||||
|
|
||||||
|
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||||
|
process_fatal_error(new_slice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rotate() override {
|
void rotate() override {
|
||||||
|
@ -216,11 +216,7 @@ class DefaultLog : public LogInterface {
|
|||||||
TsCerr() << slice;
|
TsCerr() << slice;
|
||||||
#endif
|
#endif
|
||||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||||
auto f = default_log_on_fatal_error;
|
process_fatal_error(slice);
|
||||||
if (f) {
|
|
||||||
f(slice);
|
|
||||||
}
|
|
||||||
std::abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void rotate() override {
|
void rotate() override {
|
||||||
@ -230,6 +226,19 @@ static DefaultLog default_log;
|
|||||||
|
|
||||||
LogInterface *const default_log_interface = &default_log;
|
LogInterface *const default_log_interface = &default_log;
|
||||||
LogInterface *log_interface = default_log_interface;
|
LogInterface *log_interface = default_log_interface;
|
||||||
OnFatalErrorF default_log_on_fatal_error = nullptr;
|
|
||||||
|
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 td
|
} // namespace td
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "td/utils/StringBuilder.h"
|
#include "td/utils/StringBuilder.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdlib>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#define PSTR_IMPL(...) ::td::Logger(::td::NullLog().ref(), 0, true).printf(__VA_ARGS__)
|
#define PSTR_IMPL(...) ::td::Logger(::td::NullLog().ref(), 0, true).printf(__VA_ARGS__)
|
||||||
@ -98,7 +97,7 @@ inline bool no_return_func() {
|
|||||||
|
|
||||||
#define UNREACHABLE(...) \
|
#define UNREACHABLE(...) \
|
||||||
LOG(FATAL, __VA_ARGS__); \
|
LOG(FATAL, __VA_ARGS__); \
|
||||||
std::abort()
|
::td::process_fatal_error("Unreachable in " __FILE__ " at " TD_DEFINE_STR(__LINE__))
|
||||||
|
|
||||||
constexpr int VERBOSITY_NAME(PLAIN) = -1;
|
constexpr int VERBOSITY_NAME(PLAIN) = -1;
|
||||||
constexpr int VERBOSITY_NAME(FATAL) = 0;
|
constexpr int VERBOSITY_NAME(FATAL) = 0;
|
||||||
@ -148,8 +147,11 @@ class NullLog : public LogInterface {
|
|||||||
|
|
||||||
extern LogInterface *const default_log_interface;
|
extern LogInterface *const default_log_interface;
|
||||||
extern LogInterface *log_interface;
|
extern LogInterface *log_interface;
|
||||||
typedef void (*OnFatalErrorF)(CSlice msg);
|
|
||||||
extern OnFatalErrorF default_log_on_fatal_error;
|
using OnFatalErrorCallback = void (*)(CSlice message);
|
||||||
|
void set_log_fatal_error_callback(OnFatalErrorCallback callback);
|
||||||
|
|
||||||
|
[[noreturn]] void process_fatal_error(CSlice message);
|
||||||
|
|
||||||
#define TC_RED "\e[1;31m"
|
#define TC_RED "\e[1;31m"
|
||||||
#define TC_BLUE "\e[1;34m"
|
#define TC_BLUE "\e[1;34m"
|
||||||
|
Reference in New Issue
Block a user