From 2bb9a83a9b6df4928db1e366ee5dd29c0e867040 Mon Sep 17 00:00:00 2001 From: David Alves Date: Fri, 19 Sep 2025 10:05:31 -0700 Subject: [PATCH 1/2] Add facilities to integrate llama.cpp logging with other logging stacks This adds the ability for llama.cpp logging to integrate with other logging stacks by allowing the setting of a log callback to which all logging calls are forwarded. --- common/log.cpp | 39 ++++++++++++++++++++++++++++++++------- common/log.h | 17 +++++++++++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/common/log.cpp b/common/log.cpp index 4ccdbd17cd726..e4e99def67e35 100644 --- a/common/log.cpp +++ b/common/log.cpp @@ -21,6 +21,9 @@ #endif // defined(_WIN32) int common_log_verbosity_thold = LOG_DEFAULT_LLAMA; +static ggml_log_callback g_external_log_callback = nullptr; +static void * g_external_log_user_data = nullptr; +static bool g_stdout_enabled = true; void common_log_set_verbosity_thold(int verbosity) { common_log_verbosity_thold = verbosity; @@ -101,14 +104,18 @@ struct common_log_entry { return; } - fcur = stdout; + if (g_stdout_enabled) { + fcur = stdout; - if (level != GGML_LOG_LEVEL_NONE) { - fcur = stderr; + if (level != GGML_LOG_LEVEL_NONE) { + fcur = stderr; + } + } else { + fcur = nullptr; // suppress stdio prints } } - if (level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) { + if (fcur && level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) { if (timestamp) { // [M.s.ms.us] fprintf(fcur, "%s%d.%02d.%03d.%03d%s ", @@ -130,13 +137,22 @@ struct common_log_entry { } } - fprintf(fcur, "%s", msg.data()); + if (fcur) { + fprintf(fcur, "%s", msg.data()); + } - if (level == GGML_LOG_LEVEL_WARN || level == GGML_LOG_LEVEL_ERROR || level == GGML_LOG_LEVEL_DEBUG) { + if (fcur && (level == GGML_LOG_LEVEL_WARN || level == GGML_LOG_LEVEL_ERROR || level == GGML_LOG_LEVEL_DEBUG)) { fprintf(fcur, "%s", g_col[COMMON_LOG_COL_DEFAULT]); } - fflush(fcur); + if (fcur) { + fflush(fcur); + } + + // forward to external callback only once per entry (when not printing to the file sink) + if (!file && g_external_log_callback) { + g_external_log_callback(level, msg.data(), g_external_log_user_data); + } } }; @@ -442,3 +458,12 @@ void common_log_set_prefix(struct common_log * log, bool prefix) { void common_log_set_timestamps(struct common_log * log, bool timestamps) { log->set_timestamps(timestamps); } + +void common_log_set_callback(ggml_log_callback log_callback, void * user_data) { + g_external_log_callback = log_callback; + g_external_log_user_data = user_data; +} + +void common_log_set_stdout_enabled(bool enabled) { + g_stdout_enabled = enabled; +} diff --git a/common/log.h b/common/log.h index f329b434c9395..3d6e7da7be734 100644 --- a/common/log.h +++ b/common/log.h @@ -76,6 +76,23 @@ void common_log_set_colors (struct common_log * log, log_colors colors); // n void common_log_set_prefix (struct common_log * log, bool prefix); // whether to output prefix to each log void common_log_set_timestamps(struct common_log * log, bool timestamps); // whether to output timestamps in the prefix +// Redirect log messages to an external callback in addition to, or instead of, +// writing to stdout/stderr. When a callback is set, it will be invoked for every +// log entry produced by common_log_add. +// If NULL is supplied, no callback will be invoked. +// The callback type matches ggml's logging callback for compatibility. +void common_log_set_callback(ggml_log_callback log_callback, void * user_data); + +// Convenience overload when no user_data is needed +static inline void common_log_set_callback(ggml_log_callback log_callback) { + common_log_set_callback(log_callback, NULL); +} + +// Enable or disable printing to stdout/stderr. When disabled, logs will still +// be forwarded to the callback (if set) and any configured log file, but will +// not be written to the standard streams. +void common_log_set_stdout_enabled(bool enabled); + // helper macros for logging // use these to avoid computing log arguments if the verbosity of the log is higher than the threshold // From 2721fae6339897f8c97a466cd92b662b94ba4a4a Mon Sep 17 00:00:00 2001 From: David Alves Date: Sat, 27 Sep 2025 19:02:40 +0100 Subject: [PATCH 2/2] Fix potential SIGSEGV while logging --- common/log.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/common/log.cpp b/common/log.cpp index e4e99def67e35..84505bd28d27a 100644 --- a/common/log.cpp +++ b/common/log.cpp @@ -115,7 +115,7 @@ struct common_log_entry { } } - if (fcur && level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) { + if (level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix) { if (timestamp) { // [M.s.ms.us] fprintf(fcur, "%s%d.%02d.%03d.%03d%s ", @@ -139,13 +139,9 @@ struct common_log_entry { if (fcur) { fprintf(fcur, "%s", msg.data()); - } - - if (fcur && (level == GGML_LOG_LEVEL_WARN || level == GGML_LOG_LEVEL_ERROR || level == GGML_LOG_LEVEL_DEBUG)) { - fprintf(fcur, "%s", g_col[COMMON_LOG_COL_DEFAULT]); - } - - if (fcur) { + if (level == GGML_LOG_LEVEL_WARN || level == GGML_LOG_LEVEL_ERROR || level == GGML_LOG_LEVEL_DEBUG) { + fprintf(fcur, "%s", g_col[COMMON_LOG_COL_DEFAULT]); + } fflush(fcur); }