Compare commits
	
		
			19 Commits
		
	
	
		
			0c96f67b47
			...
			v0.5.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6ff484fef8 | |||
|  | 8e512563e4 | ||
|  | 9d3a7bbb8d | ||
|  | 064881c0ad | ||
|  | f0c3a5d56a | ||
|  | 56e1ac52ff | ||
|  | cc53e07788 | ||
|  | a4b4ad7452 | ||
|  | f4494515ca | ||
|  | d0bfc31563 | ||
|  | 650ce0dc3f | ||
|  | 3ef229ed65 | ||
|  | b7f49188ad | ||
|  | d61f7b6fde | ||
|  | 86cf4c4526 | ||
|  | 6765dd1214 | ||
| b852bdceb8 | |||
| 556595be2b | |||
| e39dcdcde9 | 
							
								
								
									
										246
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | ||||
| --- | ||||
| Language:        Cpp | ||||
| # BasedOnStyle:  LLVM | ||||
| AccessModifierOffset: -2 | ||||
| AlignAfterOpenBracket: Align | ||||
| AlignArrayOfStructures: None | ||||
| AlignConsecutiveAssignments: | ||||
|   Enabled:         true | ||||
|   AcrossEmptyLines: true | ||||
|   AcrossComments:  true | ||||
|   AlignCompound:   false | ||||
|   AlignFunctionPointers: false | ||||
|   PadOperators:    true | ||||
| AlignConsecutiveBitFields: | ||||
|   Enabled:         true | ||||
|   AcrossEmptyLines: false | ||||
|   AcrossComments:  false | ||||
|   AlignCompound:   false | ||||
|   AlignFunctionPointers: false | ||||
|   PadOperators:    false | ||||
| AlignConsecutiveDeclarations: | ||||
|   Enabled:         true | ||||
|   AcrossEmptyLines: false | ||||
|   AcrossComments:  false | ||||
|   AlignCompound:   false | ||||
|   AlignFunctionPointers: false | ||||
|   PadOperators:    false | ||||
| AlignConsecutiveMacros: | ||||
|   Enabled:         true | ||||
|   AcrossEmptyLines: false | ||||
|   AcrossComments:  false | ||||
|   AlignCompound:   false | ||||
|   AlignFunctionPointers: false | ||||
|   PadOperators:    false | ||||
| AlignConsecutiveShortCaseStatements: | ||||
|   Enabled:         false | ||||
|   AcrossEmptyLines: false | ||||
|   AcrossComments:  false | ||||
|   AlignCaseColons: false | ||||
| AlignEscapedNewlines: Right | ||||
| AlignOperands:   Align | ||||
| AlignTrailingComments: | ||||
|   Kind:            Always | ||||
|   OverEmptyLines:  0 | ||||
| AllowAllArgumentsOnNextLine: true | ||||
| AllowAllParametersOfDeclarationOnNextLine: true | ||||
| AllowBreakBeforeNoexceptSpecifier: Never | ||||
| AllowShortBlocksOnASingleLine: Never | ||||
| AllowShortCaseLabelsOnASingleLine: false | ||||
| AllowShortCompoundRequirementOnASingleLine: true | ||||
| AllowShortEnumsOnASingleLine: true | ||||
| AllowShortFunctionsOnASingleLine: All | ||||
| AllowShortIfStatementsOnASingleLine: Never | ||||
| AllowShortLambdasOnASingleLine: All | ||||
| AllowShortLoopsOnASingleLine: false | ||||
| AlwaysBreakAfterDefinitionReturnType: None | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: MultiLine | ||||
| AttributeMacros: | ||||
|   - __capability | ||||
| BinPackArguments: false | ||||
| BinPackParameters: false | ||||
| BitFieldColonSpacing: Both | ||||
| BraceWrapping: | ||||
|   AfterCaseLabel:  false | ||||
|   AfterClass:      false | ||||
|   AfterControlStatement: Never | ||||
|   AfterEnum:       false | ||||
|   AfterExternBlock: false | ||||
|   AfterFunction:   false | ||||
|   AfterNamespace:  false | ||||
|   AfterObjCDeclaration: false | ||||
|   AfterStruct:     false | ||||
|   AfterUnion:      false | ||||
|   BeforeCatch:     false | ||||
|   BeforeElse:      false | ||||
|   BeforeLambdaBody: false | ||||
|   BeforeWhile:     false | ||||
|   IndentBraces:    false | ||||
|   SplitEmptyFunction: true | ||||
|   SplitEmptyRecord: true | ||||
|   SplitEmptyNamespace: true | ||||
| BreakAdjacentStringLiterals: true | ||||
| BreakAfterAttributes: Leave | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakArrays:     true | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeConceptDeclarations: Always | ||||
| BreakBeforeBraces: Attach | ||||
| BreakBeforeInlineASMColon: OnlyMultiline | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakConstructorInitializers: BeforeColon | ||||
| BreakInheritanceList: BeforeColon | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit:     80 | ||||
| CommentPragmas:  '^ IWYU pragma:' | ||||
| CompactNamespaces: false | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
| Cpp11BracedListStyle: true | ||||
| DerivePointerAlignment: false | ||||
| DisableFormat:   false | ||||
| EmptyLineAfterAccessModifier: Never | ||||
| EmptyLineBeforeAccessModifier: LogicalBlock | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| FixNamespaceComments: true | ||||
| ForEachMacros: | ||||
|   - foreach | ||||
|   - Q_FOREACH | ||||
|   - BOOST_FOREACH | ||||
| IfMacros: | ||||
|   - KJ_IF_MAYBE | ||||
| IncludeBlocks:   Preserve | ||||
| IncludeCategories: | ||||
|   - Regex:           '^"(llvm|llvm-c|clang|clang-c)/' | ||||
|     Priority:        2 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '^(<|"(gtest|gmock|isl|json)/)' | ||||
|     Priority:        3 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '.*' | ||||
|     Priority:        1 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
| IncludeIsMainRegex: '(Test)?$' | ||||
| IncludeIsMainSourceRegex: '' | ||||
| IndentAccessModifiers: false | ||||
| IndentCaseBlocks: false | ||||
| IndentCaseLabels: false | ||||
| IndentExternBlock: AfterExternBlock | ||||
| IndentGotoLabels: true | ||||
| IndentPPDirectives: None | ||||
| IndentRequiresClause: true | ||||
| IndentWidth:     4 | ||||
| IndentWrappedFunctionNames: false | ||||
| InsertBraces:    false | ||||
| InsertNewlineAtEOF: false | ||||
| InsertTrailingCommas: None | ||||
| IntegerLiteralSeparator: | ||||
|   Binary:          0 | ||||
|   BinaryMinDigits: 0 | ||||
|   Decimal:         0 | ||||
|   DecimalMinDigits: 0 | ||||
|   Hex:             0 | ||||
|   HexMinDigits:    0 | ||||
| JavaScriptQuotes: Leave | ||||
| JavaScriptWrapImports: true | ||||
| KeepEmptyLinesAtTheStartOfBlocks: true | ||||
| KeepEmptyLinesAtEOF: false | ||||
| LambdaBodyIndentation: Signature | ||||
| LineEnding:      DeriveLF | ||||
| MacroBlockBegin: '' | ||||
| MacroBlockEnd:   '' | ||||
| MaxEmptyLinesToKeep: 1 | ||||
| NamespaceIndentation: None | ||||
| ObjCBinPackProtocolList: Auto | ||||
| ObjCBlockIndentWidth: 2 | ||||
| ObjCBreakBeforeNestedBlockParam: true | ||||
| ObjCSpaceAfterProperty: false | ||||
| ObjCSpaceBeforeProtocolList: true | ||||
| PackConstructorInitializers: BinPack | ||||
| PenaltyBreakAssignment: 2 | ||||
| PenaltyBreakBeforeFirstCallParameter: 19 | ||||
| PenaltyBreakComment: 300 | ||||
| PenaltyBreakFirstLessLess: 120 | ||||
| PenaltyBreakOpenParenthesis: 0 | ||||
| PenaltyBreakScopeResolution: 500 | ||||
| PenaltyBreakString: 1000 | ||||
| PenaltyBreakTemplateDeclaration: 10 | ||||
| PenaltyExcessCharacter: 1000000 | ||||
| PenaltyIndentedWhitespace: 0 | ||||
| PenaltyReturnTypeOnItsOwnLine: 60 | ||||
| PointerAlignment: Right | ||||
| PPIndentWidth:   -1 | ||||
| QualifierAlignment: Leave | ||||
| ReferenceAlignment: Pointer | ||||
| ReflowComments:  true | ||||
| RemoveBracesLLVM: false | ||||
| RemoveParentheses: Leave | ||||
| RemoveSemicolon: false | ||||
| RequiresClausePosition: OwnLine | ||||
| RequiresExpressionIndentation: OuterScope | ||||
| SeparateDefinitionBlocks: Leave | ||||
| ShortNamespaceLines: 1 | ||||
| SkipMacroDefinitionBody: false | ||||
| SortIncludes:    CaseSensitive | ||||
| SortJavaStaticImport: Before | ||||
| SortUsingDeclarations: LexicographicNumeric | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterLogicalNot: false | ||||
| SpaceAfterTemplateKeyword: true | ||||
| SpaceAroundPointerQualifiers: Default | ||||
| SpaceBeforeAssignmentOperators: true | ||||
| SpaceBeforeCaseColon: false | ||||
| SpaceBeforeCpp11BracedList: false | ||||
| SpaceBeforeCtorInitializerColon: true | ||||
| SpaceBeforeInheritanceColon: true | ||||
| SpaceBeforeJsonColon: false | ||||
| SpaceBeforeParens: ControlStatements | ||||
| SpaceBeforeParensOptions: | ||||
|   AfterControlStatements: true | ||||
|   AfterForeachMacros: true | ||||
|   AfterFunctionDefinitionName: false | ||||
|   AfterFunctionDeclarationName: false | ||||
|   AfterIfMacros:   true | ||||
|   AfterOverloadedOperator: false | ||||
|   AfterPlacementOperator: true | ||||
|   AfterRequiresInClause: false | ||||
|   AfterRequiresInExpression: false | ||||
|   BeforeNonEmptyParentheses: false | ||||
| SpaceBeforeRangeBasedForLoopColon: true | ||||
| SpaceBeforeSquareBrackets: false | ||||
| SpaceInEmptyBlock: false | ||||
| SpacesBeforeTrailingComments: 1 | ||||
| SpacesInAngles:  Never | ||||
| SpacesInContainerLiterals: true | ||||
| SpacesInLineCommentPrefix: | ||||
|   Minimum:         1 | ||||
|   Maximum:         -1 | ||||
| SpacesInParens:  Never | ||||
| SpacesInParensOptions: | ||||
|   InCStyleCasts:   false | ||||
|   InConditionalStatements: false | ||||
|   InEmptyParentheses: false | ||||
|   Other:           false | ||||
| SpacesInSquareBrackets: false | ||||
| Standard:        Latest | ||||
| StatementAttributeLikeMacros: | ||||
|   - Q_EMIT | ||||
| StatementMacros: | ||||
|   - Q_UNUSED | ||||
|   - QT_REQUIRE_VERSION | ||||
| TabWidth:        8 | ||||
| UseTab:          Never | ||||
| VerilogBreakBetweenInstancePorts: true | ||||
| WhitespaceSensitiveMacros: | ||||
|   - BOOST_PP_STRINGIZE | ||||
|   - CF_SWIFT_NAME | ||||
|   - NS_SWIFT_NAME | ||||
|   - PP_STRINGIZE | ||||
|   - STRINGIZE | ||||
| ... | ||||
|  | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,4 @@ | ||||
|  | ||||
| .cache | ||||
| .vscode/** | ||||
| bin | ||||
| build | ||||
| CMakeUserPresets.json | ||||
|   | ||||
| @@ -1,25 +1,26 @@ | ||||
| cmake_minimum_required( VERSION 3.28) | ||||
| cmake_minimum_required(VERSION 3.28...3.30) | ||||
|  | ||||
| project(Logging) | ||||
| project(logging) | ||||
|  | ||||
| set(CMAKE_C_STANDARD 99) | ||||
|  | ||||
| aux_source_directory(${CMAKE_SOURCE_DIR}/src SRC) | ||||
| if(MSVC) | ||||
|     add_compile_options("/source-charset:utf-8") | ||||
|     add_compile_options("/execution-charset:utf-8") | ||||
| endif() | ||||
|  | ||||
| set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) | ||||
| set(ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) | ||||
| set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) | ||||
| set(CMAKE_EXPORT_COMPILE_COMMANDS yes) | ||||
|  | ||||
| option(TEST "是否启动单元测试" ON) | ||||
| option(SHARED "是否编译为动态库" OFF) | ||||
|  | ||||
| include_directories(${CMAKE_SOURCE_DIR}/include) | ||||
|  | ||||
| if (SHARED) | ||||
|     add_library(${PROJECT_NAME} SHARED ${SRC}) | ||||
| else() | ||||
|     add_library(${PROJECT_NAME} ${SRC}) | ||||
| endif() | ||||
| #编译库文件 | ||||
| add_subdirectory(src) | ||||
|  | ||||
| if (SKIPTEST) | ||||
| else() | ||||
|     add_executable(test_simple ${CMAKE_SOURCE_DIR}/test_package/test_simple.c ${SRC}) | ||||
|     add_executable(test_interceptor ${CMAKE_SOURCE_DIR}/test_package/test_interceptor.c ${SRC}) | ||||
| #测试单元 | ||||
| if (TEST) | ||||
|     enable_testing() | ||||
|     add_subdirectory(tests) | ||||
| endif() | ||||
|  | ||||
|   | ||||
							
								
								
									
										163
									
								
								README.en.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								README.en.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| # 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() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     log_info("This is an info message"); | ||||
|     log_error("This is an error message%s", "123"); | ||||
|     log_fatal("This is an fatal message"); | ||||
|     log_debug("This is a debug message"); | ||||
|     log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### file log | ||||
| ```c | ||||
| #include "logging.h" | ||||
| #include "logging/logging-handler.h" | ||||
|  | ||||
| int main() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|     logger->addHandler(loggingHandlerFile("test1", 1024*1024)); | ||||
|  | ||||
|     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 | ||||
|  | ||||
|  | ||||
| #### example | ||||
| Redirects filtered logs to a dedicated file processor | ||||
| ```c | ||||
| #include "logging.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| int main() { | ||||
|     Logger  *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     log_info("This is an info message"); | ||||
|     log_error("This is an error message%s", "123"); | ||||
|     log_fatal("This is an fatal message"); | ||||
|     log_debug("This is a debug message"); | ||||
|     log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     char *test1[]         = {"123", "tt", NULL}; | ||||
|  | ||||
|     log_filter *tint = loggingFilterSubStr( | ||||
|         test1, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|         true); | ||||
|  | ||||
|     logger->addFilter(tint); | ||||
|  | ||||
|     printf("\n"); | ||||
|     printf("filter added\n"); | ||||
|     printf("\n"); | ||||
|  | ||||
|     log_info("This is an info message"); | ||||
|     log_error("This is an error message%s", "123"); | ||||
|     log_fatal("This is an fatal message"); | ||||
|     log_debug("This is a debug message"); | ||||
|     log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### Multiple substring filters | ||||
| ```c | ||||
| #include "logging.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <time.h> | ||||
|  | ||||
| int main() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     log_info("This is an info message"); | ||||
|     log_error("This is an error message%s", "123"); | ||||
|     log_fatal("This is an fatal message"); | ||||
|     log_debug("This is a debug message"); | ||||
|     log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     char *test1[]         = {"This",NULL}; | ||||
|  | ||||
|     log_filter *tint = loggingFilterSubStr( | ||||
|         test1, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|         false); | ||||
|  | ||||
|     logger->addFilter(tint); | ||||
|  | ||||
|     char *test2[]         = {"123",NULL}; | ||||
|  | ||||
|     log_filter *tint1 = loggingFilterSubStr( | ||||
|         test2, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||
|         true); | ||||
|  | ||||
|     logger->addFilter(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; | ||||
| } | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										178
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| # C语言日志库logging | ||||
|  | ||||
| [English](README.en.md) | ||||
|  | ||||
| ## 简介 | ||||
|  | ||||
| logging是一个轻量级的简单易用C语言日志库,支持日志级别、日志格式、日志输出、日志文件等功能。 | ||||
| @@ -9,28 +11,51 @@ logging是一个轻量级的简单易用C语言日志库,支持日志级别、 | ||||
| - 支持日志级别: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 | ||||
| #include "logging.h" | ||||
|  | ||||
| int main() { | ||||
|     Logging *log = createLogging(); // 创建日志对象 | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); //获取日志控制器 | ||||
|     Log_info("This is an info message"); | ||||
|     Log_error("This is an error message%s", "123"); | ||||
|     Log_fatal("This is an fatal message"); | ||||
|     Log_debug("This is a debug message"); | ||||
|     Log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     logger->addHandler(consoleHandler("test")); //为日志对象添加控制台处理器 | ||||
|  | ||||
|     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"); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
| @@ -38,64 +63,117 @@ int main() { | ||||
| ### 文件日志 | ||||
| ```c | ||||
| #include "logging.h" | ||||
| #include "logging/logging-handler.h" | ||||
|  | ||||
| int main() { | ||||
|     // Your code goes here | ||||
|     Logging *log = createLogging(); | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|     logger->addHandler(loggingHandlerFile("test1", 1024*1024)); | ||||
|  | ||||
|     logger->addHandler(consoleHandler("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"); | ||||
|     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"); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### 日志拦截器 | ||||
| > 支持添加自定义的拦截器, 目前内置了子串拦截器 | ||||
| ### 日志过滤器 | ||||
| > 支持添加自定义的过滤器, 目前内置了子串过滤器 | ||||
|  | ||||
| > 拦截器的作用:可以将拦截到的日志重定向到拦截器的专属处理器中 | ||||
| > 过滤器的作用:可以将过滤到的日志重定向到过滤器的专属处理器中 | ||||
|  | ||||
|  | ||||
| #### 例子 | ||||
| 将拦截到的日志重定向到专属文件处理器中 | ||||
| #### 单个子串过滤器 | ||||
| 将过滤到的日志重定向到专属处理器中 | ||||
| ```c | ||||
| #include "logging.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| int main() { | ||||
|     Logging *log = createLogging(); | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); | ||||
|     logger->addHandler(consoleHandler("test")); | ||||
|     Logger  *logger = newDefaultLogger("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_info("This is an info message"); | ||||
|     Log_error("This is an error message%s", "123"); | ||||
|     Log_fatal("This is an fatal message"); | ||||
|     Log_debug("This is a debug message"); | ||||
|     Log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     char *test1[] = {"123", "你好"};//要拦截的字符串 | ||||
|     //添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中 | ||||
|     log_Interceptor * tint = substringInterceptor(test1,2,LOG_DEBUG,fileHandler("被拦截"));  | ||||
|     logger->addInterceptor(tint); | ||||
|     printf("Interceptor added\n"); | ||||
|     char *test1[]         = {"123", "tt", NULL}; | ||||
|  | ||||
|     logger->info("This is an info message"); | ||||
|     logger->error("你好,这是一个错误消息%s", "123"); | ||||
|     logger->fatal("This is an fatal message"); | ||||
|     log_filter *tint = loggingFilterSubStr( | ||||
|         test1, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|         true); | ||||
|  | ||||
|     logger->debug("This is a debug message"); | ||||
|     logger->warning("This is a warning message%s", "123"); | ||||
|     logger->addFilter(tint); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     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; | ||||
| } | ||||
| ``` | ||||
| .png) | ||||
|  | ||||
|  | ||||
| #### 多个子串过滤器 | ||||
| ```c | ||||
| #include "logging.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <time.h> | ||||
|  | ||||
| int main() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     Log_info("This is an info message"); | ||||
|     Log_error("This is an error message%s", "123"); | ||||
|     Log_fatal("This is an fatal message"); | ||||
|     Log_debug("This is a debug message"); | ||||
|     Log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     char *test1[]         = {"This",NULL}; | ||||
|  | ||||
|     log_filter *tint = loggingFilterSubStr( | ||||
|         test1, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|         false); | ||||
|  | ||||
|     logger->addFilter(tint); | ||||
|  | ||||
|     char *test2[]         = {"123",NULL}; | ||||
|  | ||||
|     log_filter *tint1 = loggingFilterSubStr( | ||||
|         test2, | ||||
|         LOG_DEBUG, | ||||
|         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||
|         true); | ||||
|  | ||||
|     logger->addFilter(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; | ||||
| } | ||||
| ``` | ||||
|  | ||||
|   | ||||
							
								
								
									
										30
									
								
								conanfile.py
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								conanfile.py
									
									
									
									
									
								
							| @@ -1,15 +1,11 @@ | ||||
| from conan import ConanFile | ||||
| from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout | ||||
| from conan.tools.files import copy, get | ||||
| from conan.tools.build import check_min_cppstd | ||||
| from conan import tools | ||||
| from conan.tools.files import copy | ||||
| import os | ||||
|  | ||||
|  | ||||
|  | ||||
| class loggingRecipe(ConanFile): | ||||
|     name = "logging" | ||||
|     version = "0.1.1" | ||||
|     version = "0.5.1" | ||||
|     license = "MIT" | ||||
|     author = "321640253@qq.com" | ||||
|     url = "https://github.com/WangZhongDian/logging.git" | ||||
| @@ -17,11 +13,11 @@ class loggingRecipe(ConanFile): | ||||
|     topics = ("logging", "C", "simple", "easy-to-use", "log","Logging") | ||||
|  | ||||
|     settings = "os", "compiler", "build_type", "arch" | ||||
|     options = {"shared": [True, False], "fPIC": [True, False]} | ||||
|     default_options = {"shared": False, "fPIC": True} | ||||
|     options = {"shared": [True, False], "fPIC": [True, False],"test":[True,False]} | ||||
|     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): | ||||
|         if self.settings.os == "Windows": | ||||
| @@ -31,8 +27,6 @@ class loggingRecipe(ConanFile): | ||||
|         if self.options.shared: | ||||
|             self.options.rm_safe("fPIC") | ||||
|  | ||||
|  | ||||
|      | ||||
|     def layout(self): | ||||
|         cmake_layout(self) | ||||
|  | ||||
| @@ -40,18 +34,16 @@ class loggingRecipe(ConanFile): | ||||
|         deps = CMakeDeps(self) | ||||
|         deps.generate() | ||||
|         tc = CMakeToolchain(self) | ||||
|         tc.variables["SKIPTEST"]=True | ||||
|         if self.options.shared: | ||||
|             tc.variables["SHARED"] = True | ||||
|         else: | ||||
|             tc.variables["SHARED"] = False | ||||
|         tc.variables["TEST"] = True if self.options.test else False | ||||
|         tc.variables["SHARED"] = True if self.options.shared else False | ||||
|         tc.generate() | ||||
|  | ||||
|     def build(self): | ||||
|         cmake = CMake(self) | ||||
|         cmake.configure() | ||||
|         cmake.build(target="Logging") | ||||
|  | ||||
|         cmake.build() | ||||
|         if self.options.test: | ||||
|             cmake.test() | ||||
|  | ||||
|     def package(self): | ||||
|         copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) | ||||
| @@ -63,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) | ||||
|  | ||||
|     def package_info(self): | ||||
|         self.cpp_info.libs = ["Logging"] | ||||
|         self.cpp_info.libs = ["logging"] | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 63 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 43 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/img/2024-09-21-11-44-06.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/img/2024-09-21-11-44-06.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 58 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/img/2024-09-21-11-44-25.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/img/2024-09-21-11-44-25.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 47 KiB | 
| @@ -1,87 +1,65 @@ | ||||
| #ifndef __LOGGING_H__ | ||||
| #define __LOGGING_H__ | ||||
|  | ||||
| #ifndef __LOGGING_H | ||||
| #define __LOGGING_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| typedef enum { | ||||
|     LOG_FATAL, | ||||
|     LOG_ERROR, | ||||
|     LOG_WARNING, | ||||
|     LOG_INFO, | ||||
|     LOG_DEBUG, | ||||
| } log_level; | ||||
| #include "logging/logging-core.h" | ||||
| #include "logging/logging-filter.h" | ||||
| #include "logging/logging-handler.h" | ||||
|  | ||||
| typedef enum { | ||||
|     L_ERROR, | ||||
|     L_OK, | ||||
| } log_status; | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef struct log_Handler { | ||||
|     void* stream; | ||||
|     bool apply_color; | ||||
|     void (*_free)(struct log_Handler* handler);//释放资源 | ||||
|     void (*output)(struct log_Handler* handler,const char* message); | ||||
| } log_Handler; | ||||
| #define Log_fatal(format, ...)                                                 \ | ||||
|     log_fatal(__FILE__, __LINE__, format, ##__VA_ARGS__) | ||||
| #define Log_error(format, ...)                                                 \ | ||||
|     log_error(__FILE__, __LINE__, format, ##__VA_ARGS__) | ||||
| #define Log_warning(format, ...)                                               \ | ||||
|     log_warning(__FILE__, __LINE__, format, ##__VA_ARGS__) | ||||
| #define Log_info(format, ...)                                                  \ | ||||
|     log_info(__FILE__, __LINE__, format, ##__VA_ARGS__) | ||||
| #define Log_debug(format, ...)                                                 \ | ||||
|     log_debug(__FILE__, __LINE__, format, ##__VA_ARGS__) | ||||
|  | ||||
|  | ||||
| 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; | ||||
|  | ||||
|  | ||||
| //日志操作器 | ||||
| typedef struct Logger | ||||
| { | ||||
|     log_level level; | ||||
|     log_Handler* handler; | ||||
|     log_Interceptor* interceptor; | ||||
|     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 (*addFormat)(const char* format); | ||||
|     // void (*addFilter)(const char* filter); | ||||
|     void (*addInterceptor)(log_Interceptor* Interceptor); | ||||
| typedef struct Logger { | ||||
|     log_level    level; | ||||
|     log_Handler *handler; | ||||
|     log_filter  *filter; | ||||
|     const char  *name; | ||||
|     bool (*addHandler)(log_Handler *handler); | ||||
|     bool (*addFilter)(log_filter *filter); | ||||
| } Logger; | ||||
|  | ||||
|  | ||||
| //日志类对象 | ||||
| typedef struct Logging { | ||||
|     Logger* (*getLogger)(const char* name, log_level level); | ||||
|     log_status (*setLevel)(Logger* logger, log_level level); | ||||
| } Logging; | ||||
|  | ||||
|  | ||||
|  | ||||
| Logging* createLogging();                         | ||||
| log_status destroyLogging(Logging* logging); | ||||
| Logger* getCurrentLogger(void); | ||||
|  | ||||
| void log_fatal(const char *file, int line, const char *format, ...); | ||||
| void log_error(const char *file, int line, const char *format, ...); | ||||
| void log_warning(const char *file, int line, const char *format, ...); | ||||
| void log_info(const char *file, int line, const char *format, ...); | ||||
| void log_debug(const char *file, int line, const char *format, ...); | ||||
|  | ||||
| /** | ||||
|  * @def 创建日志处理器 | ||||
|  * @file logging-handler.c | ||||
| * @brief | ||||
| 创建默认日志对象,日志对象为单例模式,后续可通过getDefaultLogger方法获取, | ||||
|         重复调用该方法不会创建新的日志对象,只会返回默认日志对象,并且会修改默认日志对象的名称和等级 | ||||
| * @param name 日志名称 | ||||
| * @param level 日志等级 | ||||
| * @return Logger* 日志对象指针 | ||||
| */ | ||||
| log_Handler* fileHandler(const char* name);      | ||||
| log_Handler* consoleHandler(const char* name); | ||||
| Logger *newDefaultLogger(const char *name, log_level level); | ||||
|  | ||||
| /** | ||||
|  * @brief 获取默认日志对象 | ||||
|  */ | ||||
| Logger *getDefaultLogger(void); | ||||
|  | ||||
| /** | ||||
|  * @brief 销毁日志对象,该方法会销毁默认日志对象 | ||||
|  */ | ||||
| log_status destroyDefaultLogger(void); | ||||
|  | ||||
| log_Interceptor* substringInterceptor(char *keywords[], int count, log_level level, log_Handler* handler); | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif // __LOGGING_H | ||||
| #endif // __LOGGING_H__ | ||||
							
								
								
									
										25
									
								
								include/logging/logging-core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								include/logging/logging-core.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #ifndef __LOGGING_CORE_H__ | ||||
| #define __LOGGING_CORE_H__ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef enum { | ||||
|     LOG_FATAL = 0, | ||||
|     LOG_ERROR, | ||||
|     LOG_WARNING, | ||||
|     LOG_INFO, | ||||
|     LOG_DEBUG, | ||||
| } log_level; | ||||
|  | ||||
| typedef enum { | ||||
|     L_ERROR, | ||||
|     L_OK, | ||||
| } log_status; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #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__ | ||||
							
								
								
									
										36
									
								
								include/logging/logging-handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								include/logging/logging-handler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #ifndef __LOGGING_HANDLER_H__ | ||||
| #define __LOGGING_HANDLER_H__ | ||||
|  | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef struct log_Handler { | ||||
|     void *stream; | ||||
|     bool  apply_color; | ||||
|     void (*_free)(struct log_Handler *handler); | ||||
|     void (*output)(struct log_Handler *handler, const char *message); | ||||
| } log_Handler; | ||||
|  | ||||
| /** | ||||
|  * @brief 文件处理器 | ||||
|  * @param name 文件名 | ||||
|  * @param max_size 文件最大大小 | ||||
|  * @return | ||||
|  */ | ||||
| log_Handler *loggingHandlerFile(const char *name, unsigned int max_size); | ||||
|  | ||||
| /** | ||||
|  * @brief 控制台处理器 | ||||
|  * @param | ||||
|  * @return | ||||
|  */ | ||||
| log_Handler *loggingHandlerConsole(); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif //__LOGGING_HANDLER_H__ | ||||
							
								
								
									
										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 ".." | ||||
							
								
								
									
										13
									
								
								src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| project(logging) | ||||
|  | ||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) | ||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/handler SRC) | ||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/filter SRC) | ||||
| aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils SRC) | ||||
|  | ||||
| if (SHARED) | ||||
|     add_library(${PROJECT_NAME} SHARED ${SRC}) | ||||
| else() | ||||
|     add_library(${PROJECT_NAME} ${SRC}) | ||||
| endif() | ||||
|  | ||||
							
								
								
									
										133
									
								
								src/filter/logging-filter-substr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/filter/logging-filter-substr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| #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; | ||||
|     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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/handler/logging-handler-console.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/handler/logging-handler-console.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #include "logging/logging-handler.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| static void __freeHandlerConsole(log_Handler *handler) { free(handler); } | ||||
|  | ||||
| static void __outputHandlerConsole(log_Handler *handler, const char *message) { | ||||
|     fputs(message, handler->stream); | ||||
| } | ||||
|  | ||||
| log_Handler *loggingHandlerConsole() { | ||||
|     log_Handler *handler = (log_Handler *)malloc(sizeof(log_Handler)); | ||||
|  | ||||
|     handler->stream      = stdout; | ||||
|     handler->apply_color = true; | ||||
|     handler->_free       = __freeHandlerConsole; | ||||
|     handler->output      = __outputHandlerConsole; | ||||
|  | ||||
|     return handler; | ||||
| } | ||||
							
								
								
									
										98
									
								
								src/handler/logging-handler-file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/handler/logging-handler-file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| #include "logging/logging-handler.h" | ||||
| #include <stdio.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); | ||||
| } | ||||
|  | ||||
| static void __freeFileHandler(log_Handler *handler) { | ||||
|     fclose(handler->stream); | ||||
|     free(Handler_file_EX_PRT(handler)->file_name); | ||||
|     free(handler); | ||||
| } | ||||
|  | ||||
| static void changeFile(log_Handler *handler) { | ||||
|     log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); | ||||
|     fclose(handler->stream); | ||||
|     char new_file_name[FILE_NAME_MAX_SIZE]; | ||||
|     sprintf(new_file_name, | ||||
|             "%s_%d.log", | ||||
|             handler_ex->file_name, | ||||
|             ++handler_ex->suffix); | ||||
|     handler->stream       = fopen(new_file_name, "at"); | ||||
|     handler_ex->file_size = getFileSize(handler->stream); | ||||
| } | ||||
|  | ||||
| static void outputFileHandler(log_Handler *handler, const char *message) { | ||||
|     fputs(message, handler->stream); | ||||
|     log_Handler_file_ex_t *handler_ex = Handler_file_EX_PRT(handler); | ||||
|     handler_ex->file_size += strlen(message); | ||||
|     if (handler_ex->file_size > handler_ex->file_size_max) | ||||
|         changeFile(handler); | ||||
| } | ||||
|  | ||||
| log_Handler *loggingHandlerFile(const char *name, unsigned int max_size) { | ||||
|     char                   new_file_name[FILE_NAME_MAX_SIZE]; | ||||
|     int                    suffix = 0; | ||||
|     unsigned int           file_size; | ||||
|     FILE                  *fp         = NULL; | ||||
|     log_Handler           *handler    = NULL; | ||||
|     log_Handler_file_ex_t *handler_ex = NULL; | ||||
|  | ||||
|     /// 获取未写满于设置最大文件大小的文件名 | ||||
|     do { | ||||
|         sprintf(new_file_name, "%s_%d.log", name, suffix++); | ||||
|         fp = fopen(new_file_name, "at"); | ||||
|         if (fp == NULL) | ||||
|             goto ERROR; | ||||
|         file_size = getFileSize(fp); | ||||
|     } while (file_size > max_size); | ||||
|  | ||||
|     /// 分配log_Handler与记录文件大小的空间 | ||||
|     handler = (log_Handler *)malloc(sizeof(log_Handler) + | ||||
|                                     sizeof(log_Handler_file_ex_t)); | ||||
|     if (handler == NULL) | ||||
|         goto ERROR; | ||||
|  | ||||
|     handler_ex                = Handler_file_EX_PRT(handler); | ||||
|     handler_ex->file_size_max = max_size; | ||||
|     handler_ex->file_size     = file_size; | ||||
|     handler_ex->suffix        = suffix; | ||||
|     handler_ex->file_name     = strdup(name); | ||||
|     if (handler_ex->file_name == NULL) | ||||
|         goto ERROR; | ||||
|  | ||||
|     handler->stream      = fp; | ||||
|     handler->apply_color = false; | ||||
|     handler->_free       = __freeFileHandler; | ||||
|     handler->output      = outputFileHandler; | ||||
|     return handler; | ||||
|  | ||||
| ERROR: | ||||
|     if (fp) | ||||
|         fclose(fp); | ||||
|     if (handler) { | ||||
|         free(Handler_file_EX_PRT(handler)->file_name); // 直接释放,无需检查NULL | ||||
|         free(handler); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| @@ -1,62 +0,0 @@ | ||||
| /******************************************** | ||||
| * @Date: 2024 08 12 | ||||
| * @Description: 日志处理器 | ||||
| ********************************************/ | ||||
| #include "logging.h" | ||||
|  | ||||
|  | ||||
| /** | ||||
| * @description :释放文件日志处理器相关资源 | ||||
| * @param  | ||||
| * @return  | ||||
| */ | ||||
| static void __freeFileHandler(log_Handler* handler){ | ||||
|     fclose(handler->stream); | ||||
|     free(handler); | ||||
| } | ||||
|  | ||||
| static void outputFileHandler(log_Handler *handler, const char * message){ | ||||
|     fputs(message,handler->stream); | ||||
| } | ||||
|  | ||||
| /** | ||||
| * @description :文件日志处理器 | ||||
| * @param  | ||||
| * @return  | ||||
| */ | ||||
| log_Handler* fileHandler(const char* name){ | ||||
|     char new_file_name[100]; | ||||
|     sprintf(new_file_name, "%s.log", name); | ||||
|     FILE* fp = fopen(new_file_name, "at"); | ||||
|     log_Handler* handler = (log_Handler*)malloc(sizeof(log_Handler)); | ||||
|     handler->stream = fp; | ||||
|     handler->apply_color = false; | ||||
|     handler->_free = __freeFileHandler; | ||||
|     handler->output = outputFileHandler; | ||||
|     return handler; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void __freeConsoleHandler(log_Handler* handler){ | ||||
|     free(handler); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void outputConsoleHandler(log_Handler* handler,const char * message){ | ||||
|     fputs(message,handler->stream); | ||||
| } | ||||
|  | ||||
| /** | ||||
| * @description :控制台日志处理器 | ||||
| * @param  | ||||
| * @return  | ||||
| */ | ||||
| log_Handler* consoleHandler(const char* name){ | ||||
|     log_Handler* handler = (log_Handler*)malloc(sizeof(log_Handler)); | ||||
|     handler->stream = stdout; | ||||
|     handler->apply_color = true; | ||||
|     handler->_free = __freeConsoleHandler; | ||||
|     handler->output = outputConsoleHandler; | ||||
|     return handler; | ||||
| } | ||||
| @@ -1,119 +0,0 @@ | ||||
| /******************************************** | ||||
| * @Date: 2024 08 12 | ||||
| * @Description: 日志拦截器 | ||||
| *********************************************/   | ||||
|  | ||||
| #include "logging.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* substringInterceptor(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; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										385
									
								
								src/logging.c
									
									
									
									
									
								
							
							
						
						
									
										385
									
								
								src/logging.c
									
									
									
									
									
								
							| @@ -1,228 +1,255 @@ | ||||
| /******************************************** | ||||
| * @Date: 2024 08 12 | ||||
| * @Description: 日志模块 | ||||
| ********************************************/ | ||||
|  | ||||
| #include "logging.h" | ||||
| #include "logging/logging-core.h" | ||||
| #include "logging/logging-handler.h" | ||||
| #include "utils/logging-utils.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| Logger* G_LOGGER = NULL; | ||||
|  | ||||
| #define RED "\033[0;31m" | ||||
| #define GREEN "\033[0;32m" | ||||
| #define RED    "\033[0;31m" | ||||
| #define RED_B  "\033[0;41m" | ||||
| #define GREEN  "\033[0;32m" | ||||
| #define YELLOW "\033[0;33m" | ||||
| #define BLUE "\033[0;34m" | ||||
| #define RESET "\033[0m" | ||||
| #define CYAN "\033[0;36m" | ||||
| #define MAGENTA "\033[0;35m" | ||||
| #define WHITE "\033[0;37m" | ||||
| #define BLACK "\033[0;30m" | ||||
| #define BLUE   "\033[0;34m" | ||||
| #define RESET  "\033[0m" | ||||
| #define CYAN   "\033[0;36m" | ||||
|  | ||||
| #define LOG_BUFFER_SIZE 1024 | ||||
| #define LOG_BUFFER_SIZE 4096 // 日志缓冲区大小,单个日志长度不能超过该值 | ||||
|  | ||||
|  | ||||
| static void getTimeStr(char * timeStr){ | ||||
|     time_t t = time(NULL); | ||||
|     struct tm* p = localtime(&t); | ||||
|     char  _timeStr[20]; | ||||
|     strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p); | ||||
|     strcpy(timeStr, _timeStr); | ||||
| } | ||||
| static Logger *G_LOGGER = NULL; // 全局日志对象,唯一实例 | ||||
|  | ||||
| /** | ||||
| * @description : 添加日志处理器 | ||||
| */ | ||||
| static void addHandler(log_Handler* handler){ | ||||
|     if (G_LOGGER == NULL){ | ||||
|         return; | ||||
|  * @brief 为日志添加一个handler | ||||
|  * @param handler 处理器对象 | ||||
|  */ | ||||
| static bool addHandler(log_Handler *handler) { | ||||
|     if (G_LOGGER == NULL || handler == NULL) { | ||||
|         return false; | ||||
|     } | ||||
|     if (G_LOGGER->handler == NULL){ | ||||
|     if (G_LOGGER->handler == NULL) { | ||||
|         G_LOGGER->handler = handler; | ||||
|         return; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     G_LOGGER->handler->_free(G_LOGGER->handler); | ||||
|      | ||||
|     G_LOGGER->handler = handler; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
| * @description : 内置日志记录函数 | ||||
| */ | ||||
| static void _builtin_log(char* level, const char *color, const char* message, ...){ | ||||
|     if (G_LOGGER == NULL){ | ||||
|         return; | ||||
|  * @brief 为日志添加一个filter | ||||
|  * @param filter 过滤器对象 | ||||
|  */ | ||||
| static bool addFilter(log_filter *filter) { | ||||
|     if (G_LOGGER == NULL || filter == NULL) { | ||||
|         return false; | ||||
|     } | ||||
|     if (G_LOGGER->handler == NULL){ | ||||
|         return; | ||||
|     if (G_LOGGER->filter == NULL) { | ||||
|         G_LOGGER->filter       = filter; | ||||
|         G_LOGGER->filter->next = NULL; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     log_filter *it = G_LOGGER->filter; | ||||
|     while (it->next != NULL) { | ||||
|         it = it->next; | ||||
|     } | ||||
|  | ||||
|     it->next     = filter; | ||||
|     filter->next = NULL; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 输出到handler | ||||
|  * @param handler 处理器对象 | ||||
|  * @param level 日志等级 | ||||
|  * @param color 应用的颜色 | ||||
|  * @param message 日志内容 | ||||
|  */ | ||||
| static void output_to_handler(log_Handler *handler, | ||||
|                               char        *level, | ||||
|                               const char  *color, | ||||
|                               const char  *message) { | ||||
|     char timeStr[20]; | ||||
|     getTimeStr(timeStr); | ||||
|     char logStr[LOG_BUFFER_SIZE]; | ||||
|     char logStr[LOG_BUFFER_SIZE * 2]; | ||||
|     if (handler->apply_color) | ||||
|         snprintf(logStr, | ||||
|                  LOG_BUFFER_SIZE * 2, | ||||
|                  "[%s]: %s %s%s%s %s\n", | ||||
|                  G_LOGGER->name, | ||||
|                  timeStr, | ||||
|                  color, | ||||
|                  level, | ||||
|                  RESET, | ||||
|                  message); | ||||
|     else | ||||
|         snprintf(logStr, | ||||
|                  LOG_BUFFER_SIZE * 2, | ||||
|                  "[%s]: %s %s %s\n", | ||||
|                  G_LOGGER->name, | ||||
|                  timeStr, | ||||
|                  level, | ||||
|                  message); | ||||
|  | ||||
|     log_Handler * handler = G_LOGGER->handler; | ||||
|  | ||||
|     //通过拦截器 | ||||
|     if (G_LOGGER->interceptor != NULL){ | ||||
|         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\n", timeStr, color,level,RESET, message); | ||||
|     else sprintf(logStr, "%s %s %s\n", timeStr, level, message); | ||||
|  | ||||
|     handler->output(handler,logStr); | ||||
|     handler->output(handler, logStr); | ||||
| } | ||||
|  | ||||
|  | ||||
| //*************************记录日志******************************* */ | ||||
| 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, logStr, args); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void error(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("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 :获取一个日志操作对象 | ||||
| * @param  | ||||
| * @return  | ||||
| */ | ||||
| static Logger* getLogger(const char* name, log_level level){ | ||||
|     if (G_LOGGER != NULL){ | ||||
|  * @brief 内部日志打印处理核心函数 | ||||
|  * @param level 日志等级 | ||||
|  * @param color 应用的颜色 | ||||
|  * @param message 日志内容 | ||||
|  * @param ... 格式化参数列表 | ||||
|  * @return | ||||
|  */ | ||||
| static void _builtin_cope(log_level   level_e, | ||||
|                           char       *level, | ||||
|                           const char *color, | ||||
|                           const char *message) { | ||||
|     if (G_LOGGER == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     if (G_LOGGER->handler == NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     log_filter  *it      = G_LOGGER->filter; | ||||
|     log_Handler *handler = G_LOGGER->handler; | ||||
|  | ||||
|     while (it != NULL) { | ||||
|         if (it->_dispose(it, level_e, message)) { | ||||
|             output_to_handler(it->handler, level, color, message); | ||||
|             if (it->jump_out) | ||||
|                 return; | ||||
|         } | ||||
|         it = it->next; | ||||
|     } | ||||
|     output_to_handler(handler, level, color, message); | ||||
| } | ||||
|  | ||||
| void log_fatal(const char *file, int line, const char *message, ...) { | ||||
|     if (G_LOGGER->level >= LOG_ERROR) { | ||||
|         char    logStr[LOG_BUFFER_SIZE]; | ||||
|         char    finalLogStr[LOG_BUFFER_SIZE * 2]; | ||||
|         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); | ||||
|         _builtin_cope(LOG_FATAL, "Fatal", RED_B, finalLogStr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void log_error(const char *file, int line, const char *message, ...) { | ||||
|     if (G_LOGGER->level >= LOG_ERROR) { | ||||
|         char    logStr[LOG_BUFFER_SIZE]; | ||||
|         char    finalLogStr[LOG_BUFFER_SIZE * 2]; | ||||
|         va_list args; | ||||
|         va_start(args, message); | ||||
|         vsprintf(logStr, message, args); | ||||
|         va_end(args); | ||||
|         snprintf( | ||||
|             finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); | ||||
|         _builtin_cope(LOG_ERROR, "Error", RED, finalLogStr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void log_warning(const char *file, int line, const char *message, ...) { | ||||
|     if (G_LOGGER->level >= LOG_WARNING) { | ||||
|         char    logStr[LOG_BUFFER_SIZE]; | ||||
|         char    finalLogStr[LOG_BUFFER_SIZE * 2]; | ||||
|         va_list args; | ||||
|         va_start(args, message); | ||||
|         vsprintf(logStr, message, args); | ||||
|         va_end(args); | ||||
|         snprintf( | ||||
|             finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); | ||||
|         _builtin_cope(LOG_WARNING, "Warning", YELLOW, finalLogStr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void log_info(const char *file, int line, const char *message, ...) { | ||||
|     if (G_LOGGER->level >= LOG_INFO) { | ||||
|         char    logStr[LOG_BUFFER_SIZE]; | ||||
|         char    finalLogStr[LOG_BUFFER_SIZE * 2]; | ||||
|         va_list args; | ||||
|         va_start(args, message); | ||||
|         vsprintf(logStr, message, args); | ||||
|         va_end(args); | ||||
|         snprintf( | ||||
|             finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); | ||||
|         _builtin_cope(LOG_INFO, "Info", GREEN, finalLogStr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void log_debug(const char *file, int line, const char *message, ...) { | ||||
|     if (G_LOGGER->level >= LOG_DEBUG) { | ||||
|         char    logStr[LOG_BUFFER_SIZE]; | ||||
|         char    finalLogStr[LOG_BUFFER_SIZE * 2]; | ||||
|         va_list args; | ||||
|         va_start(args, message); | ||||
|         vsprintf(logStr, message, args); | ||||
|         va_end(args); | ||||
|         snprintf( | ||||
|             finalLogStr, LOG_BUFFER_SIZE * 2, "[%s:%d] %s", file, line, logStr); | ||||
|         _builtin_cope(LOG_DEBUG, "Debug", CYAN, finalLogStr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| Logger *newDefaultLogger(const char *name, log_level level) { | ||||
|     if (G_LOGGER != NULL) { | ||||
|         G_LOGGER->name  = name; | ||||
|         G_LOGGER->level = level; | ||||
|         return G_LOGGER; | ||||
|     } | ||||
|     Logger* logger = (Logger*)malloc(sizeof(Logger)); | ||||
|     logger->fatal = fatal; | ||||
|     logger->error = error; | ||||
|     logger->warning = warning; | ||||
|     logger->info = info; | ||||
|     logger->debug = debug; | ||||
|  | ||||
|     Logger *logger     = (Logger *)malloc(sizeof(Logger)); | ||||
|  | ||||
|     logger->addHandler = addHandler; | ||||
|     logger->addInterceptor = addInterceptor; | ||||
|     logger->addFilter  = addFilter; | ||||
|  | ||||
|     logger->level = level; | ||||
|     logger->handler = NULL; | ||||
|     logger->name = name; | ||||
|     logger->interceptor = NULL; | ||||
|     logger->level      = level; | ||||
|     logger->handler    = loggingHandlerConsole(); | ||||
|     logger->name       = name; | ||||
|     logger->filter     = NULL; | ||||
|  | ||||
|     G_LOGGER = logger; | ||||
|     G_LOGGER           = logger; | ||||
|     return G_LOGGER; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
| * @description :创建一个日志对象 | ||||
| * @return :Logging* 返回一个日志对象 | ||||
| */ | ||||
| Logging* createLogging(){ | ||||
|     Logging* logging = (Logging*)malloc(sizeof(Logging)); | ||||
|     logging->getLogger = getLogger; | ||||
|     return logging; | ||||
| } | ||||
|  | ||||
| /** | ||||
| * @description :销毁日志对象 | ||||
| */ | ||||
| log_status destroyLogging(Logging* logging){ | ||||
|     if (logging == NULL){ | ||||
|         return L_ERROR; | ||||
|     } | ||||
|     if (G_LOGGER != NULL){ | ||||
|         if (G_LOGGER->handler != NULL){ | ||||
|  * @brief 销毁日志对象 | ||||
|  */ | ||||
| log_status destroyDefaultLogger(void) { | ||||
|     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); | ||||
|         if (G_LOGGER->filter != NULL) { | ||||
|             log_filter *it   = G_LOGGER->filter; | ||||
|             log_filter *next = NULL; | ||||
|             while (it != NULL) { | ||||
|                 next = it->next; | ||||
|                 it->_free(it); | ||||
|                 it = next; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         free(G_LOGGER); | ||||
|         G_LOGGER = NULL; | ||||
|     } | ||||
|     free(logging); | ||||
|     return L_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
| * @description :获取当前日志操作对象 | ||||
| * @return 当前唯一的日志操作对象 | ||||
| */ | ||||
| Logger* getCurrentLogger(void){ | ||||
|     if (G_LOGGER == NULL){ | ||||
| Logger *getDefaultLogger(void) { | ||||
|     if (G_LOGGER == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     return G_LOGGER; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										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,29 +0,0 @@ | ||||
| #include "logging.h" | ||||
|  | ||||
| int main() { | ||||
|     Logging *log = createLogging(); | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); | ||||
|     logger->addHandler(consoleHandler("test")); | ||||
|  | ||||
|     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 = substringInterceptor(test1,2,LOG_DEBUG,fileHandler("被拦截"));  | ||||
|     logger->addInterceptor(tint); | ||||
|     printf("Interceptor added\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"); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     return 0; | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| #include "logging.h" | ||||
|  | ||||
|  | ||||
| int main() { | ||||
|     Logging *log = createLogging(); | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); | ||||
|     logger->addHandler(consoleHandler("test")); | ||||
|  | ||||
|     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"); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										30
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| project(test) | ||||
|  | ||||
| enable_testing() | ||||
|  | ||||
| #测试简单基本应用 | ||||
| add_executable(${PROJECT_NAME}simple test-simple.c) | ||||
| target_link_libraries(${PROJECT_NAME}simple logging) | ||||
| if(UNIX) | ||||
|     add_test(test_simple ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}simple) | ||||
| elseif(WIN32) | ||||
|     add_test(test_simple ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}simple.exe) | ||||
| endif() | ||||
|  | ||||
| #测试简单基本应用 | ||||
| add_executable(${PROJECT_NAME}file test-log-file.c) | ||||
| target_link_libraries(${PROJECT_NAME}file logging) | ||||
| if(UNIX) | ||||
|     add_test(test_file ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}file) | ||||
| elseif(WIN32) | ||||
|     add_test(test_file ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}file.exe) | ||||
| endif() | ||||
|  | ||||
| #测试拦截器 | ||||
| add_executable(${PROJECT_NAME}filter test-filter.c) | ||||
| target_link_libraries(${PROJECT_NAME}filter logging) | ||||
| if(UNIX) | ||||
|     add_test(test_filter ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}filter) | ||||
| elseif(WIN32) | ||||
|     add_test(test_filter ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}filter.exe) | ||||
| endif() | ||||
							
								
								
									
										49
									
								
								tests/test-filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								tests/test-filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #include "logging.h" | ||||
| #include "logging/logging-core.h" | ||||
| #include "logging/logging-filter.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <time.h> | ||||
|  | ||||
| int main() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     Log_info("This is an info message"); | ||||
|     Log_error("This is an error message%s", "123"); | ||||
|     Log_fatal("This is an fatal message"); | ||||
|     Log_debug("This is a debug message"); | ||||
|     Log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     char *test1[] = {"This", NULL}; | ||||
|  | ||||
|     log_filter *tint = | ||||
|         loggingFilterSubStr(test1, | ||||
|                             LOG_DEBUG, | ||||
|                             loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|                             false); | ||||
|  | ||||
|     logger->addFilter(tint); | ||||
|  | ||||
|     char *test2[]     = {"123", NULL}; | ||||
|  | ||||
|     log_filter *tint1 = loggingFilterSubStr( | ||||
|         test2, | ||||
|         LOG_ERROR, | ||||
|         loggingHandlerFile("test_interceptor1", 1024 * 1024), | ||||
|         true); | ||||
|  | ||||
|     logger->addFilter(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; | ||||
| } | ||||
							
								
								
									
										17
									
								
								tests/test-log-file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tests/test-log-file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #include "logging.h" | ||||
| #include "logging/logging-handler.h" | ||||
|  | ||||
| int main() { | ||||
|     Logger      *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|     log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); | ||||
|     logger->addHandler(hander); | ||||
|  | ||||
|     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; | ||||
| } | ||||
							
								
								
									
										14
									
								
								tests/test-simple.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/test-simple.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #include "logging.h" | ||||
|  | ||||
| int main() { | ||||
|     Logger *logger = newDefaultLogger("testLogger", LOG_DEBUG); | ||||
|  | ||||
|     Log_info("This is an info message"); | ||||
|     Log_error("This is an error message%s", "123"); | ||||
|     Log_fatal("This is an fatal message"); | ||||
|     Log_debug("This is a debug message"); | ||||
|     Log_warning("This is a warning message%s", "123"); | ||||
|  | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user