diff --git a/README.en.md b/README.en.md index 7102038..270e53d 100644 --- a/README.en.md +++ b/README.en.md @@ -32,13 +32,11 @@ cmake --install . #include "logging.h" int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); + Log_info("This is an info message"); + Log_error("This is an error message%s", "123"); + Log_fatal("This is an fatal message"); + Log_debug("This is a debug message"); + Log_warning("This is a warning message%s", "123"); destroyDefaultLogger(); return 0; @@ -51,14 +49,14 @@ int main() { #include "logging/logging-handler.h" int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - logger->addHandler(loggingHandlerFile("test1", 1024*1024)); + log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); + addHandler(getDefaultLogger(), hander); - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); + Log_info("This is an info message"); + Log_error("This is an error message%s", "123"); + Log_fatal("This is an fatal message"); + Log_debug("This is a debug message"); + Log_warning("This is a warning message%s", "123"); destroyDefaultLogger(); return 0; @@ -69,92 +67,51 @@ int main() { > Support adding custom filters, currently with built-in substring filters > The function of an filter is to redirect filtered logs to the filter's dedicated processor - -#### example -Redirects filtered logs to a dedicated file processor -```c -#include "logging.h" -#include - -int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); - - char *test1[] = {"123", "tt", NULL}; - - log_filter *tint = loggingFilterSubStr( - test1, - LOG_DEBUG, - loggingHandlerFile("test_interceptor", 1024 * 1024), - true); - - logger->addFilter(tint); - - printf("\n"); - printf("filter added\n"); - printf("\n"); - - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); - - destroyDefaultLogger(); - return 0; -} -``` - #### Multiple substring filters ```c #include "logging.h" +#include "logging/logging-core.h" +#include "logging/logging-filter.h" #include #include #include int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); + Log_info("This is an info message"); + Log_error("This is an error message%s", "123"); + Log_fatal("This is an fatal message"); + Log_debug("This is a debug message"); + Log_warning("This is a warning message%s", "123"); - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); + char *test1[] = {"This", NULL}; - char *test1[] = {"This",NULL}; + log_filter *tint = + loggingFilterSubStr(test1, + LOG_DEBUG, + loggingHandlerFile("test_interceptor", 1024 * 1024), + false); - log_filter *tint = loggingFilterSubStr( - test1, - LOG_DEBUG, - loggingHandlerFile("test_interceptor", 1024 * 1024), - false); + addFilter(getDefaultLogger(), tint); - logger->addFilter(tint); - - char *test2[] = {"123",NULL}; + char *test2[] = {"123", NULL}; log_filter *tint1 = loggingFilterSubStr( test2, - LOG_DEBUG, + LOG_ERROR, loggingHandlerFile("test_interceptor1", 1024 * 1024), true); - logger->addFilter(tint1); + addFilter(getDefaultLogger(), tint1); printf("\n"); printf("filter added\n"); printf("\n"); - log_info("This is an info message"); - log_error("This is an error message%s", "123"); - log_fatal("This is an fatal message"); - log_debug("This is a debug message"); - log_warning("This is a warning message%s", "123"); + Log_info("This is an info message"); + Log_error("This is an error message%s", "123"); + Log_fatal("This is an fatal message"); + Log_debug("This is a debug message"); + Log_warning("This is a warning message%s", "123"); destroyDefaultLogger(); return 0; diff --git a/README.md b/README.md index 882fa4b..6c4742f 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,6 @@ cmake --install . #include "logging.h" int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - Log_info("This is an info message"); Log_error("This is an error message%s", "123"); Log_fatal("This is an fatal message"); @@ -66,8 +64,8 @@ int main() { #include "logging/logging-handler.h" int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - logger->addHandler(loggingHandlerFile("test1", 1024*1024)); + log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); + addHandler(getDefaultLogger(), hander); Log_info("This is an info message"); Log_error("This is an error message%s", "123"); @@ -85,82 +83,41 @@ int main() { > 过滤器的作用:可以将过滤到的日志重定向到过滤器的专属处理器中 - -#### 单个子串过滤器 -将过滤到的日志重定向到专属处理器中 -```c -#include "logging.h" -#include - -int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - - Log_info("This is an info message"); - Log_error("This is an error message%s", "123"); - Log_fatal("This is an fatal message"); - Log_debug("This is a debug message"); - Log_warning("This is a warning message%s", "123"); - - char *test1[] = {"123", "tt", NULL}; - - log_filter *tint = loggingFilterSubStr( - test1, - LOG_DEBUG, - loggingHandlerFile("test_interceptor", 1024 * 1024), - true); - - logger->addFilter(tint); - - printf("\n"); - printf("filter added\n"); - printf("\n"); - - Log_info("This is an info message"); - Log_error("This is an error message%s", "123"); - Log_fatal("This is an fatal message"); - Log_debug("This is a debug message"); - Log_warning("This is a warning message%s", "123"); - - destroyDefaultLogger(); - return 0; -} -``` - #### 多个子串过滤器 ```c #include "logging.h" +#include "logging/logging-core.h" +#include "logging/logging-filter.h" #include #include #include int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); - Log_info("This is an info message"); Log_error("This is an error message%s", "123"); Log_fatal("This is an fatal message"); Log_debug("This is a debug message"); Log_warning("This is a warning message%s", "123"); - char *test1[] = {"This",NULL}; + char *test1[] = {"This", NULL}; - log_filter *tint = loggingFilterSubStr( - test1, - LOG_DEBUG, - loggingHandlerFile("test_interceptor", 1024 * 1024), - false); + log_filter *tint = + loggingFilterSubStr(test1, + LOG_DEBUG, + loggingHandlerFile("test_interceptor", 1024 * 1024), + false); - logger->addFilter(tint); + addFilter(getDefaultLogger(), tint); - char *test2[] = {"123",NULL}; + char *test2[] = {"123", NULL}; log_filter *tint1 = loggingFilterSubStr( test2, - LOG_DEBUG, + LOG_ERROR, loggingHandlerFile("test_interceptor1", 1024 * 1024), true); - logger->addFilter(tint1); + addFilter(getDefaultLogger(), tint1); printf("\n"); printf("filter added\n"); diff --git a/conanfile.py b/conanfile.py index 5153e40..feb387b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,7 @@ import os class loggingRecipe(ConanFile): name = "logging" - version = "0.5.1" + version = "1.0.0" license = "MIT" author = "321640253@qq.com" url = "https://github.com/WangZhongDian/logging.git" diff --git a/include/logging.h b/include/logging.h index 230e4ec..af9fa6b 100644 --- a/include/logging.h +++ b/include/logging.h @@ -3,6 +3,7 @@ #include #include +#include #include "logging/logging-core.h" #include "logging/logging-filter.h" @@ -12,51 +13,72 @@ extern "C" { #endif +// 默认日志器宏 #define Log_fatal(format, ...) \ - log_fatal(__FILE__, __LINE__, format, ##__VA_ARGS__) + logMessage(NULL, LOG_FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__) #define Log_error(format, ...) \ - log_error(__FILE__, __LINE__, format, ##__VA_ARGS__) + logMessage(NULL, LOG_ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__) #define Log_warning(format, ...) \ - log_warning(__FILE__, __LINE__, format, ##__VA_ARGS__) + logMessage(NULL, LOG_WARNING, __FILE__, __LINE__, format, ##__VA_ARGS__) #define Log_info(format, ...) \ - log_info(__FILE__, __LINE__, format, ##__VA_ARGS__) + logMessage(NULL, LOG_INFO, __FILE__, __LINE__, format, ##__VA_ARGS__) #define Log_debug(format, ...) \ - log_debug(__FILE__, __LINE__, format, ##__VA_ARGS__) + logMessage(NULL, LOG_DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__) + +// 日志器宏 +#define log_fatal(logger, format, ...) \ + logMessage(logger, LOG_FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__) +#define log_error(logger, format, ...) \ + logMessage(logger, LOG_ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__) +#define log_warning(logger, format, ...) \ + logMessage(logger, LOG_WARNING, __FILE__, __LINE__, format, ##__VA_ARGS__) +#define log_info(logger, format, ...) \ + logMessage(logger, LOG_INFO, __FILE__, __LINE__, format, ##__VA_ARGS__) +#define log_debug(logger, format, ...) \ + logMessage(logger, LOG_DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__) typedef struct Logger { log_level level; log_Handler *handler; log_filter *filter; const char *name; - bool (*addHandler)(log_Handler *handler); - bool (*addFilter)(log_filter *filter); } Logger; -void log_fatal(const char *file, int line, const char *format, ...); -void log_error(const char *file, int line, const char *format, ...); -void log_warning(const char *file, int line, const char *format, ...); -void log_info(const char *file, int line, const char *format, ...); -void log_debug(const char *file, int line, const char *format, ...); +bool addHandler(Logger *logger, log_Handler *handler); +bool addFilter(Logger *logger, log_filter *filter); + +void logMessage(Logger *logger, + log_level level, + const char *file, + int line, + const char *message, + ...); /** -* @brief -创建默认日志对象,日志对象为单例模式,后续可通过getDefaultLogger方法获取, - 重复调用该方法不会创建新的日志对象,只会返回默认日志对象,并且会修改默认日志对象的名称和等级 -* @param name 日志名称 -* @param level 日志等级 -* @return Logger* 日志对象指针 -*/ -Logger *newDefaultLogger(const char *name, log_level level); - + * @brief 创建一个日志句柄对象 + * @param name 日志器名称 + * @return 日志句柄对象 + */ +Logger *newLogger(const char *name); /** * @brief 获取默认日志对象 + * @return 默认日志对象 */ Logger *getDefaultLogger(void); +Logger *getLogger(const char *name); + /** * @brief 销毁日志对象,该方法会销毁默认日志对象 */ -log_status destroyDefaultLogger(void); +void destroyDefaultLogger(void); + +/** + * @brief 销毁日志对象 + * @param logger 日志对象 + * @return void + */ +void destroyLogger(Logger *logger); #ifdef __cplusplus } diff --git a/include/logging/logging-core.h b/include/logging/logging-core.h index 8bcb614..4ec27f9 100644 --- a/include/logging/logging-core.h +++ b/include/logging/logging-core.h @@ -13,6 +13,14 @@ typedef enum { LOG_DEBUG, } log_level; +static const char *LOG_LEVEL_STR[] = { + "FATAL", + "ERROR", + "WARNING", + "INFO", + "DEBUG", +}; + typedef enum { L_ERROR, L_OK, diff --git a/pyproject.toml b/pyproject.toml index 8f41d9e..629cc91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "logging" -version = "0.1.0" +version = "1.0.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.12" diff --git a/src/logging.c b/src/logging.c index 45e925f..310ef49 100644 --- a/src/logging.c +++ b/src/logging.c @@ -1,6 +1,7 @@ #include "logging.h" #include "logging/logging-core.h" #include "logging/logging-handler.h" +#include "utils/logging-map.h" #include "utils/logging-utils.h" #include #include @@ -18,23 +19,25 @@ #define LOG_BUFFER_SIZE 4096 // 日志缓冲区大小,单个日志长度不能超过该值 -static Logger *G_LOGGER = NULL; // 全局日志对象,唯一实例 +static Logger *ROOT_LOGGER = NULL; // 根日志对象,唯一实例 + +static Map *LOGGER_MAP = NULL; // 日志对象映射表 /** * @brief 为日志添加一个handler * @param handler 处理器对象 */ -static bool addHandler(log_Handler *handler) { - if (G_LOGGER == NULL || handler == NULL) { +bool addHandler(Logger *logger, log_Handler *handler) { + if (logger == NULL || handler == NULL) { return false; } - if (G_LOGGER->handler == NULL) { - G_LOGGER->handler = handler; + if (logger->handler == NULL) { + logger->handler = handler; return true; } - G_LOGGER->handler->_free(G_LOGGER->handler); - G_LOGGER->handler = handler; + logger->handler->_free(logger->handler); + logger->handler = handler; return true; } @@ -42,21 +45,17 @@ static bool addHandler(log_Handler *handler) { * @brief 为日志添加一个filter * @param filter 过滤器对象 */ -/** - * @brief 为日志添加一个filter - * @param filter 过滤器对象 - */ -static bool addFilter(log_filter *filter) { - if (G_LOGGER == NULL || filter == NULL) { +bool addFilter(Logger *logger, log_filter *filter) { + if (logger == NULL || filter == NULL) { return false; } - if (G_LOGGER->filter == NULL) { - G_LOGGER->filter = filter; - G_LOGGER->filter->next = NULL; + if (logger->filter == NULL) { + logger->filter = filter; + logger->filter->next = NULL; return true; } - log_filter *it = G_LOGGER->filter; + log_filter *it = logger->filter; while (it->next != NULL) { it = it->next; } @@ -80,18 +79,19 @@ static bool addFilter(log_filter *filter) { * @param color 应用的颜色 * @param message 日志内容 */ -static void output_to_handler(log_Handler *handler, - char *level, - const char *color, - const char *message) { +static void output_to_handler(Logger *logger, + char *level, + const char *color, + const char *message) { + char timeStr[20]; getTimeStr(timeStr); char logStr[LOG_BUFFER_SIZE * 2]; - if (handler->apply_color) { + if (logger->handler->apply_color) { snprintf(logStr, LOG_BUFFER_SIZE * 2, "[%s]: %s %s%s%s %s\n", - G_LOGGER->name, + logger->name, timeStr, color, level, @@ -101,13 +101,13 @@ static void output_to_handler(log_Handler *handler, snprintf(logStr, LOG_BUFFER_SIZE * 2, "[%s]: %s %s %s\n", - G_LOGGER->name, + logger->name, timeStr, level, message); } - handler->output(handler, logStr); + logger->handler->output(logger->handler, logStr); } /** @@ -118,134 +118,153 @@ static void output_to_handler(log_Handler *handler, * @param ... 格式化参数列表 * @return */ -static void log_cope(log_level level_e, - char *level, - const char *color, - const char *message) { - if (G_LOGGER == NULL) { +static void +log_cope(Logger *logger, char *level, const char *color, const char *message) { + if (logger == NULL) { return; } - if (G_LOGGER->handler == NULL) { + if (logger->handler == NULL) { return; } - log_filter *it = G_LOGGER->filter; - log_Handler *handler = G_LOGGER->handler; + log_filter *it = logger->filter; + log_Handler *handler = logger->handler; while (it != NULL) { - if (it->_dispose(it, level_e, message)) { - output_to_handler(it->handler, level, color, message); + if (it->_dispose(it, logger->level, message)) { + output_to_handler(logger, level, color, message); if (it->jump_out) { return; } } it = it->next; } - output_to_handler(handler, level, color, message); + output_to_handler(logger, level, color, message); } -void log_fatal(const char *file, int line, const char *message, ...) { - if (G_LOGGER->level >= LOG_ERROR) { - char logStr[LOG_BUFFER_SIZE]; - char finalLogStr[LOG_BUFFER_SIZE * 2]; +void logMessage(Logger *logger, + log_level level, + const char *file, + int line, + const char *message, + ...) { + Logger *_logger = NULL; + if (logger == NULL) { + if (ROOT_LOGGER == NULL) { + ROOT_LOGGER = newLogger("ROOT"); // 创建根日志对象 + } + _logger = ROOT_LOGGER; + } else { + _logger = logger; // 使用传入的日志对象 + } + + if (_logger->level >= level) { + char logStr + [LOG_BUFFER_SIZE]; // 定义一个缓冲区,用于存储格式化后的日志字符串 + char finalLogStr[LOG_BUFFER_SIZE * + 2]; // 定义一个缓冲区,用于存储最终输出的日志字符串 va_list args; va_start(args, message); vsprintf(logStr, message, args); va_end(args); snprintf( finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); - log_cope(LOG_FATAL, "Fatal", RED_B, finalLogStr); + + switch (level) { + case LOG_DEBUG: + log_cope(_logger, "Debug", BLUE, finalLogStr); + break; + case LOG_INFO: + log_cope(_logger, "Info", GREEN, finalLogStr); + break; + case LOG_WARNING: + log_cope(_logger, "Warning", YELLOW, finalLogStr); + break; + case LOG_ERROR: + log_cope(_logger, "Error", RED, finalLogStr); + break; + case LOG_FATAL: + log_cope(_logger, "Fatal", RED_B, finalLogStr); + break; + default: + break; + } } } -void log_error(const char *file, int line, const char *message, ...) { - if (G_LOGGER->level >= LOG_ERROR) { - char logStr[LOG_BUFFER_SIZE]; - char finalLogStr[LOG_BUFFER_SIZE * 2]; - va_list args; - va_start(args, message); - vsprintf(logStr, message, args); - va_end(args); - snprintf( - finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); - log_cope(LOG_ERROR, "Error", RED, finalLogStr); - } -} - -void log_warning(const char *file, int line, const char *message, ...) { - if (G_LOGGER->level >= LOG_WARNING) { - char logStr[LOG_BUFFER_SIZE]; - char finalLogStr[LOG_BUFFER_SIZE * 2]; - va_list args; - va_start(args, message); - vsprintf(logStr, message, args); - va_end(args); - snprintf( - finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); - log_cope(LOG_WARNING, "Warning", YELLOW, finalLogStr); - } -} - -void log_info(const char *file, int line, const char *message, ...) { - if (G_LOGGER->level >= LOG_INFO) { - char logStr[LOG_BUFFER_SIZE]; - char finalLogStr[LOG_BUFFER_SIZE * 2]; - va_list args; - va_start(args, message); - vsprintf(logStr, message, args); - va_end(args); - snprintf( - finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); - log_cope(LOG_INFO, "Info", GREEN, finalLogStr); - } -} - -void log_debug(const char *file, int line, const char *message, ...) { - if (G_LOGGER->level >= LOG_DEBUG) { - char logStr[LOG_BUFFER_SIZE]; - char finalLogStr[LOG_BUFFER_SIZE * 2]; - va_list args; - va_start(args, message); - vsprintf(logStr, message, args); - va_end(args); - snprintf( - finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); - log_cope(LOG_DEBUG, "Debug", CYAN, finalLogStr); - } -} - -Logger *newDefaultLogger(const char *name, log_level level) { - if (G_LOGGER != NULL) { - G_LOGGER->name = name; - G_LOGGER->level = level; - return G_LOGGER; - } - - Logger *logger = (Logger *)malloc(sizeof(Logger)); - - logger->addHandler = addHandler; - logger->addFilter = addFilter; - - logger->level = level; - logger->handler = loggingHandlerConsole(); - logger->name = name; - logger->filter = NULL; - - G_LOGGER = logger; - return G_LOGGER; -} - /** - * @brief 销毁日志对象 + * @brief 创建一个日志句柄 + * @param name 日志器名称 + * @return 日志器对象 */ -log_status destroyDefaultLogger(void) { - if (G_LOGGER != NULL) { - if (G_LOGGER->handler != NULL) { - G_LOGGER->handler->_free(G_LOGGER->handler); +Logger *newLogger(const char *name) { + Logger *logger = (Logger *)malloc(sizeof(Logger)); + if (logger == NULL) { + return NULL; + } + + if (LOGGER_MAP == NULL) { + LOGGER_MAP = map_create(sizeof(Logger **)); + } + + logger->level = LOG_INFO; + logger->handler = loggingHandlerConsole(); + logger->name = name; + logger->filter = NULL; + + map_put(LOGGER_MAP, name, &logger); + + return logger; +} + +Logger *getDefaultLogger(void) { + if (ROOT_LOGGER != NULL) { + return ROOT_LOGGER; + } + + ROOT_LOGGER = newLogger("ROOT"); + return ROOT_LOGGER; +} + +/** + * @brief 获取日志器对象 + * @param name 日志器名称 + * @param level 日志等级 + * @return 日志器对象 + */ +Logger *getLogger(const char *name) { + if (name == NULL) { + return NULL; + } + if (LOGGER_MAP == NULL) { + LOGGER_MAP = map_create(sizeof(Logger **)); + } + + Logger **cache_logger_ptr = (Logger **)map_get(LOGGER_MAP, name); + if (cache_logger_ptr != NULL) { + return *cache_logger_ptr; + } + + Logger *logger = (Logger *)malloc(sizeof(Logger)); + + logger->level = LOG_INFO; + logger->handler = loggingHandlerConsole(); + logger->name = name; + logger->filter = NULL; + + map_put(LOGGER_MAP, name, &logger); + + return logger; +} + +void destroyLogger(Logger *logger) { + if (logger != NULL) { + if (logger->handler != NULL) { + logger->handler->_free(logger->handler); } - if (G_LOGGER->filter != NULL) { - log_filter *it = G_LOGGER->filter; + if (logger->filter != NULL) { + log_filter *it = logger->filter; log_filter *next = NULL; while (it != NULL) { next = it->next; @@ -253,16 +272,21 @@ log_status destroyDefaultLogger(void) { it = next; } } - - free(G_LOGGER); - G_LOGGER = NULL; + free(logger); } - return L_OK; } -Logger *getDefaultLogger(void) { - if (G_LOGGER == NULL) { - return NULL; - } - return G_LOGGER; +static void +__destroyLoggerForeach(const char *key, void *value, void *user_data) { + (void)user_data; + (void)key; + destroyLogger(*(Logger **)value); +} + +/** + * @brief 销毁日志对象 + */ +void destroyDefaultLogger(void) { + map_foreach(LOGGER_MAP, __destroyLoggerForeach, NULL); + map_destroy(LOGGER_MAP); } \ No newline at end of file diff --git a/src/utils/logging-map.c b/src/utils/logging-map.c new file mode 100644 index 0000000..91776f4 --- /dev/null +++ b/src/utils/logging-map.c @@ -0,0 +1,143 @@ +#include "logging-map.h" + +#include +#include + +/* 哈希函数:FNV-1a */ +static uint32_t hash_bytes(const void *data, size_t len) { + const uint8_t *p = data; + uint32_t h = 2166136261u; + while (len--) { + h ^= *p++; + h *= 16777619u; + } + return h; +} + +/* 创建空 map */ +Map *map_create(size_t value_len) { + Map *m = calloc(1, sizeof(*m)); + m->value_len = value_len; + m->bucket_cap = 8; /* 初始桶数 */ + m->bucket = calloc(m->bucket_cap, sizeof(Node *)); + return m; +} + +/* 根据 key 找到桶下标 */ +static size_t bucket_index(Map *m, const char *key) { + size_t len = strlen(key); + uint32_t h = hash_bytes(key, len); + return h & (m->bucket_cap - 1); /* 要求 bucket_cap 是 2 的幂 */ +} + +/* 在桶链中线性查找 */ +static Node *find_in_chain(Node *head, const char *key) { + for (; head; head = head->next) { + if (strcmp(head->key, key) == 0) { + return head; + } + } + return NULL; +} + +/* 扩容:2× 桶数,重新哈希所有节点 */ +static void map_resize(Map *m) { + size_t new_cap = m->bucket_cap * 2; + Node **new_bucket = calloc(new_cap, sizeof(Node *)); + + for (size_t i = 0; i < m->bucket_cap; ++i) { + Node *node = m->bucket[i]; + while (node) { + Node *next = node->next; + size_t idx = + hash_bytes(node->key, strlen(node->key)) & (new_cap - 1); + node->next = new_bucket[idx]; + new_bucket[idx] = node; + node = next; + } + } + free(m->bucket); + m->bucket = new_bucket; + m->bucket_cap = new_cap; +} + +/* 插入或覆盖 */ +void map_put(Map *m, const char *key, const void *value) { + if (m->size * 4 >= m->bucket_cap * 3) { /* 装载因子 0.75 */ + map_resize(m); + } + + size_t idx = bucket_index(m, key); + Node *node = find_in_chain(m->bucket[idx], key); + + if (node) { /* 覆盖旧值 */ + memcpy(node->value, value, m->value_len); + return; + } + + /* 新建节点 */ + node = malloc(sizeof(*node)); + node->value = malloc(m->value_len); + node->next = m->bucket[idx]; + node->key = malloc(strlen(key) + 1); + memcpy(node->key, key, strlen(key) + 1); + memcpy(node->value, value, m->value_len); + m->bucket[idx] = node; + ++m->size; +} + +/* 查找 */ +void *map_get(Map *m, const char *key) { + size_t idx = bucket_index(m, key); + Node *node = find_in_chain(m->bucket[idx], key); + return node ? node->value : NULL; +} + +/* 删除 */ +bool map_erase(Map *m, const char *key) { + size_t idx = bucket_index(m, key); + Node **link = &m->bucket[idx]; + for (; *link; link = &(*link)->next) { + if (strcmp((*link)->key, key) == 0) { + Node *to_del = *link; + *link = to_del->next; + free(to_del->key); + free(to_del->value); + free(to_del); + --m->size; + return true; + } + } + return false; +} + +/* 销毁 */ +void map_destroy(Map *m) { + for (size_t i = 0; i < m->bucket_cap; ++i) { + Node *node = m->bucket[i]; + while (node) { + Node *next = node->next; + free(node->key); + free(node->value); + free(node); + node = next; + } + } + free(m->bucket); + free(m); +} + +/* 遍历 */ +void map_foreach(Map *m, + void (*callback)(const char *key, + void *value, + void *user_data), + void *user_data) { + for (size_t i = 0; i < m->bucket_cap; ++i) { + Node *node = m->bucket[i]; + while (node) { + callback(node->key, node->value, user_data); + node = node->next; + } + } +} \ No newline at end of file diff --git a/src/utils/logging-map.h b/src/utils/logging-map.h new file mode 100644 index 0000000..cae31d7 --- /dev/null +++ b/src/utils/logging-map.h @@ -0,0 +1,45 @@ +#ifndef __LOGGING_MAP_H__ +#define __LOGGING_MAP_H__ + +#include +#include +#include + +typedef struct Node { + struct Node *next; + char *key; + void *value; +} Node; + +struct Map { + size_t value_len; + size_t bucket_cap; + size_t size; /* 当前元素个数 */ + Node **bucket; /* 指针数组 */ +}; + +typedef struct Map Map; + +/* 创建空 map:key_len/value_len 以字节为单位 */ +Map *map_create(size_t value_len); + +/* 插入或覆盖: 必须指向 key_len 字节;同理 value */ +void map_put(Map *m, const char *key, const void *value); + +/* 查找:找到返回 value 指针;未找到返回 NULL */ +void *map_get(Map *m, const char *key); + +/* 删除:返回 true 表示确实删掉了 */ +bool map_erase(Map *m, const char *key); + +/* 遍历: 遍历所有元素*/ +void map_foreach(Map *m, + void (*callback)(const char *key, + void *value, + void *user_data), + void *user_data); + +/* 销毁并释放所有内存 */ +void map_destroy(Map *m); + +#endif /* __LOGGING_MAP_H__ */ \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0baacea..010d63b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,8 @@ project(test) enable_testing() +include_directories(${CMAKE_SOURCE_DIR}/src) + #测试简单基本应用 add_executable(${PROJECT_NAME}simple test-simple.c) target_link_libraries(${PROJECT_NAME}simple logging) @@ -17,3 +19,13 @@ add_test(test_file ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}file${CMAKE_EXECUT add_executable(${PROJECT_NAME}filter test-filter.c) target_link_libraries(${PROJECT_NAME}filter logging) add_test(test_filter ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}filter${CMAKE_EXECUTEABLE_SUFFIX}) + +#测试多log多次获取 +add_executable(${PROJECT_NAME}logs test-logs.c) +target_link_libraries(${PROJECT_NAME}logs logging) +add_test(test_logs ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}logs${CMAKE_EXECUTEABLE_SUFFIX}) + +#测试工具map +add_executable(${PROJECT_NAME}map test-map.c) +target_link_libraries(${PROJECT_NAME}map logging) +add_test(test_map ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}map${CMAKE_EXECUTEABLE_SUFFIX}) \ No newline at end of file diff --git a/tests/test-filter.c b/tests/test-filter.c index 813425d..74babda 100644 --- a/tests/test-filter.c +++ b/tests/test-filter.c @@ -6,8 +6,6 @@ #include int main() { - Logger *logger = newDefaultLogger(__FILE__, LOG_DEBUG); - Log_info("This is an info message"); Log_error("This is an error message%s", "123"); Log_fatal("This is an fatal message"); @@ -22,7 +20,7 @@ int main() { loggingHandlerFile("test_interceptor", 1024 * 1024), false); - logger->addFilter(tint); + addFilter(getDefaultLogger(), tint); char *test2[] = {"123", NULL}; @@ -32,7 +30,7 @@ int main() { loggingHandlerFile("test_interceptor1", 1024 * 1024), true); - logger->addFilter(tint1); + addFilter(getDefaultLogger(), tint1); printf("\n"); printf("filter added\n"); diff --git a/tests/test-log-file.c b/tests/test-log-file.c index a9753c2..0cb136e 100644 --- a/tests/test-log-file.c +++ b/tests/test-log-file.c @@ -2,9 +2,8 @@ #include "logging/logging-handler.h" int main() { - Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); - logger->addHandler(hander); + addHandler(getDefaultLogger(), hander); Log_info("This is an info message"); Log_error("This is an error message%s", "123"); diff --git a/tests/test-logs.c b/tests/test-logs.c new file mode 100644 index 0000000..bf17fcd --- /dev/null +++ b/tests/test-logs.c @@ -0,0 +1,24 @@ +#include "logging.h" +#include "logging/logging-core.h" +#include + +int main() { + Logger *t1 = getLogger("Test1"); + t1->level = LOG_ERROR; + + Logger *t2 = getLogger("Test2"); + t2->level = LOG_DEBUG; + + Logger *t11 = getLogger("Test1"); + + if (t1 == t11) { + printf("t1 and t11 are the same\n"); + printf("t1 log level: %s", LOG_LEVEL_STR[t11->level]); + } else { + printf("t1 and t11 are different\n"); + return 1; + } + + destroyDefaultLogger(); + return 0; +} \ No newline at end of file diff --git a/tests/test-map.c b/tests/test-map.c new file mode 100644 index 0000000..a04ddc2 --- /dev/null +++ b/tests/test-map.c @@ -0,0 +1,37 @@ +#include "utils/logging-map.h" +#include +#include +#include + +void foreach_callback(const char *key, void *value, void *user_data) { + (void)user_data; + printf("foreach key: %s, value: %d\n", key, *(int *)value); +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + Map *map = map_create(sizeof(int)); + + const char *keys[] = {"key1", "key22", "key33", "key44", "key55"}; + + for (int i = 0; i < 5; i++) { + printf("put key %s,value %d\n", keys[i], i); + map_put(map, keys[i], &i); + } + + for (int i = 0; i < 5; i++) { + int *value = map_get(map, keys[i]); + printf("get value: %d\n", *value); + if (*value != i) { + return 1; + } + } + + map_foreach(map, foreach_callback, NULL); + + map_destroy(map); + + return 0; +} diff --git a/tests/test-simple.c b/tests/test-simple.c index 3f7e460..42a5a07 100644 --- a/tests/test-simple.c +++ b/tests/test-simple.c @@ -1,8 +1,6 @@ #include "logging.h" int main() { - Logger *logger = newDefaultLogger(__FILE__, LOG_DEBUG); - Log_info("This is an info message"); Log_error("This is an error message%s", "123"); Log_fatal("This is an fatal message");