From 4886e6f8ff4ebb7394d99d94d6bf5e4921ebb1f0 Mon Sep 17 00:00:00 2001 From: Hu Yueh-Wei Date: Wed, 6 Nov 2024 08:37:49 +0700 Subject: [PATCH] feat: add color to log (#237) --- core/include/ten_utils/log/log.h | 13 ++ .../ten_utils/log/formatter.h | 24 ++++ core/include_internal/ten_utils/log/log.h | 3 + core/include_internal/ten_utils/log/output.h | 4 +- .../ten_utils/log/termcolor.h | 18 +++ core/src/ten_utils/log/formatter.c | 121 ++++++++++++++++++ core/src/ten_utils/log/global.c | 2 +- core/src/ten_utils/log/log.c | 39 ++---- core/src/ten_utils/log/output.c | 18 ++- 9 files changed, 205 insertions(+), 37 deletions(-) create mode 100644 core/include_internal/ten_utils/log/formatter.h create mode 100644 core/include_internal/ten_utils/log/termcolor.h create mode 100644 core/src/ten_utils/log/formatter.c diff --git a/core/include/ten_utils/log/log.h b/core/include/ten_utils/log/log.h index 2d2ee264d..eb3562f51 100644 --- a/core/include/ten_utils/log/log.h +++ b/core/include/ten_utils/log/log.h @@ -101,6 +101,12 @@ typedef struct ten_string_t ten_string_t; typedef void (*ten_log_output_func_t)(ten_string_t *msg, void *user_data); typedef void (*ten_log_close_func_t)(void *user_data); +typedef void (*ten_log_formatter_func_t)(ten_string_t *buf, TEN_LOG_LEVEL level, + const char *func_name, + size_t func_name_len, + const char *file_name, + size_t file_name_len, size_t line_no, + const char *msg, size_t msg_len); typedef struct ten_log_output_t { ten_log_output_func_t output_cb; @@ -108,11 +114,18 @@ typedef struct ten_log_output_t { void *user_data; } ten_log_output_t; +typedef struct ten_log_formatter_t { + ten_log_formatter_func_t format_cb; + void *user_data; // In case the formatter needs any user data +} ten_log_formatter_t; + typedef struct ten_log_t { ten_signature_t signature; TEN_LOG_LEVEL output_level; ten_log_output_t output; + + ten_log_formatter_t formatter; } ten_log_t; TEN_UTILS_API ten_log_t ten_global_log; diff --git a/core/include_internal/ten_utils/log/formatter.h b/core/include_internal/ten_utils/log/formatter.h new file mode 100644 index 000000000..a2584d4e7 --- /dev/null +++ b/core/include_internal/ten_utils/log/formatter.h @@ -0,0 +1,24 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "ten_utils/ten_config.h" + +#include "ten_utils/log/log.h" + +TEN_UTILS_PRIVATE_API void ten_log_default_formatter( + ten_string_t *buf, TEN_LOG_LEVEL level, const char *func_name, + size_t func_name_len, const char *file_name, size_t file_name_len, + size_t line_no, const char *msg, size_t msg_len); + +TEN_UTILS_PRIVATE_API void ten_log_colored_formatter( + ten_string_t *buf, TEN_LOG_LEVEL level, const char *func_name, + size_t func_name_len, const char *file_name, size_t file_name_len, + size_t line_no, const char *msg, size_t msg_len); + +TEN_UTILS_PRIVATE_API void ten_log_set_formatter( + ten_log_t *self, ten_log_formatter_func_t format_cb, void *user_data); diff --git a/core/include_internal/ten_utils/log/log.h b/core/include_internal/ten_utils/log/log.h index fbfd30238..deb457e3c 100644 --- a/core/include_internal/ten_utils/log/log.h +++ b/core/include_internal/ten_utils/log/log.h @@ -31,6 +31,9 @@ TEN_UTILS_API void ten_log_deinit(ten_log_t *self); TEN_UTILS_PRIVATE_API void ten_log_destroy(ten_log_t *self); +TEN_UTILS_PRIVATE_API const char *filename(const char *path, size_t path_len, + size_t *filename_len); + TEN_UTILS_API void ten_log_log_with_size_from_va_list( ten_log_t *self, TEN_LOG_LEVEL level, const char *func_name, size_t func_name_len, const char *file_name, size_t file_name_len, diff --git a/core/include_internal/ten_utils/log/output.h b/core/include_internal/ten_utils/log/output.h index a4e2bcdeb..6a468cc11 100644 --- a/core/include_internal/ten_utils/log/output.h +++ b/core/include_internal/ten_utils/log/output.h @@ -20,8 +20,8 @@ typedef struct ten_string_t ten_string_t; TEN_UTILS_API void ten_log_set_output_to_stderr(ten_log_t *self); -TEN_UTILS_PRIVATE_API void ten_log_out_stderr_cb(ten_string_t *msg, - void *user_data); +TEN_UTILS_PRIVATE_API void ten_log_output_to_stderr_cb(ten_string_t *msg, + void *user_data); TEN_UTILS_PRIVATE_API void ten_log_set_output_to_file(ten_log_t *self, const char *log_path); diff --git a/core/include_internal/ten_utils/log/termcolor.h b/core/include_internal/ten_utils/log/termcolor.h new file mode 100644 index 000000000..976b908a2 --- /dev/null +++ b/core/include_internal/ten_utils/log/termcolor.h @@ -0,0 +1,18 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "ten_utils/ten_config.h" + +#define TEN_LOG_COLOR_RESET "\033[0m" +#define TEN_LOG_COLOR_RED "\033[31m" +#define TEN_LOG_COLOR_GREEN "\033[32m" +#define TEN_LOG_COLOR_YELLOW "\033[33m" +#define TEN_LOG_COLOR_BLUE "\033[34m" +#define TEN_LOG_COLOR_MAGENTA "\033[35m" +#define TEN_LOG_COLOR_CYAN "\033[36m" +#define TEN_LOG_COLOR_WHITE "\033[37m" diff --git a/core/src/ten_utils/log/formatter.c b/core/src/ten_utils/log/formatter.c new file mode 100644 index 000000000..5e2bdacb1 --- /dev/null +++ b/core/src/ten_utils/log/formatter.c @@ -0,0 +1,121 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "ten_utils/ten_config.h" + +#include + +#include "include_internal/ten_utils/log/level.h" +#include "include_internal/ten_utils/log/log.h" +#include "include_internal/ten_utils/log/pid.h" +#include "include_internal/ten_utils/log/termcolor.h" +#include "include_internal/ten_utils/log/time.h" +#include "ten_utils/lib/string.h" +#include "ten_utils/log/log.h" + +void ten_log_set_formatter(ten_log_t *self, ten_log_formatter_func_t format_cb, + void *user_data) { + TEN_ASSERT(self, "Invalid argument."); + + self->formatter.format_cb = format_cb; + self->formatter.user_data = user_data; +} + +// Default formatter (no colors). +void ten_log_default_formatter(ten_string_t *buf, TEN_LOG_LEVEL level, + const char *func_name, size_t func_name_len, + const char *file_name, size_t file_name_len, + size_t line_no, const char *msg, + size_t msg_len) { + struct tm time_info; + size_t msec = 0; + + ten_log_get_time(&time_info, &msec); + ten_log_add_time_string(buf, &time_info, msec); + + int64_t pid = 0; + int64_t tid = 0; + ten_log_get_pid_tid(&pid, &tid); + + ten_string_append_formatted(buf, " %d(%d) %c", pid, tid, + ten_log_level_char(level)); + + if (func_name_len) { + ten_string_append_formatted(buf, " %.*s", (int)func_name_len, func_name); + } + + size_t actual_file_name_len = 0; + const char *actual_file_name = + filename(file_name, file_name_len, &actual_file_name_len); + if (actual_file_name_len) { + ten_string_append_formatted(buf, "@%.*s:%d", (int)actual_file_name_len, + actual_file_name, (int)line_no); + } + + ten_string_append_formatted(buf, " %.*s", (int)msg_len, msg); +} + +// Colored formatter. +void ten_log_colored_formatter(ten_string_t *buf, TEN_LOG_LEVEL level, + const char *func_name, size_t func_name_len, + const char *file_name, size_t file_name_len, + size_t line_no, const char *msg, + size_t msg_len) { + struct tm time_info; + size_t msec = 0; + ten_log_get_time(&time_info, &msec); + ten_log_add_time_string(buf, &time_info, msec); + + int64_t pid = 0; + int64_t tid = 0; + ten_log_get_pid_tid(&pid, &tid); + + // Determine color based on log level. + const char *level_color = NULL; + switch (level) { + case TEN_LOG_LEVEL_FATAL: + case TEN_LOG_LEVEL_ERROR: + level_color = TEN_LOG_COLOR_RED; + break; + case TEN_LOG_LEVEL_WARN: + level_color = TEN_LOG_COLOR_YELLOW; + break; + case TEN_LOG_LEVEL_INFO: + level_color = TEN_LOG_COLOR_GREEN; + break; + case TEN_LOG_LEVEL_DEBUG: + case TEN_LOG_LEVEL_VERBOSE: + level_color = TEN_LOG_COLOR_CYAN; + break; + default: + level_color = TEN_LOG_COLOR_WHITE; + break; + } + + ten_string_append_formatted(buf, " %d(%d) %s%c%s", pid, tid, level_color, + ten_log_level_char(level), TEN_LOG_COLOR_RESET); + + // Add color to function name. + if (func_name_len) { + ten_string_append_formatted(buf, " %s%.*s%s", TEN_LOG_COLOR_MAGENTA, + (int)func_name_len, func_name, + TEN_LOG_COLOR_RESET); + } + + // Add color to file name and line number. + size_t actual_file_name_len = 0; + const char *actual_file_name = + filename(file_name, file_name_len, &actual_file_name_len); + if (actual_file_name_len) { + ten_string_append_formatted(buf, "%s@%.*s:%d%s", TEN_LOG_COLOR_BLUE, + (int)actual_file_name_len, actual_file_name, + (int)line_no, TEN_LOG_COLOR_RESET); + } + + // Add color to message. + ten_string_append_formatted(buf, " %s%.*s%s", TEN_LOG_COLOR_WHITE, + (int)msg_len, msg, TEN_LOG_COLOR_RESET); +} diff --git a/core/src/ten_utils/log/global.c b/core/src/ten_utils/log/global.c index 4628c2d55..ea7d6dc9b 100644 --- a/core/src/ten_utils/log/global.c +++ b/core/src/ten_utils/log/global.c @@ -15,7 +15,7 @@ ten_log_t ten_global_log = {TEN_LOG_SIGNATURE, TEN_LOG_LEVEL_DEBUG, - {ten_log_out_stderr_cb, NULL, NULL}}; + {ten_log_output_to_stderr_cb, NULL, NULL}}; void ten_log_global_init(void) { ten_log_init(&ten_global_log); } diff --git a/core/src/ten_utils/log/log.c b/core/src/ten_utils/log/log.c index 785cf9f95..29d0d82fa 100644 --- a/core/src/ten_utils/log/log.c +++ b/core/src/ten_utils/log/log.c @@ -12,11 +12,9 @@ #include #include "include_internal/ten_utils/lib/string.h" -#include "include_internal/ten_utils/log/level.h" +#include "include_internal/ten_utils/log/formatter.h" #include "include_internal/ten_utils/log/log.h" #include "include_internal/ten_utils/log/output.h" -#include "include_internal/ten_utils/log/pid.h" -#include "include_internal/ten_utils/log/time.h" #include "ten_utils/lib/signature.h" #include "ten_utils/lib/string.h" @@ -70,8 +68,7 @@ void ten_log_destroy(ten_log_t *self) { static const char *funcname(const char *func) { return func ? func : ""; } -static const char *filename(const char *path, size_t path_len, - size_t *filename_len) { +const char *filename(const char *path, size_t path_len, size_t *filename_len) { assert(filename_len && "Invalid argument."); if (!path || path_len == 0) { @@ -185,33 +182,15 @@ void ten_log_log_with_size(ten_log_t *self, TEN_LOG_LEVEL level, ten_string_t buf; ten_string_init(&buf); - struct tm time_info; - size_t msec = 0; - ten_log_get_time(&time_info, &msec); - ten_log_add_time_string(&buf, &time_info, msec); - - int64_t pid = 0; - int64_t tid = 0; - ten_log_get_pid_tid(&pid, &tid); - - ten_string_append_formatted(&buf, " %d(%d) %c", pid, tid, - ten_log_level_char(level)); - - if (func_name_len) { - ten_string_append_formatted(&buf, " %.*s", func_name_len, - funcname(func_name)); + if (self->formatter.format_cb) { + self->formatter.format_cb(&buf, level, func_name, func_name_len, file_name, + file_name_len, line_no, msg, msg_len); + } else { + // Use default formatter if none is set. + ten_log_default_formatter(&buf, level, func_name, func_name_len, file_name, + file_name_len, line_no, msg, msg_len); } - size_t actual_file_name_len = 0; - const char *actual_file_name = - filename(file_name, file_name_len, &actual_file_name_len); - if (actual_file_name_len) { - ten_string_append_formatted(&buf, "@%.*s:%d", actual_file_name_len, - actual_file_name, line_no); - } - - ten_string_append_formatted(&buf, " %.*s", msg_len, msg); - self->output.output_cb(&buf, self->output.user_data); ten_string_deinit(&buf); diff --git a/core/src/ten_utils/log/output.c b/core/src/ten_utils/log/output.c index 0b3bcef9b..dfa8db3e6 100644 --- a/core/src/ten_utils/log/output.c +++ b/core/src/ten_utils/log/output.c @@ -16,6 +16,7 @@ #include #endif +#include "include_internal/ten_utils/log/formatter.h" #include "include_internal/ten_utils/log/log.h" #include "include_internal/ten_utils/log/output.h" #include "ten_utils/lib/file.h" @@ -56,7 +57,7 @@ static int *get_log_fd(const char *log_path) { return fd_ptr; } -static void ten_log_output_file_cb(ten_string_t *msg, void *user_data) { +static void ten_log_output_to_file_cb(ten_string_t *msg, void *user_data) { assert(msg && "Invalid argument."); if (!user_data) { @@ -87,10 +88,13 @@ void ten_log_set_output_to_file(ten_log_t *self, const char *log_path) { assert(log_path && "Invalid argument."); int *fd = get_log_fd(log_path); - ten_log_output_set(self, ten_log_output_file_cb, ten_log_close_file_cb, fd); + ten_log_output_set(self, ten_log_output_to_file_cb, ten_log_close_file_cb, + fd); + + ten_log_set_formatter(self, ten_log_default_formatter, NULL); } -void ten_log_out_stderr_cb(ten_string_t *msg, void *user_data) { +void ten_log_output_to_stderr_cb(ten_string_t *msg, void *user_data) { assert(msg && "Invalid argument."); (void)user_data; @@ -112,5 +116,11 @@ void ten_log_out_stderr_cb(ten_string_t *msg, void *user_data) { } void ten_log_set_output_to_stderr(ten_log_t *self) { - ten_log_output_set(self, ten_log_out_stderr_cb, NULL, NULL); + ten_log_output_set(self, ten_log_output_to_stderr_cb, NULL, NULL); + +#if defined(OS_LINUX) || defined(OS_MACOS) + ten_log_set_formatter(self, ten_log_colored_formatter, NULL); +#else + ten_log_set_formatter(self, ten_log_default_formatter, NULL); +#endif }