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_compile_definitions(tg_cli PRIVATE -DUSE_READLINE=1)
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
@ -17,6 +17,12 @@ namespace td {
|
||||
static FileLog file_log;
|
||||
static TsLog ts_log(&file_log);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -56,6 +56,24 @@ class Log {
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -5,6 +5,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/ClientActor.h"
|
||||
#include "td/telegram/Log.h"
|
||||
|
||||
#include "td/telegram/td_api_json.h"
|
||||
|
||||
@ -42,6 +43,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring> // for strcmp
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
@ -56,7 +58,7 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
void dump_memory_usage() {
|
||||
static void dump_memory_usage() {
|
||||
if (is_memprof_on()) {
|
||||
LOG(WARNING) << "memory_dump";
|
||||
clear_thread_locals();
|
||||
@ -87,7 +89,7 @@ static int32 saved_point;
|
||||
static string saved_line;
|
||||
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)) {
|
||||
// spin
|
||||
}
|
||||
@ -100,7 +102,7 @@ void deactivate_readline() {
|
||||
rl_redisplay();
|
||||
}
|
||||
|
||||
void reactivate_readline() {
|
||||
static void reactivate_readline() {
|
||||
rl_set_prompt(prompt);
|
||||
rl_replace_line(saved_line.c_str(), 0);
|
||||
rl_point = saved_point;
|
||||
@ -109,7 +111,7 @@ void reactivate_readline() {
|
||||
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",
|
||||
"GetChats",
|
||||
"GetHistory",
|
||||
@ -162,7 +164,7 @@ char *command_generator(const char *text, int state) {
|
||||
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;
|
||||
if (start == 0) {
|
||||
matches = rl_completion_matches(text, command_generator);
|
||||
@ -2751,6 +2753,10 @@ class CliClient final : public Actor {
|
||||
quit();
|
||||
} else if (op == "dnq" || op == "DumpNetQueries") {
|
||||
dump_pending_network_queries();
|
||||
} else if (op == "fatal") {
|
||||
LOG(FATAL) << "Fatal!";
|
||||
} else if (op == "unreachable") {
|
||||
UNREACHABLE();
|
||||
} else {
|
||||
op_not_found_count++;
|
||||
}
|
||||
@ -2864,26 +2870,31 @@ class CliClient final : public Actor {
|
||||
};
|
||||
CliClient *CliClient::instance_ = nullptr;
|
||||
|
||||
void quit() {
|
||||
static void quit() {
|
||||
CliClient::quit_instance();
|
||||
}
|
||||
|
||||
void fail_signal(int sig) {
|
||||
static void fail_signal(int sig) {
|
||||
signal_safe_write_signal_number(sig);
|
||||
while (true) {
|
||||
// spin forever to allow debugger to attach
|
||||
}
|
||||
}
|
||||
|
||||
void usage() {
|
||||
static void usage() {
|
||||
//TODO:
|
||||
}
|
||||
|
||||
static void on_fatal_error(const char *error) {
|
||||
std::cerr << "Fatal error: " << error << std::endl;
|
||||
}
|
||||
|
||||
void main(int argc, char **argv) {
|
||||
ignore_signal(SignalType::HangUp).ensure();
|
||||
ignore_signal(SignalType::Pipe).ensure();
|
||||
set_signal_handler(SignalType::Error, fail_signal).ensure();
|
||||
set_signal_handler(SignalType::Abort, fail_signal).ensure();
|
||||
td::Log::set_fatal_error_callback(on_fatal_error);
|
||||
|
||||
CliLog cli_log;
|
||||
log_interface = &cli_log;
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "td/telegram/Log.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void td_set_log_file_path(const char *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) {
|
||||
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.
|
||||
* 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
|
||||
* switch back to the default logging behaviour.
|
||||
* \param[in] file_path Null-terminated path to a file where the internal TDLib log will be written.
|
||||
* Use an empty path to switch back to the default logging behaviour.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -6,3 +6,4 @@ _td_json_client_execute
|
||||
_td_set_log_file_path
|
||||
_td_set_log_max_file_size
|
||||
_td_set_log_verbosity_level
|
||||
_td_set_log_fatal_error_callback
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
namespace td {
|
||||
@ -23,25 +22,25 @@ class FileLog : public LogInterface {
|
||||
static constexpr int DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
|
||||
|
||||
public:
|
||||
void append(CSlice xslice, int log_level) override {
|
||||
Slice slice = xslice;
|
||||
void append(CSlice cslice, int log_level) override {
|
||||
Slice slice = cslice;
|
||||
while (!slice.empty()) {
|
||||
auto r_size = fd_.write(slice);
|
||||
if (r_size.is_error()) {
|
||||
std::abort();
|
||||
process_fatal_error(r_size.error().message());
|
||||
}
|
||||
auto written = r_size.ok();
|
||||
size_ += static_cast<int64>(written);
|
||||
slice.remove_prefix(written);
|
||||
}
|
||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||
std::abort();
|
||||
process_fatal_error(cslice);
|
||||
}
|
||||
|
||||
if (size_ > rotate_threshold_) {
|
||||
auto status = rename(path_, path_ + ".old");
|
||||
if (status.is_error()) {
|
||||
std::abort();
|
||||
process_fatal_error(status.message());
|
||||
}
|
||||
do_rotate();
|
||||
}
|
||||
@ -83,7 +82,7 @@ class FileLog : public LogInterface {
|
||||
fd_.close();
|
||||
auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Truncate | FileFd::Write);
|
||||
if (r_fd.is_error()) {
|
||||
std::abort();
|
||||
process_fatal_error(r_fd.error().message());
|
||||
}
|
||||
fd_ = r_fd.move_as_ok();
|
||||
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);
|
||||
CHECK(printed == magic_size - 2);
|
||||
buffer_[start_pos + magic_size - 1] = ' ';
|
||||
|
||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||
process_fatal_error(new_slice);
|
||||
}
|
||||
}
|
||||
|
||||
void rotate() override {
|
||||
|
@ -216,11 +216,7 @@ class DefaultLog : public LogInterface {
|
||||
TsCerr() << slice;
|
||||
#endif
|
||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||
auto f = default_log_on_fatal_error;
|
||||
if (f) {
|
||||
f(slice);
|
||||
}
|
||||
std::abort();
|
||||
process_fatal_error(slice);
|
||||
}
|
||||
}
|
||||
void rotate() override {
|
||||
@ -230,6 +226,19 @@ static DefaultLog default_log;
|
||||
|
||||
LogInterface *const default_log_interface = &default_log;
|
||||
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
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
|
||||
#define PSTR_IMPL(...) ::td::Logger(::td::NullLog().ref(), 0, true).printf(__VA_ARGS__)
|
||||
@ -98,7 +97,7 @@ inline bool no_return_func() {
|
||||
|
||||
#define UNREACHABLE(...) \
|
||||
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(FATAL) = 0;
|
||||
@ -148,8 +147,11 @@ class NullLog : public LogInterface {
|
||||
|
||||
extern LogInterface *const default_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_BLUE "\e[1;34m"
|
||||
|
Loading…
Reference in New Issue
Block a user