aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlevlam <levlam@telegram.org>2018-01-24 18:45:57 +0300
committerlevlam <levlam@telegram.org>2018-01-24 18:45:57 +0300
commit18e7b0816d0be70cf2871d13facd0d470f16c95f (patch)
tree9f81f029971815b1639af76dfebbddf7ce042ad7
parent644a4ffbeabefdae847d81bfd3245c4c9aed17df (diff)
Add set_fatal_error_callback to public Log interface.
GitOrigin-RevId: 3e7c3bb97d86fa753deae864fdf574de1de1aee4
-rw-r--r--CMakeLists.txt2
-rw-r--r--td/telegram/Log.cpp16
-rw-r--r--td/telegram/Log.h18
-rw-r--r--td/telegram/cli.cpp27
-rw-r--r--td/telegram/td_log.cpp6
-rw-r--r--td/telegram/td_log.h22
-rw-r--r--tdclientjson_export_list1
-rw-r--r--tdutils/td/utils/FileLog.h13
-rw-r--r--tdutils/td/utils/MemoryLog.h4
-rw-r--r--tdutils/td/utils/logging.cpp21
-rw-r--r--tdutils/td/utils/logging.h10
11 files changed, 112 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f2703a50..e03962b61 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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()
diff --git a/td/telegram/Log.cpp b/td/telegram/Log.cpp
index a6b6e6722..4c8a28b9d 100644
--- a/td/telegram/Log.cpp
+++ b/td/telegram/Log.cpp
@@ -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
diff --git a/td/telegram/Log.h b/td/telegram/Log.h
index fcd43aee9..f72191583 100644
--- a/td/telegram/Log.h
+++ b/td/telegram/Log.h
@@ -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
diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp
index ed9be04df..40e78db12 100644
--- a/td/telegram/cli.cpp
+++ b/td/telegram/cli.cpp
@@ -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;
diff --git a/td/telegram/td_log.cpp b/td/telegram/td_log.cpp
index f82cd1664..0bffe0c7a 100644
--- a/td/telegram/td_log.cpp
+++ b/td/telegram/td_log.cpp
@@ -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);
+}
diff --git a/td/telegram/td_log.h b/td/telegram/td_log.h
index d3794edfa..7aa8549c0 100644
--- a/td/telegram/td_log.h
+++ b/td/telegram/td_log.h
@@ -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
diff --git a/tdclientjson_export_list b/tdclientjson_export_list
index bb23be91f..f1db3603c 100644
--- a/tdclientjson_export_list
+++ b/tdclientjson_export_list
@@ -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
diff --git a/tdutils/td/utils/FileLog.h b/tdutils/td/utils/FileLog.h
index 0520d0250..7ca4249d6 100644
--- a/tdutils/td/utils/FileLog.h
+++ b/tdutils/td/utils/FileLog.h
@@ -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();
diff --git a/tdutils/td/utils/MemoryLog.h b/tdutils/td/utils/MemoryLog.h
index 113a46cc0..7b0eb39c7 100644
--- a/tdutils/td/utils/MemoryLog.h
+++ b/tdutils/td/utils/MemoryLog.h
@@ -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 {
diff --git a/tdutils/td/utils/logging.cpp b/tdutils/td/utils/logging.cpp
index 95f4e9286..9fa9a3f54 100644
--- a/tdutils/td/utils/logging.cpp
+++ b/tdutils/td/utils/logging.cpp
@@ -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
diff --git a/tdutils/td/utils/logging.h b/tdutils/td/utils/logging.h
index cfff0bbdf..3ed4f48f8 100644
--- a/tdutils/td/utils/logging.h
+++ b/tdutils/td/utils/logging.h
@@ -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"