Compare commits
	
		
			66 Commits
		
	
	
		
			86cf4c4526
			...
			v1.0.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f587b62a26 | |||
| ca20d51edb | |||
| 5540a9169a | |||
| c5c625f50e | |||
| 9fce78a59e | |||
| 8ac539eb79 | |||
| 84a57ff0aa | |||
| ef62dc2075 | |||
| 359c9f247a | |||
| aecfbbb74a | |||
| b273fd86e8 | |||
| 8fef266119 | |||
| 6ff484fef8 | |||
| e04a960777 | |||
| b2eec437cd | |||
|  | 8e512563e4 | ||
| 3f5153b110 | |||
| 09dd534675 | |||
| 633e91f80b | |||
|  | 9d3a7bbb8d | ||
|  | fde26f4f42 | ||
| 214665ec91 | |||
|  | 064881c0ad | ||
| 942970336c | |||
| 1c09c41ea3 | |||
|  | f0c3a5d56a | ||
|  | 56e1ac52ff | ||
| 9b777e4862 | |||
|  | 0b749c8d1d | ||
| 5c24b070bb | |||
|  | cc53e07788 | ||
| 915c18640a | |||
|  | a4b4ad7452 | ||
|  | feca0ef8e3 | ||
| b9abf6c7d3 | |||
| 6ac7afd4c2 | |||
|  | f4494515ca | ||
| 7afc3d3b41 | |||
|  | d0bfc31563 | ||
|  | a6392e27ce | ||
| 8a57c43180 | |||
| e57f0fa02c | |||
| de03985fef | |||
|  | 650ce0dc3f | ||
|  | 81cebc7a18 | ||
| 41004e5735 | |||
| de141cbafc | |||
|  | 3ef229ed65 | ||
| 668f88f8af | |||
| 34f818196e | |||
| 78341d522c | |||
| 2ecdefa239 | |||
| be445cdfe7 | |||
| 24f7124dfb | |||
| 8eb324ad23 | |||
|  | b7f49188ad | ||
|  | 406dbc5a79 | ||
| 0fa6097bbf | |||
| f6e2c31c85 | |||
|  | d61f7b6fde | ||
|  | c7c6af7dcf | ||
| 0d78195e4e | |||
| 01273809da | |||
| 4213c38730 | |||
| 9963f68175 | |||
| 85ae9d3deb | 
							
								
								
									
										92
									
								
								.clang-tidy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								.clang-tidy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | --- | ||||||
|  | Checks: '-*, | ||||||
|  |         clang-analyzer-core.*, | ||||||
|  |         clang-analyzer-cplusplus.*, | ||||||
|  |         modernize-redundant-void-arg, | ||||||
|  |         modernize-use-bool-literals, | ||||||
|  |         modernize-use-equals-default, | ||||||
|  |         modernize-use-nullptr, | ||||||
|  |         modernize-use-override, | ||||||
|  |         google-explicit-constructor, | ||||||
|  |         google-readability-casting, | ||||||
|  |         readability-braces-around-statements, | ||||||
|  |         readability-identifier-naming.ClassCase, | ||||||
|  |         readability-identifier-naming.StructCase, | ||||||
|  |         readability-identifier-naming.TypedefCase, | ||||||
|  |         readability-identifier-naming.EnumCase, | ||||||
|  |         readability-non-const-parameter, | ||||||
|  |         cert-dcl21-cpp, | ||||||
|  |         bugprone-undelegated-constructor, | ||||||
|  |         bugprone-macro-parentheses, | ||||||
|  |         bugprone-macro-repeated-side-effects, | ||||||
|  |         bugprone-forward-declaration-namespace, | ||||||
|  |         bugprone-bool-pointer-implicit-conversion, | ||||||
|  |         bugprone-misplaced-widening-cast, | ||||||
|  |         cppcoreguidelines-narrowing-conversions, | ||||||
|  |         misc-unconventional-assign-operator, | ||||||
|  |         misc-unused-parameters' | ||||||
|  | WarningsAsErrors: '' | ||||||
|  | HeaderFilterRegex: '' | ||||||
|  | CheckOptions: | ||||||
|  |   # 现代化(Modernize) | ||||||
|  |   - key:             modernize-redundant-void-arg | ||||||
|  |     value:           'true'  # 检查并移除函数声明中冗余的 void 参数。 | ||||||
|  |   - key:             modernize-use-bool-literals | ||||||
|  |     value:           'true'  # 建议使用布尔字面量 true 和 false 代替整数值 0 和 1。 | ||||||
|  |   - key:             modernize-use-equals-default | ||||||
|  |     value:           'true'  # 建议在默认构造函数、复制构造函数和赋值运算符中使用 = default,以简化代码。 | ||||||
|  |   - key:             modernize-use-nullptr | ||||||
|  |     value:           'true'  # 建议使用 nullptr 代替 NULL 或 0 来表示空指针。 | ||||||
|  |   - key:             modernize-use-override | ||||||
|  |     value:           'true'  # 建议在覆盖基类虚函数时使用 override 关键字,以增加代码的清晰性和安全性。 | ||||||
|  |  | ||||||
|  |   # Google 代码风格(Google) | ||||||
|  |   - key:             google-explicit-constructor | ||||||
|  |     value:           'true'  # 检查并建议在单参数构造函数中使用 explicit 关键字,以防止隐式转换。 | ||||||
|  |   - key:             google-readability-casting | ||||||
|  |     value:           'true'  # 检查并建议使用 C++ 风格的类型转换(如 static_cast、dynamic_cast、const_cast 和 reinterpret_cast)代替 C 风格的类型转换。 | ||||||
|  |  | ||||||
|  |   # 可读性(Readability) | ||||||
|  |   - key:             readability-braces-around-statements | ||||||
|  |     value:           'true'  # 建议在单行语句周围添加大括号,以提高代码的可读性和一致性。 | ||||||
|  |   - key:             readability-identifier-naming.ClassCase | ||||||
|  |     value:           'CamelCase'  # 类名应使用 CamelCase 风格,例如 MyClassName。 | ||||||
|  |   - key:             readability-identifier-naming.StructCase | ||||||
|  |     value:           'CamelCase'  # 结构体名应使用 CamelCase 风格,例如 MyStructName。 | ||||||
|  |   - key:             readability-identifier-naming.TypedefCase | ||||||
|  |     value:           'CamelCase'  # 类型定义应使用 CamelCase 风格,例如 MyTypeDef。 | ||||||
|  |   - key:             readability-identifier-naming.EnumCase | ||||||
|  |     value:           'CamelCase'  # 枚举名应使用 CamelCase 风格,例如 MyEnumName。 | ||||||
|  |   - key:             readability-non-const-parameter | ||||||
|  |     value:           'true'  # 检查并标识非 const 参数,以提高代码的可读性和安全性。 | ||||||
|  |  | ||||||
|  |   # CERT 安全编码标准(CERT) | ||||||
|  |   - key:             cert-dcl21-cpp | ||||||
|  |     value:           'true'  # 检查并标识在头文件中不应包含无命名空间的 using 声明和指令,以防止命名空间污染。 | ||||||
|  |  | ||||||
|  |   # Bug 检测(Bugprone) | ||||||
|  |   - key:             bugprone-undelegated-constructor | ||||||
|  |     value:           'true'  # 检查并标识未委托的构造函数,以确保构造函数的正确性。 | ||||||
|  |   - key:             bugprone-macro-parentheses | ||||||
|  |     value:           'true'  # 检查并建议在宏定义中使用括号,以防止潜在的错误。 | ||||||
|  |   - key:             bugprone-macro-repeated-side-effects | ||||||
|  |     value:           'true'  # 检查并标识宏中重复的副作用,以防止潜在的错误。 | ||||||
|  |   - key:             bugprone-forward-declaration-namespace | ||||||
|  |     value:           'true'  # 检查并标识命名空间前向声明的潜在问题。 | ||||||
|  |   - key:             bugprone-bool-pointer-implicit-conversion | ||||||
|  |     value:           'true'  # 检查并标识布尔指针的隐式转换,以防止潜在的错误。 | ||||||
|  |   - key:             bugprone-misplaced-widening-cast | ||||||
|  |     value:           'true'  # 检查并标识错误的宽化转换,以防止潜在的错误。 | ||||||
|  |  | ||||||
|  |   # C++ 核心指南(CppCoreGuidelines) | ||||||
|  |   - key:             cppcoreguidelines-narrowing-conversions | ||||||
|  |     value:           'true'  # 检查并标识可能导致数据丢失的窄化转换。 | ||||||
|  |  | ||||||
|  |   # 杂项(Miscellaneous) | ||||||
|  |   - key:             misc-unconventional-assign-operator | ||||||
|  |     value:           'true'  # 检查并标识不常见的赋值操作符重载,以确保代码的一致性和可维护性。 | ||||||
|  |   - key:             misc-unused-parameters | ||||||
|  |     value:           'true'  # 检测未使用的参数。 | ||||||
|  | ... | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								.github/workflows/linux_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/linux_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | name: test on Linux | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |     push: | ||||||
|  |         branches: ["main"] | ||||||
|  |     pull_request:  | ||||||
|  |         branches: ["main"] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |     test: | ||||||
|  |         runs-on: ubuntu-latest | ||||||
|  |         steps: | ||||||
|  |             - name: checkout code | ||||||
|  |               uses: actions/checkout@v4 | ||||||
|  |             - name: test | ||||||
|  |               run: bash ./script/test.sh | ||||||
							
								
								
									
										17
									
								
								.github/workflows/windows_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/windows_test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | name: test on Windows | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |     push: | ||||||
|  |         branches: ["main","dev"] | ||||||
|  |  | ||||||
|  |     pull_request:  | ||||||
|  |         branches: ["main"] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |     test: | ||||||
|  |         runs-on: windows-latest | ||||||
|  |         steps: | ||||||
|  |             - name: checkout code | ||||||
|  |               uses: actions/checkout@v4 | ||||||
|  |             - name: test | ||||||
|  |               run: ./script/test_windows.ps1 | ||||||
							
								
								
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | 3.12 | ||||||
| @@ -1,9 +1,19 @@ | |||||||
| cmake_minimum_required( VERSION 3.28) | cmake_minimum_required(VERSION 3.28...3.30) | ||||||
|  |  | ||||||
|  | project(logging) | ||||||
|  |  | ||||||
| set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) | set(CMAKE_C_STANDARD 99) | ||||||
| set(ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) | set(CMAKE_C_CLANG_TIDY "clang-tidy") | ||||||
| set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) |  | ||||||
|  | if(MSVC) | ||||||
|  |     add_compile_options("/source-charset:utf-8") | ||||||
|  |     add_compile_options("/execution-charset:utf-8") | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | set(CMAKE_EXPORT_COMPILE_COMMANDS yes) | ||||||
|  |  | ||||||
|  | option(TEST "是否启动单元测试" ON) | ||||||
|  | option(SHARED "是否编译为动态库" OFF) | ||||||
|  |  | ||||||
| include_directories(${CMAKE_SOURCE_DIR}/include) | include_directories(${CMAKE_SOURCE_DIR}/include) | ||||||
|  |  | ||||||
| @@ -11,7 +21,13 @@ include_directories(${CMAKE_SOURCE_DIR}/include) | |||||||
| add_subdirectory(src) | add_subdirectory(src) | ||||||
|  |  | ||||||
| #测试单元 | #测试单元 | ||||||
| if (SKIPTEST) | if (TEST) | ||||||
| else() |     enable_testing() | ||||||
|     add_subdirectory(tests) |     add_subdirectory(tests) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | install(FILES include/logging.h DESTINATION include) | ||||||
|  | install(FILES include/logging/logging-core.h DESTINATION include/logging) | ||||||
|  | install(FILES include/logging/logging-filter.h DESTINATION include/logging) | ||||||
|  | install(FILES include/logging/logging-handler.h DESTINATION include/logging) | ||||||
|   | |||||||
							
								
								
									
										120
									
								
								README.en.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								README.en.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | # 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 | ||||||
|  | git clone https://github.com/WangZhongDian/logging.git | ||||||
|  | cd logging | ||||||
|  | cmake build -B build . && cd build && cmake --build . | ||||||
|  | cmake --install . | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## usage | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### console log  | ||||||
|  | ```c | ||||||
|  | #include "logging.h" | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### file log | ||||||
|  | ```c | ||||||
|  | #include "logging.h" | ||||||
|  | #include "logging/logging-handler.h" | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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"); | ||||||
|  |  | ||||||
|  |     destroyDefaultLogger(); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Logging filter  | ||||||
|  | > 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 | ||||||
|  |  | ||||||
|  | #### Multiple substring filters | ||||||
|  | ```c | ||||||
|  | #include "logging.h" | ||||||
|  | #include "logging/logging-core.h" | ||||||
|  | #include "logging/logging-filter.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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}; | ||||||
|  |  | ||||||
|  |     log_filter *tint = | ||||||
|  |         loggingFilterSubStr(test1, | ||||||
|  |                             LOG_DEBUG, | ||||||
|  |                             loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||||
|  |                             false); | ||||||
|  |  | ||||||
|  |     addFilter(getDefaultLogger(), tint); | ||||||
|  |  | ||||||
|  |     char *test2[]     = {"123", NULL}; | ||||||
|  |  | ||||||
|  |     log_filter *tint1 = loggingFilterSubStr( | ||||||
|  |         test2, | ||||||
|  |         LOG_ERROR, | ||||||
|  |         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||||
|  |         true); | ||||||
|  |  | ||||||
|  |     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"); | ||||||
|  |  | ||||||
|  |     destroyDefaultLogger(); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
							
								
								
									
										134
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | |||||||
| # C语言日志库logging | # C语言日志库logging | ||||||
|  |  | ||||||
|  | [English](README.en.md) | ||||||
|  |  | ||||||
| ## 简介 | ## 简介 | ||||||
|  |  | ||||||
| logging是一个轻量级的简单易用C语言日志库,支持日志级别、日志格式、日志输出、日志文件等功能。 | logging是一个轻量级的简单易用C语言日志库,支持日志级别、日志格式、日志输出、日志文件等功能。 | ||||||
| @@ -9,25 +11,49 @@ logging是一个轻量级的简单易用C语言日志库,支持日志级别、 | |||||||
| - 支持日志级别:DEBUG、INFO、WARN、ERROR、FATAL | - 支持日志级别:DEBUG、INFO、WARN、ERROR、FATAL | ||||||
| - 支持日志格式:时间戳、日志级别、日志内容 | - 支持日志格式:时间戳、日志级别、日志内容 | ||||||
| - 支持日志输出:控制台、文件 | - 支持日志输出:控制台、文件 | ||||||
| - 支持日志文件:自动创建、自动滚动、自动删除(未完成) | - 支持日志文件:自动创建、自动滚动、日志分割 | ||||||
|  |  | ||||||
|  | ## 安装 | ||||||
|  | ### conan安装使用 | ||||||
|  | ```shell | ||||||
|  | git clone https://github.com/WangZhongDian/logging.git | ||||||
|  | cd logging | ||||||
|  | conan create .  | ||||||
|  | ``` | ||||||
|  | 在你的项目的conanfile.txt中添加 | ||||||
|  | ```txt | ||||||
|  | [requires] | ||||||
|  | logging/0.5.0 | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ```shell | ||||||
|  | conan install . --build=missing | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### cmake安装使用 | ||||||
|  | ```shell | ||||||
|  | git clone https://github.com/WangZhongDian/logging.git | ||||||
|  | cd logging | ||||||
|  | cmake build -B build . && cd build && cmake --build . | ||||||
|  | cmake --install . | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## 使用方法 | ## 使用方法 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ### 控制台日志 | ### 控制台日志 | ||||||
| ```c | ```c | ||||||
| #include "logging.h" | #include "logging.h" | ||||||
|  |  | ||||||
| int main() { | int main() { | ||||||
|     Logging *log    = newLogging(); |     Log_info("This is an info message"); | ||||||
|     Logger  *logger = log->getLogger("testLogger", LOG_DEBUG); |     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"); | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |     destroyDefaultLogger(); | ||||||
|     logger->error("你好,这是一个错误消息%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); |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| @@ -35,72 +61,76 @@ int main() { | |||||||
| ### 文件日志 | ### 文件日志 | ||||||
| ```c | ```c | ||||||
| #include "logging.h" | #include "logging.h" | ||||||
|  | #include "logging/logging-handler.h" | ||||||
|  |  | ||||||
| int main() { | int main() { | ||||||
|     Logging *log = newLogging(); |     log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); | ||||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); |     addHandler(getDefaultLogger(), hander); | ||||||
|  |  | ||||||
|     logger->addHandler(loggingFileHandler("test"));   //为日志对象添加文件处理器 |     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"); | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |     destroyDefaultLogger(); | ||||||
|     logger->error("你好,这是一个错误消息%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); |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### 日志拦截器 | ### 日志过滤器 | ||||||
| > 支持添加自定义的拦截器, 目前内置了子串拦截器 | > 支持添加自定义的过滤器, 目前内置了子串过滤器 | ||||||
|  |  | ||||||
| > 拦截器的作用:可以将拦截到的日志重定向到拦截器的专属处理器中 | > 过滤器的作用:可以将过滤到的日志重定向到过滤器的专属处理器中 | ||||||
|  |  | ||||||
|  | #### 多个子串过滤器 | ||||||
| #### 例子 |  | ||||||
| 将拦截到的日志重定向到专属文件处理器中 |  | ||||||
| ```c | ```c | ||||||
| #include "logging.h" | #include "logging.h" | ||||||
|  | #include "logging/logging-core.h" | ||||||
|  | #include "logging/logging-filter.h" | ||||||
|  | #include <stdbool.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
| int main() { | int main() { | ||||||
|     Logging *log    = newLogging(); |     Log_info("This is an info message"); | ||||||
|     Logger  *logger = log->getLogger("testLogger", LOG_DEBUG); |     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"); | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |     char *test1[] = {"This", NULL}; | ||||||
|     logger->error("你好,这是一个错误消息%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_filter *tint = | ||||||
|     // 添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中 |         loggingFilterSubStr(test1, | ||||||
|     log_Interceptor *tint = |                             LOG_DEBUG, | ||||||
|         loggingSubStringInterceptor(test1, 2, LOG_DEBUG, loggingFileHandler("被拦截")); |                             loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||||
|  |                             false); | ||||||
|  |  | ||||||
|     logger->addInterceptor(tint); |     addFilter(getDefaultLogger(), tint); | ||||||
|  |  | ||||||
|  |     char *test2[]     = {"123", NULL}; | ||||||
|  |  | ||||||
|  |     log_filter *tint1 = loggingFilterSubStr( | ||||||
|  |         test2, | ||||||
|  |         LOG_ERROR, | ||||||
|  |         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||||
|  |         true); | ||||||
|  |  | ||||||
|  |     addFilter(getDefaultLogger(), tint1); | ||||||
|  |  | ||||||
|     printf("\n"); |     printf("\n"); | ||||||
|     printf("Interceptor added\n"); |     printf("filter added\n"); | ||||||
|     printf("\n"); |     printf("\n"); | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |     Log_info("This is an info message"); | ||||||
|     logger->error("你好,这是一个错误消息%s", "123"); |     Log_error("This is an error message%s", "123"); | ||||||
|     logger->fatal("This is an fatal message"); |     Log_fatal("This is an fatal message"); | ||||||
|     logger->debug("This is a debug message"); |     Log_debug("This is a debug message"); | ||||||
|     logger->warning("This is a warning message%s", "123"); |     Log_warning("This is a warning message%s", "123"); | ||||||
|  |  | ||||||
|     log->destroyLogging(log); |     destroyDefaultLogger(); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # build |  | ||||||
| ```shell |  | ||||||
| conan create . --build=missing |  | ||||||
| ``` |  | ||||||
							
								
								
									
										29
									
								
								conanfile.py
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								conanfile.py
									
									
									
									
									
								
							| @@ -1,14 +1,11 @@ | |||||||
| from conan import ConanFile | from conan import ConanFile | ||||||
| from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout | from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout | ||||||
| from conan.tools.files import copy, get | from conan.tools.files import copy | ||||||
| from conan.tools.build import check_min_cppstd |  | ||||||
| from conan import tools |  | ||||||
| import os | import os | ||||||
|  |  | ||||||
|  |  | ||||||
| class loggingRecipe(ConanFile): | class loggingRecipe(ConanFile): | ||||||
|     name = "logging" |     name = "logging" | ||||||
|     version = "0.2.3" |     version = "1.0.0" | ||||||
|     license = "MIT" |     license = "MIT" | ||||||
|     author = "321640253@qq.com" |     author = "321640253@qq.com" | ||||||
|     url = "https://github.com/WangZhongDian/logging.git" |     url = "https://github.com/WangZhongDian/logging.git" | ||||||
| @@ -16,11 +13,11 @@ class loggingRecipe(ConanFile): | |||||||
|     topics = ("logging", "C", "simple", "easy-to-use", "log","Logging") |     topics = ("logging", "C", "simple", "easy-to-use", "log","Logging") | ||||||
|  |  | ||||||
|     settings = "os", "compiler", "build_type", "arch" |     settings = "os", "compiler", "build_type", "arch" | ||||||
|     options = {"shared": [True, False], "fPIC": [True, False]} |     options = {"shared": [True, False], "fPIC": [True, False],"test":[True,False]} | ||||||
|     default_options = {"shared": False, "fPIC": True} |     default_options = {"shared": False, "fPIC": True,"test":True} | ||||||
|  |  | ||||||
|  |  | ||||||
|     exports_sources = "include/*", "CMakeLists.txt", "src/*" |     exports_sources = "include/*", "CMakeLists.txt", "src/*", "tests/*" | ||||||
|  |  | ||||||
|     def config_options(self): |     def config_options(self): | ||||||
|         if self.settings.os == "Windows": |         if self.settings.os == "Windows": | ||||||
| @@ -30,8 +27,6 @@ class loggingRecipe(ConanFile): | |||||||
|         if self.options.shared: |         if self.options.shared: | ||||||
|             self.options.rm_safe("fPIC") |             self.options.rm_safe("fPIC") | ||||||
|  |  | ||||||
|  |  | ||||||
|      |  | ||||||
|     def layout(self): |     def layout(self): | ||||||
|         cmake_layout(self) |         cmake_layout(self) | ||||||
|  |  | ||||||
| @@ -39,18 +34,16 @@ class loggingRecipe(ConanFile): | |||||||
|         deps = CMakeDeps(self) |         deps = CMakeDeps(self) | ||||||
|         deps.generate() |         deps.generate() | ||||||
|         tc = CMakeToolchain(self) |         tc = CMakeToolchain(self) | ||||||
|         tc.variables["SKIPTEST"]=True |         tc.variables["TEST"] = True if self.options.test else False | ||||||
|         if self.options.shared: |         tc.variables["SHARED"] = True if self.options.shared else False | ||||||
|             tc.variables["SHARED"] = True |  | ||||||
|         else: |  | ||||||
|             tc.variables["SHARED"] = False |  | ||||||
|         tc.generate() |         tc.generate() | ||||||
|  |  | ||||||
|     def build(self): |     def build(self): | ||||||
|         cmake = CMake(self) |         cmake = CMake(self) | ||||||
|         cmake.configure() |         cmake.configure() | ||||||
|         cmake.build(target="Logging") |         cmake.build() | ||||||
|  |         if self.options.test: | ||||||
|  |             cmake.test() | ||||||
|  |  | ||||||
|     def package(self): |     def package(self): | ||||||
|         copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) |         copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) | ||||||
| @@ -62,4 +55,4 @@ class loggingRecipe(ConanFile): | |||||||
|         copy(self, pattern="*.dylib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) |         copy(self, pattern="*.dylib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) | ||||||
|  |  | ||||||
|     def package_info(self): |     def package_info(self): | ||||||
|         self.cpp_info.libs = ["Logging"] |         self.cpp_info.libs = ["logging"] | ||||||
|   | |||||||
| @@ -3,35 +3,85 @@ | |||||||
|  |  | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
|  |  | ||||||
| #include "logging/logging-core.h" | #include "logging/logging-core.h" | ||||||
|  | #include "logging/logging-filter.h" | ||||||
| #include "logging/logging-handler.h" | #include "logging/logging-handler.h" | ||||||
| #include "logging/logging-interceptor.h" |  | ||||||
|  |  | ||||||
| // 日志操作器 | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // 默认日志器宏 | ||||||
|  | #define Log_fatal(format, ...)                                                 \ | ||||||
|  |     logMessage(NULL, LOG_FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__) | ||||||
|  | #define Log_error(format, ...)                                                 \ | ||||||
|  |     logMessage(NULL, LOG_ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__) | ||||||
|  | #define Log_warning(format, ...)                                               \ | ||||||
|  |     logMessage(NULL, LOG_WARNING, __FILE__, __LINE__, format, ##__VA_ARGS__) | ||||||
|  | #define Log_info(format, ...)                                                  \ | ||||||
|  |     logMessage(NULL, LOG_INFO, __FILE__, __LINE__, format, ##__VA_ARGS__) | ||||||
|  | #define Log_debug(format, ...)                                                 \ | ||||||
|  |     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 { | typedef struct Logger { | ||||||
|     log_level    level; |     log_level    level; | ||||||
|     log_Handler *handler; |     log_Handler *handler; | ||||||
|     log_Interceptor *interceptor; |     log_filter  *filter; | ||||||
|     const char  *name; |     const char  *name; | ||||||
|     void (*fatal)(const char *format, ...); |  | ||||||
|     void (*error)(const char *format, ...); |  | ||||||
|     void (*warning)(const char *format, ...); |  | ||||||
|     void (*info)(const char *format, ...); |  | ||||||
|     void (*debug)(const char *format, ...); |  | ||||||
|  |  | ||||||
|     void (*addHandler)(log_Handler *handler); |  | ||||||
|     void (*addInterceptor)(log_Interceptor *Interceptor); |  | ||||||
| } Logger; | } Logger; | ||||||
|  |  | ||||||
| // 日志类对象 | bool addHandler(Logger *logger, log_Handler *handler); | ||||||
| typedef struct Logging { | bool addFilter(Logger *logger, log_filter *filter); | ||||||
|     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(); // 创建日志类对象 | void logMessage(Logger     *logger, | ||||||
|  |                 log_level   level, | ||||||
|  |                 const char *file, | ||||||
|  |                 int         line, | ||||||
|  |                 const char *message, | ||||||
|  |                 ...); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 创建一个日志句柄对象 | ||||||
|  |  * @param name 日志器名称 | ||||||
|  |  * @return 日志句柄对象 | ||||||
|  |  */ | ||||||
|  | Logger *newLogger(const char *name); | ||||||
|  | /** | ||||||
|  |  * @brief 获取默认日志对象 | ||||||
|  |  * @return 默认日志对象 | ||||||
|  |  */ | ||||||
|  | Logger *getDefaultLogger(void); | ||||||
|  |  | ||||||
|  | Logger *getLogger(const char *name); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 销毁日志对象,该方法会销毁默认日志对象 | ||||||
|  |  */ | ||||||
|  | void destroyDefaultLogger(void); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 销毁日志对象 | ||||||
|  |  * @param logger 日志对象 | ||||||
|  |  * @return void | ||||||
|  |  */ | ||||||
|  | void destroyLogger(Logger *logger); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif // __LOGGING_H__ | #endif // __LOGGING_H__ | ||||||
| @@ -1,18 +1,33 @@ | |||||||
| #ifndef __LOGGING_CORE_H__ | #ifndef __LOGGING_CORE_H__ | ||||||
| #define __LOGGING_CORE_H__ | #define __LOGGING_CORE_H__ | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     LOG_FATAL, |     LOG_FATAL = 0, | ||||||
|     LOG_ERROR, |     LOG_ERROR, | ||||||
|     LOG_WARNING, |     LOG_WARNING, | ||||||
|     LOG_INFO, |     LOG_INFO, | ||||||
|     LOG_DEBUG, |     LOG_DEBUG, | ||||||
| } log_level; | } log_level; | ||||||
|  |  | ||||||
|  | static const char *LOG_LEVEL_STR[] = { | ||||||
|  |     "FATAL", | ||||||
|  |     "ERROR", | ||||||
|  |     "WARNING", | ||||||
|  |     "INFO", | ||||||
|  |     "DEBUG", | ||||||
|  | }; | ||||||
|  |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     L_ERROR, |     L_ERROR, | ||||||
|     L_OK, |     L_OK, | ||||||
| } log_status; | } log_status; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif // __LOGGING_CORE_H__ | #endif // __LOGGING_CORE_H__ | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								include/logging/logging-filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/logging/logging-filter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #ifndef __LOGGING_INTERCEPTOR_H__ | ||||||
|  | #define __LOGGING_INTERCEPTOR_H__ | ||||||
|  |  | ||||||
|  | #include "logging-core.h" | ||||||
|  | #include "logging-handler.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef struct log_filter { | ||||||
|  |     log_level    level; | ||||||
|  |     log_Handler *handler; | ||||||
|  |     bool         jump_out; | ||||||
|  |     bool (*_dispose)(struct log_filter *filter, | ||||||
|  |                      log_level          level, | ||||||
|  |                      const char        *message, | ||||||
|  |                      ...); | ||||||
|  |     void (*_free)(struct log_filter *filter); | ||||||
|  |     struct log_filter *next; | ||||||
|  | } log_filter; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief  子字符串过滤器 | ||||||
|  |  * @param keywords: 关键字数组 | ||||||
|  |  * @param count: 关键字数组长度 | ||||||
|  |  * @param level: 过滤截日志等级 | ||||||
|  |  * @param handler: 日志处理器,用于处理过滤下来的日志 | ||||||
|  |  * @return log_filter * | ||||||
|  |  */ | ||||||
|  | log_filter *loggingFilterSubStr(char        *keywords[], | ||||||
|  |                                 log_level    level, | ||||||
|  |                                 log_Handler *handler, | ||||||
|  |                                 bool         jump_out); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // __LOGGING_INTERCEPTOR_H__ | ||||||
| @@ -3,15 +3,34 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
| typedef struct log_Handler { | typedef struct log_Handler { | ||||||
|     void* stream; |     void *stream; | ||||||
|     bool  apply_color; |     bool  apply_color; | ||||||
|     void (*_free)(struct log_Handler* handler);//释放资源 |     void (*_free)(struct log_Handler *handler); | ||||||
|     void (*output)(struct log_Handler* handler,const char* message); |     void (*output)(struct log_Handler *handler, const char *message); | ||||||
| } log_Handler; | } log_Handler; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 文件处理器 | ||||||
|  |  * @param file_name 文件名 | ||||||
|  |  * @param max_size 文件最大大小 | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | log_Handler *loggingHandlerFile(const char *file_name, unsigned int max_size); | ||||||
|  |  | ||||||
| log_Handler* loggingFileHandler(const char* name);      | /** | ||||||
| log_Handler* loggingConsoleHandler(); |  * @brief 控制台处理器 | ||||||
|  |  * @param | ||||||
|  |  * @return | ||||||
|  |  */ | ||||||
|  | log_Handler *loggingHandlerConsole(); | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif //__LOGGING_HANDLER_H__ | #endif //__LOGGING_HANDLER_H__ | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| #ifndef __LOGGING_INTERCEPTOR_H__ |  | ||||||
| #define __LOGGING_INTERCEPTOR_H__ |  | ||||||
|  |  | ||||||
| #include "logging-core.h" |  | ||||||
| #include "logging-handler.h" |  | ||||||
|  |  | ||||||
| typedef struct log_Interceptor { |  | ||||||
|     log_level    level;   // 拦截级别 |  | ||||||
|     log_Handler *handler; // 拦截目标处理器 |  | ||||||
|     bool (*_dispose)(char *level, const char *message, ...); // 拦截触发器 |  | ||||||
|     void (*_free)(struct log_Interceptor *Interceptor);      // 释放资源 |  | ||||||
|  |  | ||||||
| } log_Interceptor; |  | ||||||
|  |  | ||||||
| log_Interceptor *loggingSubStringInterceptor(char        *keywords[], |  | ||||||
|                                              int          count, |  | ||||||
|                                              log_level    level, |  | ||||||
|                                              log_Handler *handler); |  | ||||||
|  |  | ||||||
| #endif // __LOGGING_INTERCEPTOR_H__ |  | ||||||
							
								
								
									
										16
									
								
								makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
|  | .PHONY:format | ||||||
|  |  | ||||||
|  | format: | ||||||
|  | 	bash script/format.sh | ||||||
|  |  | ||||||
|  | build: | ||||||
|  | 	cmake -S . -B build | ||||||
|  | 	cmake --build build | ||||||
|  |  | ||||||
|  | test: build | ||||||
|  | 	cd build && ctest | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	rm -rf build | ||||||
							
								
								
									
										9
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | [project] | ||||||
|  | name = "logging" | ||||||
|  | version = "1.0.0" | ||||||
|  | description = "Add your description here" | ||||||
|  | readme = "README.md" | ||||||
|  | requires-python = ">=3.12" | ||||||
|  | dependencies = [ | ||||||
|  |     "conan>=2.18.1", | ||||||
|  | ] | ||||||
							
								
								
									
										3
									
								
								script/format.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								script/format.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | # Run clang-format on all C/C++ files in this directory and below. | ||||||
|  | find . -name "*.c" -o -name "*.h" -exec clang-format -style=file -i {} + | ||||||
							
								
								
									
										2
									
								
								script/test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								script/test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | cmake build -B build . && cd build && cmake --build . && ctest | ||||||
							
								
								
									
										5
									
								
								script/test_windows.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								script/test_windows.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | cmake build -B build .  | ||||||
|  | Set-Location -Path "./build" | ||||||
|  | cmake --build . | ||||||
|  | ctest | ||||||
|  | Set-Location -Path ".." | ||||||
| @@ -1,8 +1,9 @@ | |||||||
| project(Logging) | project(logging) | ||||||
|  |  | ||||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) | ||||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/handler 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}/filter SRC) | ||||||
|  | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils SRC) | ||||||
|  |  | ||||||
| if (SHARED) | if (SHARED) | ||||||
|     add_library(${PROJECT_NAME} SHARED ${SRC}) |     add_library(${PROJECT_NAME} SHARED ${SRC}) | ||||||
| @@ -10,3 +11,4 @@ else() | |||||||
|     add_library(${PROJECT_NAME} ${SRC}) |     add_library(${PROJECT_NAME} ${SRC}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib) | ||||||
							
								
								
									
										139
									
								
								src/filter/logging-filter-substr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/filter/logging-filter-substr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | #include "logging/logging-filter.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | typedef struct keywords_s { | ||||||
|  |     char              *key; | ||||||
|  |     struct keywords_s *next; | ||||||
|  | } keywords_t; | ||||||
|  |  | ||||||
|  | static void get_next(char *str, int *next) { | ||||||
|  |     next[1] = 0; | ||||||
|  |     int i   = 1; | ||||||
|  |     int j   = 0; | ||||||
|  |     while (i < strlen(str)) { | ||||||
|  |         if (j == 0 || str[i] == str[j]) { | ||||||
|  |             next[++i] = ++j; | ||||||
|  |         } else { | ||||||
|  |             j = next[j]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool kmp_search(char *substr, char *master) { | ||||||
|  |     if (substr == NULL) { | ||||||
|  |         return true; // 空串全匹配 | ||||||
|  |     } | ||||||
|  |     if (master == NULL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     int    i         = 0; | ||||||
|  |     int    j         = 0; | ||||||
|  |     size_t substrlen = strlen(substr); | ||||||
|  |     size_t masterlen = strlen(master); | ||||||
|  |     int   *next      = (int *)malloc(sizeof(int) * (substrlen + 1)); | ||||||
|  |     get_next(substr, next); | ||||||
|  |  | ||||||
|  |     while (i < masterlen && j < substrlen) { | ||||||
|  |         if (master[i] == substr[j]) { | ||||||
|  |             i++; | ||||||
|  |             j++; | ||||||
|  |         } else { | ||||||
|  |             if (j == 0) { | ||||||
|  |                 i++; | ||||||
|  |             } else { | ||||||
|  |                 j = next[j]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     free(next); | ||||||
|  |     if (j == substrlen) { | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool _disposeSubstring(log_filter *filter, | ||||||
|  |                               log_level   level, | ||||||
|  |                               const char *message, | ||||||
|  |                               ...) { | ||||||
|  |     int         count   = 0; | ||||||
|  |     keywords_t *keyword = (keywords_t *)(filter + 1); | ||||||
|  |  | ||||||
|  |     if (keyword->key == NULL && keyword->next == NULL) { | ||||||
|  |         if (level <= filter->level) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     while (keyword != NULL && level <= filter->level) { | ||||||
|  |         if (kmp_search(keyword->key, (char *)message)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         keyword = keyword->next; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void _freeFilter(log_filter *filter) { | ||||||
|  |     keywords_t *it_keyword = | ||||||
|  |         (keywords_t *)(filter + 1); // it_keyword 不是起始地址,请勿free | ||||||
|  |     keywords_t *keyword = it_keyword->next; | ||||||
|  |     keywords_t *next    = NULL; | ||||||
|  |  | ||||||
|  |     while (keyword != NULL) { | ||||||
|  |         next = keyword->next; | ||||||
|  |         free(keyword->key); | ||||||
|  |         free(keyword); | ||||||
|  |         keyword = next; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (filter->handler != NULL) { | ||||||
|  |         filter->handler->_free(filter->handler); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (it_keyword->key != NULL) { | ||||||
|  |         free(it_keyword->key); | ||||||
|  |     } | ||||||
|  |     free(filter); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | log_filter *loggingFilterSubStr(char        *keywords[], | ||||||
|  |                                 log_level    level, | ||||||
|  |                                 log_Handler *handler, | ||||||
|  |                                 bool         jump_out) { | ||||||
|  |     // 分配log_filter和keywords_t的连续内存 | ||||||
|  |     log_filter *filter = | ||||||
|  |         (log_filter *)malloc(sizeof(log_filter) + sizeof(keywords_t)); | ||||||
|  |     filter->_dispose    = _disposeSubstring; | ||||||
|  |     filter->handler     = handler; | ||||||
|  |     filter->level       = level; | ||||||
|  |     filter->jump_out    = jump_out; | ||||||
|  |     filter->_free       = _freeFilter; | ||||||
|  |  | ||||||
|  |     keywords_t *keyword = (keywords_t *)(filter + 1); | ||||||
|  |     keyword->key        = NULL; | ||||||
|  |     int count           = 0; | ||||||
|  |     if (keywords[count] != NULL) { | ||||||
|  |         keyword->key = strdup(keywords[count]); | ||||||
|  |         count++; | ||||||
|  |         keyword->next = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     while (keywords[count] != NULL) { | ||||||
|  |         keyword->next = (keywords_t *)malloc(sizeof(keywords_t)); | ||||||
|  |         keyword       = keyword->next; | ||||||
|  |         keyword->key  = strdup(keywords[count]); | ||||||
|  |         count++; | ||||||
|  |     } | ||||||
|  |     keyword->next = NULL; | ||||||
|  |  | ||||||
|  |     return filter; | ||||||
|  | } | ||||||
| @@ -1,36 +1,20 @@ | |||||||
| /******************************************** |  | ||||||
|  * @Date: 2024 09 18 |  | ||||||
|  * @Description: 控制台日志处理器 |  | ||||||
|  ********************************************/ |  | ||||||
| #include "logging/logging-handler.h" | #include "logging/logging-handler.h" | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
| /** | static void __freeHandlerConsole(log_Handler *handler) { free(handler); } | ||||||
|  * @brief 释放组件 |  | ||||||
|  * @param handler 处理器 |  | ||||||
|  */ |  | ||||||
| static void __freeConsoleHandler(log_Handler *handler) { free(handler); } |  | ||||||
|  |  | ||||||
| /** | static void __outputHandlerConsole(log_Handler *handler, const char *message) { | ||||||
|  * @brief 输出组件 |  | ||||||
|  * @param handler 处理器 |  | ||||||
|  * @param message 消息 |  | ||||||
|  */ |  | ||||||
| static void outputConsoleHandler(log_Handler *handler, const char *message) { |  | ||||||
|     fputs(message, handler->stream); |     fputs(message, handler->stream); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | log_Handler *loggingHandlerConsole() { | ||||||
|  * @brief :控制台日志处理器 |  | ||||||
|  */ |  | ||||||
| log_Handler *loggingConsoleHandler() { |  | ||||||
|     log_Handler *handler = (log_Handler *)malloc(sizeof(log_Handler)); |     log_Handler *handler = (log_Handler *)malloc(sizeof(log_Handler)); | ||||||
|  |  | ||||||
|     handler->stream      = stdout; |     handler->stream      = stdout; | ||||||
|     handler->apply_color = true; |     handler->apply_color = true; | ||||||
|     handler->_free       = __freeConsoleHandler; |     handler->_free       = __freeHandlerConsole; | ||||||
|     handler->output      = outputConsoleHandler; |     handler->output      = __outputHandlerConsole; | ||||||
|  |  | ||||||
|     return handler; |     return handler; | ||||||
| } | } | ||||||
| @@ -1,45 +1,103 @@ | |||||||
| /******************************************** |  | ||||||
|  * @Date: 2024 09 18 |  | ||||||
|  * @Description: 文件日志处理器 |  | ||||||
|  ********************************************/ |  | ||||||
| #include "logging/logging-handler.h" | #include "logging/logging-handler.h" | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | // 根据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); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @brief 文件日志处理器释放组件 |  | ||||||
|  */ |  | ||||||
| static void __freeFileHandler(log_Handler *handler) { | static void __freeFileHandler(log_Handler *handler) { | ||||||
|     fclose(handler->stream); |     fclose(handler->stream); | ||||||
|  |     free(Handler_file_EX_PRT(handler)->file_name); | ||||||
|     free(handler); |     free(handler); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | static void changeFile(log_Handler *handler) { | ||||||
|  * @brief 文件日志处理器输出组件 |     log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); | ||||||
|  * @param handler 文件日志处理器 |     fclose(handler->stream); | ||||||
|  * @param message 消息 |     char new_file_name[FILE_NAME_MAX_SIZE]; | ||||||
|  */ |     sprintf(new_file_name, | ||||||
| static void outputFileHandler(log_Handler *handler, const char *message) { |             "%s_%d.log", | ||||||
|     fputs(message, handler->stream); |             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) { | ||||||
|  * @brief 文件日志处理器 |     fputs(message, handler->stream); | ||||||
|  * @param   name 文件名 |     log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); | ||||||
|  * @return  log_Handler * |     handler_ex->file_size += strlen(message); | ||||||
|  */ |     if (handler_ex->file_size > handler_ex->file_size_max) { | ||||||
| log_Handler *loggingFileHandler(const char *name) { |         changeFile(handler); | ||||||
|     char new_file_name[100]; | } | ||||||
|     sprintf(new_file_name, "%s.log", name); | } | ||||||
|  |  | ||||||
|     FILE *fp             = fopen(new_file_name, "at"); | log_Handler *loggingHandlerFile(const char *file_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; | ||||||
|  |  | ||||||
|     log_Handler *handler = (log_Handler *)malloc(sizeof(log_Handler)); |     /// 获取未写满于设置最大文件大小的文件名 | ||||||
|  |     do { | ||||||
|  |         sprintf(new_file_name, "%s_%d.log", file_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) + | ||||||
|  |                                     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(file_name); | ||||||
|  |     if (handler_ex->file_name == NULL) { | ||||||
|  |         goto ERROR; | ||||||
|  | } | ||||||
|  |  | ||||||
|     handler->stream      = fp; |     handler->stream      = fp; | ||||||
|     handler->apply_color = false; |     handler->apply_color = false; | ||||||
|     handler->_free       = __freeFileHandler; |     handler->_free       = __freeFileHandler; | ||||||
|     handler->output      = outputFileHandler; |     handler->output      = outputFileHandler; | ||||||
|  |  | ||||||
|     return handler; |     return handler; | ||||||
|  |  | ||||||
|  | ERROR: | ||||||
|  |     if (fp) { | ||||||
|  |         fclose(fp); | ||||||
|  | } | ||||||
|  |     if (handler) { | ||||||
|  |         free(Handler_file_EX_PRT(handler)->file_name); // 直接释放,无需检查NULL | ||||||
|  |         free(handler); | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
| } | } | ||||||
| @@ -1,122 +0,0 @@ | |||||||
| /******************************************** |  | ||||||
|  * @Date: 2024 08 12 |  | ||||||
|  * @Description: 子串拦截器 |  | ||||||
|  *********************************************/ |  | ||||||
|  |  | ||||||
| #include "logging/logging-interceptor.h" |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| static log_Interceptor *G_interceptor = NULL; |  | ||||||
|  |  | ||||||
| static char **G_keywords              = NULL; |  | ||||||
|  |  | ||||||
| static void get_next(char *str, int *next) { |  | ||||||
|     next[1] = 0; |  | ||||||
|     int i   = 1; |  | ||||||
|     int j   = 0; |  | ||||||
|     while (i < strlen(str)) { |  | ||||||
|         if (j == 0 || str[i] == str[j]) { |  | ||||||
|             next[++i] = ++j; |  | ||||||
|         } else { |  | ||||||
|             j = next[j]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static bool kmp_search(char *substr, char *master) { |  | ||||||
|     int  i         = 0; |  | ||||||
|     int  j         = 0; |  | ||||||
|     int  substrlen = strlen(substr); |  | ||||||
|     int  masterlen = strlen(master); |  | ||||||
|     int *next      = (int *)malloc(sizeof(int) * substrlen + 1); |  | ||||||
|     get_next(substr, next); |  | ||||||
|  |  | ||||||
|     while (i < masterlen && j < substrlen) { |  | ||||||
|         if (master[i] == substr[j]) { |  | ||||||
|             i++; |  | ||||||
|             j++; |  | ||||||
|         } else { |  | ||||||
|             if (j == 0) { |  | ||||||
|                 i++; |  | ||||||
|             } else { |  | ||||||
|                 j = next[j]; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     free(next); |  | ||||||
|     if (j == substrlen) |  | ||||||
|         return true; |  | ||||||
|     else |  | ||||||
|         return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @description 处理 |  | ||||||
|  * @param |  | ||||||
|  * @return |  | ||||||
|  */ |  | ||||||
| static bool _disposeSubstring(char *level, const char *message, ...) { |  | ||||||
|     int count = 0; |  | ||||||
|  |  | ||||||
|     if (G_keywords == NULL) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     while (G_keywords[count] != NULL) { |  | ||||||
|         if (kmp_search(G_keywords[count], (char *)message)) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         count++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @description : 完成拦截器自我释放内存 |  | ||||||
|  */ |  | ||||||
| static void _freeSubstring(log_Interceptor *interceptor) { |  | ||||||
|     int sum = 0; |  | ||||||
|     while (G_keywords[sum] != NULL) { |  | ||||||
|         free(G_keywords[sum]); |  | ||||||
|         sum++; |  | ||||||
|     } |  | ||||||
|     free(G_keywords); |  | ||||||
|     G_keywords = NULL; |  | ||||||
|  |  | ||||||
|     if (interceptor->handler != NULL) { |  | ||||||
|         interceptor->handler->_free(interceptor->handler); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     free(interceptor); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @description : 子字符串拦截器 |  | ||||||
|  */ |  | ||||||
| log_Interceptor *loggingSubStringInterceptor(char        *keywords[], |  | ||||||
|                                              int          count, |  | ||||||
|                                              log_level    level, |  | ||||||
|                                              log_Handler *handler) { |  | ||||||
|     log_Interceptor *interceptor = |  | ||||||
|         (log_Interceptor *)malloc(sizeof(log_Interceptor)); |  | ||||||
|     interceptor->_dispose = _disposeSubstring; |  | ||||||
|     interceptor->handler  = handler; |  | ||||||
|     interceptor->level    = level; |  | ||||||
|     interceptor->_free    = _freeSubstring; |  | ||||||
|  |  | ||||||
|     G_keywords            = (char **)malloc((sizeof(G_keywords) * count) + 1); |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < count; i++) { |  | ||||||
|         G_keywords[i] = (char *)malloc(strlen(keywords[i]) + 1); |  | ||||||
|         strcpy(G_keywords[i], keywords[i]); |  | ||||||
|     } |  | ||||||
|     G_keywords[count] = NULL; |  | ||||||
|  |  | ||||||
|     G_interceptor     = interceptor; |  | ||||||
|     return G_interceptor; |  | ||||||
| } |  | ||||||
							
								
								
									
										428
									
								
								src/logging.c
									
									
									
									
									
								
							
							
						
						
									
										428
									
								
								src/logging.c
									
									
									
									
									
								
							| @@ -1,9 +1,9 @@ | |||||||
| /******************************************** |  | ||||||
|  * @Date: 2024 08 12 |  | ||||||
|  * @Description: 日志模块 |  | ||||||
|  ********************************************/ |  | ||||||
| #include "logging.h" | #include "logging.h" | ||||||
|  | #include "logging/logging-core.h" | ||||||
| #include "logging/logging-handler.h" | #include "logging/logging-handler.h" | ||||||
|  | #include "utils/logging-map.h" | ||||||
|  | #include "utils/logging-utils.h" | ||||||
|  | #include <stdbool.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| @@ -16,233 +16,277 @@ | |||||||
| #define BLUE   "\033[0;34m" | #define BLUE   "\033[0;34m" | ||||||
| #define RESET  "\033[0m" | #define RESET  "\033[0m" | ||||||
| #define CYAN   "\033[0;36m" | #define CYAN   "\033[0;36m" | ||||||
| #define MAGENTA "\033[0;35m" |  | ||||||
| #define WHITE   "\033[0;37m" |  | ||||||
| #define BLACK   "\033[0;30m" |  | ||||||
|  |  | ||||||
| #define LOG_BUFFER_SIZE 1024 | #define LOG_BUFFER_SIZE 4096 // 日志缓冲区大小,单个日志长度不能超过该值 | ||||||
|  |  | ||||||
| Logger *G_LOGGER = NULL; | static Logger *ROOT_LOGGER = NULL; // 根日志对象,唯一实例 | ||||||
|  |  | ||||||
| static void getTimeStr(char *timeStr) { | static Map *LOGGER_MAP     = NULL; // 日志对象映射表 | ||||||
|     time_t     t = time(NULL); |  | ||||||
|     struct tm *p = localtime(&t); | /** | ||||||
|     char       _timeStr[20]; |  * @brief 为日志添加一个handler | ||||||
|     strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p); |  * @param handler 处理器对象 | ||||||
|     strcpy(timeStr, _timeStr); |  */ | ||||||
|  | bool addHandler(Logger *logger, log_Handler *handler) { | ||||||
|  |     if (logger == NULL || handler == NULL) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if (logger->handler == NULL) { | ||||||
|  |         logger->handler = handler; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     logger->handler->_free(logger->handler); | ||||||
|  |     logger->handler = handler; | ||||||
|  |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @description : 添加日志处理器 |  * @brief 为日志添加一个filter | ||||||
|  |  * @param filter 过滤器对象 | ||||||
|  */ |  */ | ||||||
| static void addHandler(log_Handler *handler) { | bool addFilter(Logger *logger, log_filter *filter) { | ||||||
|     if (G_LOGGER == NULL) { |     if (logger == NULL || filter == NULL) { | ||||||
|         return; |         return false; | ||||||
|     } |     } | ||||||
|     if (G_LOGGER->handler == NULL) { |     if (logger->filter == NULL) { | ||||||
|         G_LOGGER->handler = handler; |         logger->filter       = filter; | ||||||
|         return; |         logger->filter->next = NULL; | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     G_LOGGER->handler->_free(G_LOGGER->handler); |     log_filter *it = logger->filter; | ||||||
|  |     while (it->next != NULL) { | ||||||
|  |         it = it->next; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     G_LOGGER->handler = handler; |     it->next     = filter; | ||||||
|  |     filter->next = NULL; | ||||||
|  |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @description : 添加日志拦截器 |  * @brief 输出到handler | ||||||
|  * @param |  * @param handler 处理器对象 | ||||||
|  * @return |  * @param level 日志等级 | ||||||
|  |  * @param color 应用的颜色 | ||||||
|  |  * @param message 日志内容 | ||||||
|  */ |  */ | ||||||
| void addInterceptor(log_Interceptor *Interceptor) { |  | ||||||
|     if (G_LOGGER == NULL) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     if (G_LOGGER->interceptor == NULL) { |  | ||||||
|         G_LOGGER->interceptor = Interceptor; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     G_LOGGER->interceptor->_free(G_LOGGER->interceptor); |  | ||||||
|  |  | ||||||
|     G_LOGGER->interceptor = Interceptor; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @description : 内置日志记录函数 |  * @brief 输出到handler | ||||||
|  |  * @param handler 处理器对象 | ||||||
|  |  * @param level 日志等级 | ||||||
|  |  * @param color 应用的颜色 | ||||||
|  |  * @param message 日志内容 | ||||||
|  */ |  */ | ||||||
| static void | static void output_to_handler(Logger     *logger, | ||||||
| _builtin_log(char *level, const char *color, const char *message, ...) { |                               char       *level, | ||||||
|     if (G_LOGGER == NULL) { |                               const char *color, | ||||||
|         return; |                               const char *message) { | ||||||
|     } |  | ||||||
|     if (G_LOGGER->handler == NULL) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     char timeStr[20]; |     char timeStr[20]; | ||||||
|     getTimeStr(timeStr); |     getTimeStr(timeStr); | ||||||
|     char logStr[LOG_BUFFER_SIZE]; |     char logStr[LOG_BUFFER_SIZE * 2]; | ||||||
|  |     if (logger->handler->apply_color) { | ||||||
|     log_Handler *handler = G_LOGGER->handler; |         snprintf(logStr, | ||||||
|  |                  LOG_BUFFER_SIZE * 2, | ||||||
|     // 通过拦截器 |                  "[%s]: %s %s%s%s %s\n", | ||||||
|     if (G_LOGGER->interceptor != NULL) { |                  logger->name, | ||||||
|         if (G_LOGGER->interceptor->_dispose(level, message)) { |  | ||||||
|             if (G_LOGGER->interceptor->handler != NULL) { |  | ||||||
|                 handler = G_LOGGER->interceptor->handler; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // 判断处理器是否应用颜色 |  | ||||||
|     if (handler->apply_color) |  | ||||||
|         sprintf(logStr, |  | ||||||
|                 "%s: %s %s%s%s %s\n", |  | ||||||
|                 G_LOGGER->name, |  | ||||||
|                  timeStr, |                  timeStr, | ||||||
|                  color, |                  color, | ||||||
|                  level, |                  level, | ||||||
|                  RESET, |                  RESET, | ||||||
|                  message); |                  message); | ||||||
|     else |     } else { | ||||||
|         sprintf( |         snprintf(logStr, | ||||||
|             logStr, "%s: %s %s %s\n", G_LOGGER->name, timeStr, level, message); |                  LOG_BUFFER_SIZE * 2, | ||||||
|  |                  "[%s]: %s %s %s\n", | ||||||
|     handler->output(handler, logStr); |                  logger->name, | ||||||
| } |                  timeStr, | ||||||
|  |                  level, | ||||||
| //*************************记录日志******************************* */ |                  message); | ||||||
| static void fatal(const char *message, ...) { |  | ||||||
|     if (G_LOGGER->level >= LOG_ERROR) { |  | ||||||
|         char    logStr[LOG_BUFFER_SIZE]; |  | ||||||
|         va_list args; |  | ||||||
|         va_start(args, message); |  | ||||||
|         vsprintf(logStr, message, args); |  | ||||||
|         va_end(args); |  | ||||||
|         _builtin_log("Fatal", RED_B, logStr, args); |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |  | ||||||
| static void error(const char *message, ...) { |     logger->handler->output(logger->handler, logStr); | ||||||
|     if (G_LOGGER->level >= LOG_ERROR) { |  | ||||||
|         char    logStr[LOG_BUFFER_SIZE]; |  | ||||||
|         va_list args; |  | ||||||
|         va_start(args, message); |  | ||||||
|         vsprintf(logStr, message, args); |  | ||||||
|         va_end(args); |  | ||||||
|         _builtin_log("Error", RED, logStr, args); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void warning(const char *message, ...) { |  | ||||||
|     if (G_LOGGER->level >= LOG_WARNING) { |  | ||||||
|         char    logStr[LOG_BUFFER_SIZE]; |  | ||||||
|         va_list args; |  | ||||||
|         va_start(args, message); |  | ||||||
|         vsprintf(logStr, message, args); |  | ||||||
|         va_end(args); |  | ||||||
|         _builtin_log("Warning", YELLOW, logStr, args); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void info(const char *message, ...) { |  | ||||||
|     if (G_LOGGER->level >= LOG_INFO) { |  | ||||||
|         char    logStr[LOG_BUFFER_SIZE]; |  | ||||||
|         va_list args; |  | ||||||
|         va_start(args, message); |  | ||||||
|         vsprintf(logStr, message, args); |  | ||||||
|         va_end(args); |  | ||||||
|         _builtin_log("Info", GREEN, logStr, args); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void debug(const char *message, ...) { |  | ||||||
|     if (G_LOGGER->level >= LOG_DEBUG) { |  | ||||||
|         char    logStr[LOG_BUFFER_SIZE]; |  | ||||||
|         va_list args; |  | ||||||
|         va_start(args, message); |  | ||||||
|         vsprintf(logStr, message, args); |  | ||||||
|         va_end(args); |  | ||||||
|         _builtin_log("Debug", CYAN, logStr, args); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| //*************************记录日志******************************* */ |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @description :获取一个日志操作对象 |  * @brief 内部日志打印处理核心函数 | ||||||
|  * @param |  * @param level 日志等级 | ||||||
|  |  * @param color 应用的颜色 | ||||||
|  |  * @param message 日志内容 | ||||||
|  |  * @param ... 格式化参数列表 | ||||||
|  * @return |  * @return | ||||||
|  */ |  */ | ||||||
| static Logger *getLogger(const char *name, log_level level) { | static void | ||||||
|     if (G_LOGGER != NULL) { | log_cope(Logger *logger, char *level, const char *color, const char *message) { | ||||||
|         G_LOGGER->name  = name; |     if (logger == NULL) { | ||||||
|         G_LOGGER->level = level; |         return; | ||||||
|         return G_LOGGER; |     } | ||||||
|  |     if (logger->handler == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     log_filter  *it      = logger->filter; | ||||||
|  |     log_Handler *handler = logger->handler; | ||||||
|  |  | ||||||
|  |     while (it != NULL) { | ||||||
|  |         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(logger, level, color, message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |  | ||||||
|  |         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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief 创建一个日志句柄 | ||||||
|  |  * @param name 日志器名称 | ||||||
|  |  * @return 日志器对象 | ||||||
|  |  */ | ||||||
|  | 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 *logger  = (Logger *)malloc(sizeof(Logger)); | ||||||
|     // 方法 |  | ||||||
|     logger->fatal          = fatal; |  | ||||||
|     logger->error          = error; |  | ||||||
|     logger->warning        = warning; |  | ||||||
|     logger->info           = info; |  | ||||||
|     logger->debug          = debug; |  | ||||||
|  |  | ||||||
|     logger->addHandler     = addHandler; |     logger->level   = LOG_INFO; | ||||||
|     logger->addInterceptor = addInterceptor; |     logger->handler = loggingHandlerConsole(); | ||||||
|  |  | ||||||
|     // 属性 |  | ||||||
|     logger->level          = level; |  | ||||||
|     logger->handler        = loggingConsoleHandler(); |  | ||||||
|     logger->name    = name; |     logger->name    = name; | ||||||
|     logger->interceptor    = NULL; |     logger->filter  = NULL; | ||||||
|  |  | ||||||
|     G_LOGGER               = logger; |     map_put(LOGGER_MAP, name, &logger); | ||||||
|     return G_LOGGER; |  | ||||||
|  |     return logger; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void destroyLogger(Logger *logger) { | ||||||
|  |     if (logger != NULL) { | ||||||
|  |         if (logger->handler != NULL) { | ||||||
|  |             logger->handler->_free(logger->handler); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (logger->filter != NULL) { | ||||||
|  |             log_filter *it   = logger->filter; | ||||||
|  |             log_filter *next = NULL; | ||||||
|  |             while (it != NULL) { | ||||||
|  |                 next = it->next; | ||||||
|  |                 it->_free(it); | ||||||
|  |                 it = next; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         free(logger); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | __destroyLoggerForeach(const char *key, void *value, void *user_data) { | ||||||
|  |     (void)user_data; | ||||||
|  |     (void)key; | ||||||
|  |     destroyLogger(*(Logger **)value); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @description :销毁日志对象 |  * @brief 销毁日志对象 | ||||||
|  */ |  */ | ||||||
| log_status destroyLogging(Logging *logging) { | void destroyDefaultLogger(void) { | ||||||
|     if (logging == NULL) { |     map_foreach(LOGGER_MAP, __destroyLoggerForeach, NULL); | ||||||
|         return L_ERROR; |     map_destroy(LOGGER_MAP); | ||||||
|     } |  | ||||||
|     if (G_LOGGER != NULL) { |  | ||||||
|         if (G_LOGGER->handler != NULL) { |  | ||||||
|             G_LOGGER->handler->_free(G_LOGGER->handler); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (G_LOGGER->interceptor != NULL) { |  | ||||||
|             G_LOGGER->interceptor->_free(G_LOGGER->interceptor); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         free(G_LOGGER); |  | ||||||
|         G_LOGGER = NULL; |  | ||||||
|     } |  | ||||||
|     free(logging); |  | ||||||
|     return L_OK; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @description :获取当前日志操作对象 |  | ||||||
|  * @return 当前唯一的日志操作对象 |  | ||||||
|  */ |  | ||||||
| Logger *getCurrentLogger(void) { |  | ||||||
|     if (G_LOGGER == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     return G_LOGGER; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @description :创建一个日志对象 |  | ||||||
|  * @return :Logging* 返回一个日志对象 |  | ||||||
|  */ |  | ||||||
| Logging *newLogging() { |  | ||||||
|     Logging *logging          = (Logging *)malloc(sizeof(Logging)); |  | ||||||
|     logging->getLogger        = getLogger; |  | ||||||
|     logging->destroyLogging   = destroyLogging; |  | ||||||
|     logging->getCurrentLogger = getCurrentLogger; |  | ||||||
|     return logging; |  | ||||||
| } | } | ||||||
							
								
								
									
										143
									
								
								src/utils/logging-map.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								src/utils/logging-map.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | #include "logging-map.h" | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | /* 哈希函数: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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								src/utils/logging-map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/utils/logging-map.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #ifndef __LOGGING_MAP_H__ | ||||||
|  | #define __LOGGING_MAP_H__ | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdint.h> | ||||||
|  |  | ||||||
|  | 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> 必须指向 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__ */ | ||||||
							
								
								
									
										15
									
								
								src/utils/logging-utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/utils/logging-utils.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | #include "logging-utils.h" | ||||||
|  | #include <string.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @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); | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								src/utils/logging-utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/utils/logging-utils.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | #ifndef __LOGGING_UTILS_H__ | ||||||
|  | #define __LOGGING_UTILS_H__ | ||||||
|  |  | ||||||
|  | void getTimeStr(char *timeStr); | ||||||
|  | #endif // __LOGGING_UTILS_H__ | ||||||
| @@ -1,8 +1,31 @@ | |||||||
| project(test) | project(test) | ||||||
|  |  | ||||||
| add_executable(${PROJECT_NAME}simple test_simple.c) | enable_testing() | ||||||
| target_link_libraries(${PROJECT_NAME}simple Logging) |  | ||||||
|  | include_directories(${CMAKE_SOURCE_DIR}/src) | ||||||
|  |  | ||||||
|  | #测试简单基本应用 | ||||||
|  | add_executable(${PROJECT_NAME}simple test-simple.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}simple logging) | ||||||
|  | add_test(test_simple ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}simple${CMAKE_EXECUTEABLE_SUFFIX}) | ||||||
|  |  | ||||||
|  | #测试简单基本应用 | ||||||
|  | add_executable(${PROJECT_NAME}file test-log-file.c) | ||||||
|  | target_link_libraries(${PROJECT_NAME}file logging) | ||||||
|  | add_test(test_file ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}file${CMAKE_EXECUTEABLE_SUFFIX}) | ||||||
|  |  | ||||||
|  |  | ||||||
| add_executable(${PROJECT_NAME}interceptor test_interceptor.c) | #测试拦截器 | ||||||
| target_link_libraries(${PROJECT_NAME}interceptor Logging) | 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}) | ||||||
							
								
								
									
										47
									
								
								tests/test-filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tests/test-filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | #include "logging.h" | ||||||
|  | #include "logging/logging-core.h" | ||||||
|  | #include "logging/logging-filter.h" | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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}; | ||||||
|  |  | ||||||
|  |     log_filter *tint = | ||||||
|  |         loggingFilterSubStr(test1, | ||||||
|  |                             LOG_DEBUG, | ||||||
|  |                             loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||||
|  |                             false); | ||||||
|  |  | ||||||
|  |     addFilter(getDefaultLogger(), tint); | ||||||
|  |  | ||||||
|  |     char *test2[]     = {"123", NULL}; | ||||||
|  |  | ||||||
|  |     log_filter *tint1 = loggingFilterSubStr( | ||||||
|  |         test2, | ||||||
|  |         LOG_ERROR, | ||||||
|  |         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||||
|  |         true); | ||||||
|  |  | ||||||
|  |     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"); | ||||||
|  |  | ||||||
|  |     destroyDefaultLogger(); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								tests/test-log-file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/test-log-file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | #include "logging.h" | ||||||
|  | #include "logging/logging-handler.h" | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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"); | ||||||
|  |  | ||||||
|  |     destroyDefaultLogger(); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								tests/test-logs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/test-logs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | #include "logging.h" | ||||||
|  | #include "logging/logging-core.h" | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								tests/test-map.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/test-map.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | #include "utils/logging-map.h" | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								tests/test-simple.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/test-simple.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #include "logging.h" | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     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; | ||||||
|  | } | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| #include "logging.h" |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| int main() { |  | ||||||
|     Logging *log    = newLogging(); |  | ||||||
|     Logger  *logger = log->getLogger("testLogger", LOG_DEBUG); |  | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |  | ||||||
|     logger->error("你好,这是一个错误消息%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("被拦截")); |  | ||||||
|  |  | ||||||
|     logger->addInterceptor(tint); |  | ||||||
|  |  | ||||||
|     printf("\n"); |  | ||||||
|     printf("Interceptor added\n"); |  | ||||||
|     printf("\n"); |  | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |  | ||||||
|     logger->error("你好,这是一个错误消息%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); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| #include "logging.h" |  | ||||||
|  |  | ||||||
| int main() { |  | ||||||
|     Logging *log    = newLogging(); |  | ||||||
|     Logger  *logger = log->getLogger("testLogger", LOG_DEBUG); |  | ||||||
|  |  | ||||||
|     logger->info("This is an info message"); |  | ||||||
|     logger->error("你好,这是一个错误消息%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); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
							
								
								
									
										238
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | |||||||
|  | version = 1 | ||||||
|  | revision = 2 | ||||||
|  | requires-python = ">=3.12" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "certifi" | ||||||
|  | version = "2025.6.15" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "charset-normalizer" | ||||||
|  | version = "3.4.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "colorama" | ||||||
|  | version = "0.4.6" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "conan" | ||||||
|  | version = "2.18.1" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "colorama" }, | ||||||
|  |     { name = "distro", marker = "platform_system == 'FreeBSD' or sys_platform == 'linux'" }, | ||||||
|  |     { name = "fasteners" }, | ||||||
|  |     { name = "jinja2" }, | ||||||
|  |     { name = "patch-ng" }, | ||||||
|  |     { name = "python-dateutil" }, | ||||||
|  |     { name = "pyyaml" }, | ||||||
|  |     { name = "requests" }, | ||||||
|  |     { name = "urllib3" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c7/55/9a10f21dd6dc9137c6e7b51eff7c54ab92400812e6e795d1a991ead00b54/conan-2.18.1.tar.gz", hash = "sha256:5d8e9fac7614de9297933f65de8f17db14851a871cebc962f4856b7c294f43c5", size = 521034, upload-time = "2025-07-04T07:08:07.842Z" } | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "distro" | ||||||
|  | version = "1.8.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/4b/89/eaa3a3587ebf8bed93e45aa79be8c2af77d50790d15b53f6dfc85b57f398/distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8", size = 59428, upload-time = "2022-10-10T15:30:33.395Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f4/2c/c90a3adaf0ddb70afe193f5ebfb539612af57cffe677c3126be533df3098/distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff", size = 20315, upload-time = "2022-10-10T15:30:26.903Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "fasteners" | ||||||
|  | version = "0.19" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/5f/d4/e834d929be54bfadb1f3e3b931c38e956aaa3b235a46a3c764c26c774902/fasteners-0.19.tar.gz", hash = "sha256:b4f37c3ac52d8a445af3a66bce57b33b5e90b97c696b7b984f530cf8f0ded09c" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl", hash = "sha256:758819cb5d94cdedf4e836988b74de396ceacb8e2794d21f82d131fd9ee77237" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "idna" | ||||||
|  | version = "3.10" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "jinja2" | ||||||
|  | version = "3.1.6" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "markupsafe" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "logging" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = { virtual = "." } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "conan" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [package.metadata] | ||||||
|  | requires-dist = [{ name = "conan", specifier = ">=2.18.1" }] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "markupsafe" | ||||||
|  | version = "3.0.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "patch-ng" | ||||||
|  | version = "1.18.1" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ee/c0/53a2f017ac5b5397a7064c2654b73c3334ac8461315707cbede6c12199eb/patch-ng-1.18.1.tar.gz", hash = "sha256:52fd46ee46f6c8667692682c1fd7134edc65a2d2d084ebec1d295a6087fc0291", size = 17913, upload-time = "2024-10-25T12:20:10.591Z" } | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "python-dateutil" | ||||||
|  | version = "2.9.0.post0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "six" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "pyyaml" | ||||||
|  | version = "6.0.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "requests" | ||||||
|  | version = "2.32.4" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "certifi" }, | ||||||
|  |     { name = "charset-normalizer" }, | ||||||
|  |     { name = "idna" }, | ||||||
|  |     { name = "urllib3" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "six" | ||||||
|  | version = "1.17.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "urllib3" | ||||||
|  | version = "2.0.7" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/af/47/b215df9f71b4fdba1025fc05a77db2ad243fa0926755a52c5e71659f4e3c/urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", size = 282546, upload-time = "2023-10-17T17:46:50.542Z" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d2/b2/b157855192a68541a91ba7b2bbcb91f1b4faa51f8bae38d8005c034be524/urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e", size = 124213, upload-time = "2023-10-17T17:46:48.538Z" }, | ||||||
|  | ] | ||||||
		Reference in New Issue
	
	Block a user