From d0bfc31563a69982d1051e54663e140a4fac1192 Mon Sep 17 00:00:00 2001 From: youmetme <103353084+WangZhongDian@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:56:47 +0800 Subject: [PATCH 1/2] Dev (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #feat 增强Fatal级别的底色,修改logging类的方法 * 更新版本号 * 加入test脚本 * fix:conanfile * test action * 修复错别字 * add test on windows action * fix test on windows action * fix action on windows * fix * fix 内存分配错误 * fix msvc 不支持中文注释,删除中文注释 * test on windows and test chinese char * ersion 0.2.4 * feature:根据文件大小分割日志 * fix:内存泄露 * fix:使用char偏移单位 --- README.md | 52 +++++++++-------- conanfile.py | 2 +- include/logging.h | 40 ++++++++++---- include/logging/logging-core.h | 8 +++ include/logging/logging-handler.h | 10 +++- include/logging/logging-interceptor.h | 20 +++++-- src/CMakeLists.txt | 1 + src/handler/logging-handler-file.c | 80 +++++++++++++++++++++++++-- src/logging.c | 72 ++++++++++++------------ src/utils/logging-utils.c | 15 +++++ src/utils/logging-utils.h | 5 ++ tests/test_interceptor.c | 14 +++-- tests/test_simple.c | 5 +- 13 files changed, 231 insertions(+), 93 deletions(-) create mode 100644 src/utils/logging-utils.c create mode 100644 src/utils/logging-utils.h diff --git a/README.md b/README.md index e37816c..34f0226 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ logging是一个轻量级的简单易用C语言日志库,支持日志级别、 - 支持日志输出:控制台、文件 - 支持日志文件:自动创建、自动滚动、自动删除(未完成) +## 安装 +- conan安装使用 +```shell +conan create . --build=missing +``` +- cmake安装使用 +```shell +``` + ## 使用方法 ### 控制台日志 @@ -18,16 +27,15 @@ logging是一个轻量级的简单易用C语言日志库,支持日志级别、 #include "logging.h" int main() { - Logging *log = newLogging(); - Logger *logger = log->getLogger("testLogger", LOG_DEBUG); + Logger *logger = newLogger("testLogger", LOG_DEBUG); logger->info("This is an info message"); - logger->error("你好,这是一个错误消息%s", "123"); + logger->error("This is an error message%s", "123"); logger->fatal("This is an fatal message"); logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - log->destroyLogging(log); + destroyLogger(); return 0; } ``` @@ -35,20 +43,19 @@ int main() { ### 文件日志 ```c #include "logging.h" +#include "logging/logging-handler.h" int main() { - Logging *log = newLogging(); - Logger *logger = log->getLogger("testLogger",LOG_DEBUG); - - logger->addHandler(loggingFileHandler("test")); //为日志对象添加文件处理器 + Logger *logger = newLogger("testLogger", LOG_DEBUG); + logger->addHandler(loggingFileHandler("test1", 1024*1024)); logger->info("This is an info message"); - logger->error("你好,这是一个错误消息%s", "123"); + logger->error("This is an error message%s", "123"); logger->fatal("This is an fatal message"); logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - log->destroyLogging(log); + destroyLogger(); return 0; } ``` @@ -66,19 +73,21 @@ int main() { #include int main() { - Logging *log = newLogging(); - Logger *logger = log->getLogger("testLogger", LOG_DEBUG); + Logger *logger = newLogger("testLogger", LOG_DEBUG); logger->info("This is an info message"); - logger->error("你好,这是一个错误消息%s", "123"); + logger->error("This is an error message%s", "123"); logger->fatal("This is an fatal message"); logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - char *test1[] = {"123", "你好"}; // 要拦截的字符串 - // 添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中 - log_Interceptor *tint = - loggingSubStringInterceptor(test1, 2, LOG_DEBUG, loggingFileHandler("被拦截")); + char *test1[] = {"123", "tt"}; + + log_Interceptor *tint = loggingSubStringInterceptor( + test1, + 2, + LOG_DEBUG, + loggingFileHandler("test_interceptor", 1024 * 1024)); logger->addInterceptor(tint); @@ -87,20 +96,15 @@ int main() { printf("\n"); logger->info("This is an info message"); - logger->error("你好,这是一个错误消息%s", "123"); + logger->error("This is an error message%s", "123"); logger->fatal("This is an fatal message"); logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - log->destroyLogging(log); + destroyLogger(); return 0; } ``` ![](docs/img/2024-09-21-11-44-25.png) ![](docs/img/2024-09-21-11-44-06.png) - -# build -```shell -conan create . --build=missing -``` \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index d2e2cb5..2787442 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,7 @@ import os class loggingRecipe(ConanFile): name = "logging" - version = "0.2.4" + version = "0.3.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 387b071..853aa6d 100644 --- a/include/logging.h +++ b/include/logging.h @@ -8,6 +8,9 @@ #include "logging/logging-handler.h" #include "logging/logging-interceptor.h" +#ifdef __cplusplus +extern "C" { +#endif typedef struct Logger { log_level level; @@ -20,18 +23,35 @@ typedef struct Logger { void (*info)(const char *format, ...); void (*debug)(const char *format, ...); - void (*addHandler)(log_Handler *handler); - void (*addInterceptor)(log_Interceptor *Interceptor); + bool (*addHandler)(log_Handler *handler); + bool (*addInterceptor)(log_Interceptor *Interceptor); } Logger; +/** +* @brief 创建日志对象,日志对象为单例模式,后续可通过getDefaultLogger方法获取, + 重复调用该方法不会创建新的日志对象,只会返回默认日志对象,并且会修改默认日志对象的名称和等级 +* @param name 日志名称 +* @param level 日志等级 +* @return Logger* 日志对象指针 +*/ +Logger *newLogger(const char *name, log_level level); +/** + * @brief 设置日志等级 + * @param logger 日志对象 + * @param level 日志等级 + */ +log_status setLevel(Logger *logger, log_level level); +/** + * @brief 获取默认日志对象 + */ +Logger *getDefaultLogger(void); +/** + * @brief 销毁日志对象,该方法会销毁默认日志对象 + */ +log_status destroyLogger(void); -typedef struct Logging { - Logger *(*getLogger)(const char *name, log_level level); - log_status (*setLevel)(Logger *logger, log_level level); - Logger *(*getCurrentLogger)(void); - log_status (*destroyLogging)(struct Logging *logging); -} Logging; - -Logging *newLogging(); +#ifdef __cplusplus +} +#endif #endif // __LOGGING_H__ \ No newline at end of file diff --git a/include/logging/logging-core.h b/include/logging/logging-core.h index 25e8f6a..5418900 100644 --- a/include/logging/logging-core.h +++ b/include/logging/logging-core.h @@ -1,6 +1,10 @@ #ifndef __LOGGING_CORE_H__ #define __LOGGING_CORE_H__ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { LOG_FATAL, LOG_ERROR, @@ -14,4 +18,8 @@ typedef enum { L_OK, } log_status; +#ifdef __cplusplus +} +#endif + #endif // __LOGGING_CORE_H__ diff --git a/include/logging/logging-handler.h b/include/logging/logging-handler.h index 9254266..79f341f 100644 --- a/include/logging/logging-handler.h +++ b/include/logging/logging-handler.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct log_Handler { void *stream; bool apply_color; @@ -10,7 +14,11 @@ typedef struct log_Handler { void (*output)(struct log_Handler *handler, const char *message); } log_Handler; -log_Handler *loggingFileHandler(const char *name); +log_Handler *loggingFileHandler(const char *name, unsigned int max_size); log_Handler *loggingConsoleHandler(); +#ifdef __cplusplus +} +#endif + #endif //__LOGGING_HANDLER_H__ \ No newline at end of file diff --git a/include/logging/logging-interceptor.h b/include/logging/logging-interceptor.h index 973fe48..543b16a 100644 --- a/include/logging/logging-interceptor.h +++ b/include/logging/logging-interceptor.h @@ -4,6 +4,10 @@ #include "logging-core.h" #include "logging-handler.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct log_Interceptor { log_level level; log_Handler *handler; @@ -12,15 +16,21 @@ typedef struct log_Interceptor { } log_Interceptor; - /** -* @brief 子字符串拦截器 -* @param -* @return -*/ + * @brief 子字符串拦截器 + * @param keywords: 关键字数组 + * @param count: 关键字数组长度 + * @param level: 最低拦截日志等级 + * @param handler: 日志处理器,用于处理拦截下来的日志 + * @return log_Interceptor * + */ log_Interceptor *loggingSubStringInterceptor(char *keywords[], int count, log_level level, log_Handler *handler); +#ifdef __cplusplus +} +#endif + #endif // __LOGGING_INTERCEPTOR_H__ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 93e3dd2..d01b49c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ project(logging) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/handler SRC) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/interceptor SRC) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils SRC) if (SHARED) add_library(${PROJECT_NAME} SHARED ${SRC}) diff --git a/src/handler/logging-handler-file.c b/src/handler/logging-handler-file.c index b2bbc2a..ec92abc 100644 --- a/src/handler/logging-handler-file.c +++ b/src/handler/logging-handler-file.c @@ -1,28 +1,96 @@ #include "logging/logging-handler.h" #include #include +#include + +// 根据log_Handler结构体指针起始获取log_Handler_file_ex_t结构体指针 +// log_Handler_file_ex_t与log_Handler处于连续内存中 +// 使用char*指针进行偏移,达到以偏移1个字节为单位的偏移 +#define Handler_file_EX_PRT(handler) \ + ((log_Handler_file_ex_t *)((char *)handler + sizeof(log_Handler))) + +#define FILE_NAME_MAX_SIZE 50 + +typedef struct log_Handler_file_ex_s { + unsigned int file_size; + unsigned int file_size_max; + unsigned int suffix; + char *file_name; +} log_Handler_file_ex_t; + +static unsigned int getFileSize(FILE *fp) { + fseek(fp, 0L, SEEK_END); + return ftell(fp); +} static void __freeFileHandler(log_Handler *handler) { fclose(handler->stream); + free(Handler_file_EX_PRT(handler)->file_name); free(handler); } +static void changeFile(log_Handler *handler) { + log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); + fclose(handler->stream); + char new_file_name[FILE_NAME_MAX_SIZE]; + sprintf(new_file_name, + "%s_%d.log", + handler_ex->file_name, + ++handler_ex->suffix); + handler->stream = fopen(new_file_name, "at"); + handler_ex->file_size = getFileSize(handler->stream); +} + static void outputFileHandler(log_Handler *handler, const char *message) { fputs(message, handler->stream); + log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); + handler_ex->file_size += strlen(message); + if (handler_ex->file_size > handler_ex->file_size_max) + changeFile(handler); } -log_Handler *loggingFileHandler(const char *name) { - char new_file_name[100]; - sprintf(new_file_name, "%s.log", name); +log_Handler *loggingFileHandler(const char *name, unsigned int max_size) { + char new_file_name[FILE_NAME_MAX_SIZE]; + int suffix = 0; + unsigned int file_size; + FILE *fp = NULL; + log_Handler *handler = NULL; + log_Handler_file_ex_t *handler_ex = NULL; - FILE *fp = fopen(new_file_name, "at"); + do { + sprintf(new_file_name, "%s_%d.log", name, suffix++); + fp = fopen(new_file_name, "at"); + if (fp == NULL) + goto ERROR; + file_size = getFileSize(fp); + } while (file_size > max_size); - log_Handler *handler = (log_Handler *)malloc(sizeof(log_Handler)); + /// 分配log_Handler与记录文件大小的空间 + handler = (log_Handler *)malloc(sizeof(log_Handler) + + sizeof(log_Handler_file_ex_t)); + if (handler == NULL) + goto ERROR; + + handler_ex = Handler_file_EX_PRT(handler); + handler_ex->file_size_max = max_size; + handler_ex->file_size = file_size; + handler_ex->suffix = suffix; + handler_ex->file_name = strdup(name); + if (handler_ex->file_name == NULL) + goto ERROR; handler->stream = fp; handler->apply_color = false; handler->_free = __freeFileHandler; handler->output = outputFileHandler; - return handler; + +ERROR: + if (fp) + fclose(fp); + if (handler) { + free(Handler_file_EX_PRT(handler)->file_name); // 直接释放,无需检查NULL + free(handler); + } + return NULL; } \ No newline at end of file diff --git a/src/logging.c b/src/logging.c index 6b7c455..55571b7 100644 --- a/src/logging.c +++ b/src/logging.c @@ -1,5 +1,7 @@ #include "logging.h" #include "logging/logging-handler.h" +#include "utils/logging-utils.h" +#include #include #include #include @@ -17,42 +19,46 @@ Logger *G_LOGGER = NULL; -static void getTimeStr(char *timeStr) { - time_t t = time(NULL); - struct tm *p = localtime(&t); - char _timeStr[20]; - strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p); - strcpy(timeStr, _timeStr); -} - -static void addHandler(log_Handler *handler) { - if (G_LOGGER == NULL) { - return; +/** + * @brief 为日志添加一个handler + * @param handler 处理器对象 + */ +static bool addHandler(log_Handler *handler) { + if (G_LOGGER == NULL || handler == NULL) { + return false; } if (G_LOGGER->handler == NULL) { G_LOGGER->handler = handler; - return; + return true; } G_LOGGER->handler->_free(G_LOGGER->handler); - G_LOGGER->handler = handler; + return true; } -void addInterceptor(log_Interceptor *Interceptor) { - if (G_LOGGER == NULL) { - return; +static bool addInterceptor(log_Interceptor *Interceptor) { + if (G_LOGGER == NULL || Interceptor == NULL) { + return false; } if (G_LOGGER->interceptor == NULL) { G_LOGGER->interceptor = Interceptor; - return; + return true; } G_LOGGER->interceptor->_free(G_LOGGER->interceptor); - G_LOGGER->interceptor = Interceptor; + return true; } +/** + * @brief 内部日志打印处理核心函数 + * @param level 日志等级 + * @param color 应用的颜色 + * @param message 日志内容 + * @param ... 格式化参数列表 + * @return + */ static void _builtin_log(char *level, const char *color, const char *message, ...) { if (G_LOGGER == NULL) { @@ -77,7 +83,7 @@ _builtin_log(char *level, const char *color, const char *message, ...) { if (handler->apply_color) sprintf(logStr, - "%s: %s %s%s%s %s\n", + "[%s]: %s %s%s%s %s\n", G_LOGGER->name, timeStr, color, @@ -85,8 +91,12 @@ _builtin_log(char *level, const char *color, const char *message, ...) { RESET, message); else - sprintf( - logStr, "%s: %s %s %s\n", G_LOGGER->name, timeStr, level, message); + sprintf(logStr, + "[%s]: %s %s %s\n", + G_LOGGER->name, + timeStr, + level, + message); handler->output(handler, logStr); } @@ -146,7 +156,7 @@ static void debug(const char *message, ...) { } } -static Logger *getLogger(const char *name, log_level level) { +Logger *newLogger(const char *name, log_level level) { if (G_LOGGER != NULL) { G_LOGGER->name = name; G_LOGGER->level = level; @@ -174,12 +184,9 @@ static Logger *getLogger(const char *name, log_level level) { } /** - * @description :销毁日志对象 + * @brief 销毁日志对象 */ -log_status destroyLogging(Logging *logging) { - if (logging == NULL) { - return L_ERROR; - } +log_status destroyLogger(void) { if (G_LOGGER != NULL) { if (G_LOGGER->handler != NULL) { G_LOGGER->handler->_free(G_LOGGER->handler); @@ -192,21 +199,12 @@ log_status destroyLogging(Logging *logging) { free(G_LOGGER); G_LOGGER = NULL; } - free(logging); return L_OK; } -Logger *getCurrentLogger(void) { +Logger *getDefaultLogger(void) { if (G_LOGGER == NULL) { return NULL; } return G_LOGGER; -} - -Logging *newLogging() { - Logging *logging = (Logging *)malloc(sizeof(Logging)); - logging->getLogger = getLogger; - logging->destroyLogging = destroyLogging; - logging->getCurrentLogger = getCurrentLogger; - return logging; } \ No newline at end of file diff --git a/src/utils/logging-utils.c b/src/utils/logging-utils.c new file mode 100644 index 0000000..e9480d2 --- /dev/null +++ b/src/utils/logging-utils.c @@ -0,0 +1,15 @@ +#include "logging-utils.h" +#include +#include + +/** +* @brief 获取当前时间字符串 +* @param timeStr 存储时间字符串缓冲区指针 +*/ +void getTimeStr(char *timeStr) { + time_t t = time(NULL); + struct tm *p = localtime(&t); + char _timeStr[20]; + strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p); + strcpy(timeStr, _timeStr); +} \ No newline at end of file diff --git a/src/utils/logging-utils.h b/src/utils/logging-utils.h new file mode 100644 index 0000000..e187bb6 --- /dev/null +++ b/src/utils/logging-utils.h @@ -0,0 +1,5 @@ +#ifndef __LOGGING_UTILS_H__ +#define __LOGGING_UTILS_H__ + +void getTimeStr(char *timeStr); +#endif // __LOGGING_UTILS_H__ \ No newline at end of file diff --git a/tests/test_interceptor.c b/tests/test_interceptor.c index 08889b3..986d574 100644 --- a/tests/test_interceptor.c +++ b/tests/test_interceptor.c @@ -2,8 +2,7 @@ #include int main() { - Logging *log = newLogging(); - Logger *logger = log->getLogger("testLogger", LOG_DEBUG); + Logger *logger = newLogger("testLogger", LOG_DEBUG); logger->info("This is an info message"); logger->error("This is an error message%s", "123"); @@ -11,10 +10,13 @@ int main() { logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - char *test1[] = {"123", "tt"}; + char *test1[] = {"123", "tt"}; - log_Interceptor *tint = - loggingSubStringInterceptor(test1, 2, LOG_DEBUG, loggingFileHandler("test_interceptor")); + log_Interceptor *tint = loggingSubStringInterceptor( + test1, + 2, + LOG_DEBUG, + loggingFileHandler("test_interceptor", 1024 * 1024)); logger->addInterceptor(tint); @@ -28,6 +30,6 @@ int main() { logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - log->destroyLogging(log); + destroyLogger(); return 0; } \ No newline at end of file diff --git a/tests/test_simple.c b/tests/test_simple.c index 9abc796..d803794 100644 --- a/tests/test_simple.c +++ b/tests/test_simple.c @@ -1,8 +1,7 @@ #include "logging.h" int main() { - Logging *log = newLogging(); - Logger *logger = log->getLogger("testLogger", LOG_DEBUG); + Logger *logger = newLogger("testLogger", LOG_DEBUG); logger->info("This is an info message"); logger->error("This is an error message%s", "123"); @@ -10,6 +9,6 @@ int main() { logger->debug("This is a debug message"); logger->warning("This is a warning message%s", "123"); - log->destroyLogging(log); + destroyLogger(); return 0; } \ No newline at end of file From f4494515ca200cbb42d565c0a0779eb67377f411 Mon Sep 17 00:00:00 2001 From: youmetme <103353084+WangZhongDian@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:13:57 +0800 Subject: [PATCH 2/2] Add English brief (#12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #feat 增强Fatal级别的底色,修改logging类的方法 * 更新版本号 * 加入test脚本 * fix:conanfile * test action * 修复错别字 * add test on windows action * fix test on windows action * fix action on windows * fix * fix 内存分配错误 * fix msvc 不支持中文注释,删除中文注释 * test on windows and test chinese char * ersion 0.2.4 * feature:根据文件大小分割日志 * fix:内存泄露 * fix:使用char偏移单位 * add english brief --- README.en.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 13 ++++++- 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 README.en.md diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..a35ec21 --- /dev/null +++ b/README.en.md @@ -0,0 +1,108 @@ +# C language logging library logging + +## brief + +Logging is a lightweight and easy-to-use C language log library that supports log level, log format, log output, log files, and other functions. + +## function +- Support log levels: DEBUG, INFO, Warning, ERROR, FATAL +- Support log formats: timestamp, log level, log content +- Support log output: console, file +- Support log files: automatic creation, automatic scrolling, log segmentation + +## install +- Conan +```shell +conan create . +``` +- cmake +```shell +``` + +## usage + +### console log +```c +#include "logging.h" + +int main() { + Logger *logger = newLogger("testLogger", LOG_DEBUG); + + logger->info("This is an info message"); + logger->error("This is an error message%s", "123"); + logger->fatal("This is an fatal message"); + logger->debug("This is a debug message"); + logger->warning("This is a warning message%s", "123"); + + destroyLogger(); + return 0; +} +``` + +### file log +```c +#include "logging.h" +#include "logging/logging-handler.h" + +int main() { + Logger *logger = newLogger("testLogger", LOG_DEBUG); + logger->addHandler(loggingFileHandler("test1", 1024*1024)); + + logger->info("This is an info message"); + logger->error("This is an error message%s", "123"); + logger->fatal("This is an fatal message"); + logger->debug("This is a debug message"); + logger->warning("This is a warning message%s", "123"); + + destroyLogger(); + return 0; +} +``` + +### Logging Interceptor +> Support adding custom interceptors, currently with built-in substring interceptors +> The function of an interceptor is to redirect intercepted logs to the interceptor's dedicated processor + + +#### example +Redirects intercepted logs to a dedicated file processor +```c +#include "logging.h" +#include + +int main() { + Logger *logger = newLogger("testLogger", LOG_DEBUG); + + logger->info("This is an info message"); + logger->error("This is an error message%s", "123"); + logger->fatal("This is an fatal message"); + logger->debug("This is a debug message"); + logger->warning("This is a warning message%s", "123"); + + char *test1[] = {"123", "tt"}; + + log_Interceptor *tint = loggingSubStringInterceptor( + test1, + 2, + LOG_DEBUG, + loggingFileHandler("test_interceptor", 1024 * 1024)); + + logger->addInterceptor(tint); + + printf("\n"); + printf("Interceptor added\n"); + printf("\n"); + + logger->info("This is an info message"); + logger->error("This is an error message%s", "123"); + logger->fatal("This is an fatal message"); + logger->debug("This is a debug message"); + logger->warning("This is a warning message%s", "123"); + + destroyLogger(); + return 0; +} +``` +![](docs/img/2024-09-21-11-44-25.png) +![](docs/img/2024-09-21-11-44-06.png) + diff --git a/README.md b/README.md index 34f0226..3fedfca 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # C语言日志库logging +[English](README.en.md) + ## 简介 logging是一个轻量级的简单易用C语言日志库,支持日志级别、日志格式、日志输出、日志文件等功能。 @@ -9,7 +11,16 @@ logging是一个轻量级的简单易用C语言日志库,支持日志级别、 - 支持日志级别:DEBUG、INFO、WARN、ERROR、FATAL - 支持日志格式:时间戳、日志级别、日志内容 - 支持日志输出:控制台、文件 -- 支持日志文件:自动创建、自动滚动、自动删除(未完成) +- 支持日志文件:自动创建、自动滚动、日志分割 + +## 安装 +- conan安装使用 +```shell +conan create . +``` +- cmake安装使用 +```shell +``` ## 安装 - conan安装使用