Compare commits
	
		
			71 Commits
		
	
	
		
			0c96f67b47
			...
			dev
		
	
	| 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 | |||
|  | 86cf4c4526 | ||
| 9963f68175 | |||
| 85ae9d3deb | |||
|  | 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 | ||||
| ... | ||||
|  | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,4 @@ | ||||
|  | ||||
| .cache | ||||
| .vscode/** | ||||
| bin | ||||
| build | ||||
| CMakeUserPresets.json | ||||
|   | ||||
							
								
								
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 3.12 | ||||
| @@ -1,25 +1,33 @@ | ||||
| cmake_minimum_required( VERSION 3.28) | ||||
| cmake_minimum_required(VERSION 3.28...3.30) | ||||
|  | ||||
| project(Logging) | ||||
| project(logging) | ||||
|  | ||||
| set(CMAKE_C_STANDARD 99) | ||||
| set(CMAKE_C_CLANG_TIDY "clang-tidy") | ||||
|  | ||||
| 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}) | ||||
| #编译库文件 | ||||
| add_subdirectory(src) | ||||
|  | ||||
| #测试单元 | ||||
| if (TEST) | ||||
|     enable_testing() | ||||
|     add_subdirectory(tests) | ||||
| endif() | ||||
|  | ||||
| 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}) | ||||
| 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; | ||||
| } | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										139
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| # C语言日志库logging | ||||
|  | ||||
| [English](README.en.md) | ||||
|  | ||||
| ## 简介 | ||||
|  | ||||
| logging是一个轻量级的简单易用C语言日志库,支持日志级别、日志格式、日志输出、日志文件等功能。 | ||||
| @@ -9,28 +11,49 @@ 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(); // 创建日志对象 | ||||
|     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 *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); | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
| @@ -38,64 +61,76 @@ 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->addHandler(consoleHandler("test"));   //为日志对象添加文件处理器 | ||||
|     log_Handler *hander = loggingHandlerFile("test_log", 1024 * 1024 * 10); | ||||
|     addHandler(getDefaultLogger(), hander); | ||||
|  | ||||
|     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"); | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     destroyDefaultLogger(); | ||||
|     return 0; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### 日志拦截器 | ||||
| > 支持添加自定义的拦截器, 目前内置了子串拦截器 | ||||
| ### 日志过滤器 | ||||
| > 支持添加自定义的过滤器, 目前内置了子串过滤器 | ||||
|  | ||||
| > 拦截器的作用:可以将拦截到的日志重定向到拦截器的专属处理器中 | ||||
| > 过滤器的作用:可以将过滤到的日志重定向到过滤器的专属处理器中 | ||||
|  | ||||
|  | ||||
| #### 例子 | ||||
| 将拦截到的日志重定向到专属文件处理器中 | ||||
| #### 多个子串过滤器 | ||||
| ```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() { | ||||
|     Logging *log = createLogging(); | ||||
|     Logger *logger = log->getLogger("testLogger",LOG_DEBUG); | ||||
|     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"); | ||||
|     char *test1[] = {"This", NULL}; | ||||
|  | ||||
|     char *test1[] = {"123", "你好"};//要拦截的字符串 | ||||
|     //添加拦截器,将拦截到的日志重定向到拦截器的专属处理器中 | ||||
|     log_Interceptor * tint = substringInterceptor(test1,2,LOG_DEBUG,fileHandler("被拦截"));  | ||||
|     logger->addInterceptor(tint); | ||||
|     printf("Interceptor added\n"); | ||||
|     log_filter *tint = | ||||
|         loggingFilterSubStr(test1, | ||||
|                             LOG_DEBUG, | ||||
|                             loggingHandlerFile("test_interceptor", 1024 * 1024), | ||||
|                             false); | ||||
|  | ||||
|     logger->info("This is an info message"); | ||||
|     logger->error("你好,这是一个错误消息%s", "123"); | ||||
|     logger->fatal("This is an fatal message"); | ||||
|     addFilter(getDefaultLogger(), tint); | ||||
|  | ||||
|     logger->debug("This is a debug message"); | ||||
|     logger->warning("This is a warning message%s", "123"); | ||||
|     char *test2[]     = {"123", NULL}; | ||||
|  | ||||
|     destroyLogging(log); | ||||
|     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; | ||||
| } | ||||
| ``` | ||||
| .png) | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										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 = "1.0.0" | ||||
|     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,87 @@ | ||||
| #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> | ||||
| #include <stddef.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, ...)                                                 \ | ||||
|     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 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; | ||||
| } Logger; | ||||
|  | ||||
| bool addHandler(Logger *logger, log_Handler *handler); | ||||
| bool addFilter(Logger *logger, log_filter *filter); | ||||
|  | ||||
| //日志类对象 | ||||
| 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 logMessage(Logger     *logger, | ||||
|                 log_level   level, | ||||
|                 const char *file, | ||||
|                 int         line, | ||||
|                 const char *message, | ||||
|                 ...); | ||||
|  | ||||
| /** | ||||
|  * @def 创建日志处理器 | ||||
|  * @file logging-handler.c | ||||
| */ | ||||
| log_Handler* fileHandler(const char* name);      | ||||
| log_Handler* consoleHandler(const char* name); | ||||
|  * @brief 创建一个日志句柄对象 | ||||
|  * @param name 日志器名称 | ||||
|  * @return 日志句柄对象 | ||||
|  */ | ||||
| Logger *newLogger(const char *name); | ||||
| /** | ||||
|  * @brief 获取默认日志对象 | ||||
|  * @return 默认日志对象 | ||||
|  */ | ||||
| Logger *getDefaultLogger(void); | ||||
|  | ||||
| Logger *getLogger(const char *name); | ||||
|  | ||||
| /** | ||||
|  * @brief 销毁日志对象,该方法会销毁默认日志对象 | ||||
|  */ | ||||
| void destroyDefaultLogger(void); | ||||
|  | ||||
| log_Interceptor* substringInterceptor(char *keywords[], int count, log_level level, log_Handler* handler); | ||||
| /** | ||||
|  * @brief 销毁日志对象 | ||||
|  * @param logger 日志对象 | ||||
|  * @return void | ||||
|  */ | ||||
| void destroyLogger(Logger *logger); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif // __LOGGING_H | ||||
| #endif // __LOGGING_H__ | ||||
							
								
								
									
										33
									
								
								include/logging/logging-core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								include/logging/logging-core.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #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; | ||||
|  | ||||
| static const char *LOG_LEVEL_STR[] = { | ||||
|     "FATAL", | ||||
|     "ERROR", | ||||
|     "WARNING", | ||||
|     "INFO", | ||||
|     "DEBUG", | ||||
| }; | ||||
|  | ||||
| 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 file_name 文件名 | ||||
|  * @param max_size 文件最大大小 | ||||
|  * @return | ||||
|  */ | ||||
| log_Handler *loggingHandlerFile(const char *file_name, unsigned int max_size); | ||||
|  | ||||
| /** | ||||
|  * @brief 控制台处理器 | ||||
|  * @param | ||||
|  * @return | ||||
|  */ | ||||
| log_Handler *loggingHandlerConsole(); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif //__LOGGING_HANDLER_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 ".." | ||||
							
								
								
									
										14
									
								
								src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| 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() | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										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; | ||||
| } | ||||
							
								
								
									
										103
									
								
								src/handler/logging-handler-file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/handler/logging-handler-file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| #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 *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; | ||||
|  | ||||
|     /// 获取未写满于设置最大文件大小的文件名 | ||||
|     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->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; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										448
									
								
								src/logging.c
									
									
									
									
									
								
							
							
						
						
									
										448
									
								
								src/logging.c
									
									
									
									
									
								
							| @@ -1,228 +1,292 @@ | ||||
| /******************************************** | ||||
| * @Date: 2024 08 12 | ||||
| * @Description: 日志模块 | ||||
| ********************************************/ | ||||
|  | ||||
| #include "logging.h" | ||||
| #include "logging/logging-core.h" | ||||
| #include "logging/logging-handler.h" | ||||
| #include "utils/logging-map.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 Logger *ROOT_LOGGER = NULL; // 根日志对象,唯一实例 | ||||
|  | ||||
| static void getTimeStr(char * timeStr){ | ||||
|     time_t t = time(NULL); | ||||
|     struct tm* p = localtime(&t); | ||||
|     char  _timeStr[20]; | ||||
|     strftime(_timeStr, sizeof(_timeStr), "%Y-%m-%d %H:%M:%S", p); | ||||
|     strcpy(timeStr, _timeStr); | ||||
| static Map *LOGGER_MAP     = NULL; // 日志对象映射表 | ||||
|  | ||||
| /** | ||||
|  * @brief 为日志添加一个handler | ||||
|  * @param handler 处理器对象 | ||||
|  */ | ||||
| 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 : 添加日志处理器 | ||||
| */ | ||||
| static void addHandler(log_Handler* handler){ | ||||
|     if (G_LOGGER == NULL){ | ||||
|         return; | ||||
|  * @brief 为日志添加一个filter | ||||
|  * @param filter 过滤器对象 | ||||
|  */ | ||||
| bool addFilter(Logger *logger, log_filter *filter) { | ||||
|     if (logger == NULL || filter == NULL) { | ||||
|         return false; | ||||
|     } | ||||
|     if (G_LOGGER->handler == NULL){ | ||||
|         G_LOGGER->handler = handler; | ||||
|         return; | ||||
|     if (logger->filter == NULL) { | ||||
|         logger->filter       = filter; | ||||
|         logger->filter->next = NULL; | ||||
|         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; | ||||
|     log_filter *it = logger->filter; | ||||
|     while (it->next != NULL) { | ||||
|         it = it->next; | ||||
|     } | ||||
|  | ||||
|     G_LOGGER->interceptor->_free(G_LOGGER->interceptor); | ||||
|  | ||||
|     G_LOGGER->interceptor = Interceptor; | ||||
|     it->next     = filter; | ||||
|     filter->next = NULL; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
| * @description : 内置日志记录函数 | ||||
| */ | ||||
| static void _builtin_log(char* level, const char *color, const char* message, ...){ | ||||
|     if (G_LOGGER == NULL){ | ||||
|         return; | ||||
|     } | ||||
|     if (G_LOGGER->handler == NULL){ | ||||
|         return; | ||||
|     } | ||||
|  * @brief 输出到handler | ||||
|  * @param handler 处理器对象 | ||||
|  * @param level 日志等级 | ||||
|  * @param color 应用的颜色 | ||||
|  * @param message 日志内容 | ||||
|  */ | ||||
| /** | ||||
|  * @brief 输出到handler | ||||
|  * @param handler 处理器对象 | ||||
|  * @param level 日志等级 | ||||
|  * @param color 应用的颜色 | ||||
|  * @param message 日志内容 | ||||
|  */ | ||||
| static void output_to_handler(Logger     *logger, | ||||
|                               char       *level, | ||||
|                               const char *color, | ||||
|                               const char *message) { | ||||
|  | ||||
|     char timeStr[20]; | ||||
|     getTimeStr(timeStr); | ||||
|     char logStr[LOG_BUFFER_SIZE]; | ||||
|     char logStr[LOG_BUFFER_SIZE * 2]; | ||||
|     if (logger->handler->apply_color) { | ||||
|         snprintf(logStr, | ||||
|                  LOG_BUFFER_SIZE * 2, | ||||
|                  "[%s]: %s %s%s%s %s\n", | ||||
|                  logger->name, | ||||
|                  timeStr, | ||||
|                  color, | ||||
|                  level, | ||||
|                  RESET, | ||||
|                  message); | ||||
|     } else { | ||||
|         snprintf(logStr, | ||||
|                  LOG_BUFFER_SIZE * 2, | ||||
|                  "[%s]: %s %s %s\n", | ||||
|                  logger->name, | ||||
|                  timeStr, | ||||
|                  level, | ||||
|                  message); | ||||
|     } | ||||
|  | ||||
|     log_Handler * handler = G_LOGGER->handler; | ||||
|     logger->handler->output(logger->handler, logStr); | ||||
| } | ||||
|  | ||||
|     //通过拦截器 | ||||
|     if (G_LOGGER->interceptor != NULL){ | ||||
|         if(G_LOGGER->interceptor->_dispose(level,message)){ | ||||
|             if(G_LOGGER->interceptor->handler != NULL){ | ||||
|                 handler = G_LOGGER->interceptor->handler; | ||||
| /** | ||||
|  * @brief 内部日志打印处理核心函数 | ||||
|  * @param level 日志等级 | ||||
|  * @param color 应用的颜色 | ||||
|  * @param message 日志内容 | ||||
|  * @param ... 格式化参数列表 | ||||
|  * @return | ||||
|  */ | ||||
| static void | ||||
| log_cope(Logger *logger, char *level, const char *color, const char *message) { | ||||
|     if (logger == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|     //判断处理器是否应用颜色 | ||||
|     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); | ||||
|     output_to_handler(logger, level, color, 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, 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){ | ||||
|         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->addHandler = addHandler; | ||||
|     logger->addInterceptor = addInterceptor; | ||||
|  | ||||
|     logger->level = level; | ||||
|     logger->handler = NULL; | ||||
|     logger->name = name; | ||||
|     logger->interceptor = NULL; | ||||
|  | ||||
|     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){ | ||||
|             G_LOGGER->handler->_free(G_LOGGER->handler); | ||||
| 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; | ||||
|         } | ||||
|  | ||||
|         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){ | ||||
|  * @brief 创建一个日志句柄 | ||||
|  * @param name 日志器名称 | ||||
|  * @return 日志器对象 | ||||
|  */ | ||||
| Logger *newLogger(const char *name) { | ||||
|     Logger *logger = (Logger *)malloc(sizeof(Logger)); | ||||
|     if (logger == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     return G_LOGGER; | ||||
|  | ||||
|     if (LOGGER_MAP == NULL) { | ||||
|         LOGGER_MAP = map_create(sizeof(Logger **)); | ||||
|     } | ||||
|  | ||||
|     logger->level   = LOG_INFO; | ||||
|     logger->handler = loggingHandlerConsole(); | ||||
|     logger->name    = name; | ||||
|     logger->filter  = NULL; | ||||
|  | ||||
|     map_put(LOGGER_MAP, name, &logger); | ||||
|  | ||||
|     return logger; | ||||
| } | ||||
|  | ||||
| Logger *getDefaultLogger(void) { | ||||
|     if (ROOT_LOGGER != NULL) { | ||||
|         return ROOT_LOGGER; | ||||
|     } | ||||
|  | ||||
|     ROOT_LOGGER = newLogger("ROOT"); | ||||
|     return ROOT_LOGGER; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 获取日志器对象 | ||||
|  * @param name 日志器名称 | ||||
|  * @param level 日志等级 | ||||
|  * @return 日志器对象 | ||||
|  */ | ||||
| Logger *getLogger(const char *name) { | ||||
|     if (name == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (LOGGER_MAP == NULL) { | ||||
|         LOGGER_MAP = map_create(sizeof(Logger **)); | ||||
|     } | ||||
|  | ||||
|     Logger **cache_logger_ptr = (Logger **)map_get(LOGGER_MAP, name); | ||||
|     if (cache_logger_ptr != NULL) { | ||||
|         return *cache_logger_ptr; | ||||
|     } | ||||
|  | ||||
|     Logger *logger  = (Logger *)malloc(sizeof(Logger)); | ||||
|  | ||||
|     logger->level   = LOG_INFO; | ||||
|     logger->handler = loggingHandlerConsole(); | ||||
|     logger->name    = name; | ||||
|     logger->filter  = NULL; | ||||
|  | ||||
|     map_put(LOGGER_MAP, name, &logger); | ||||
|  | ||||
|     return logger; | ||||
| } | ||||
|  | ||||
| void destroyLogger(Logger *logger) { | ||||
|     if (logger != NULL) { | ||||
|         if (logger->handler != NULL) { | ||||
|             logger->handler->_free(logger->handler); | ||||
|         } | ||||
|  | ||||
|         if (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); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief 销毁日志对象 | ||||
|  */ | ||||
| void destroyDefaultLogger(void) { | ||||
|     map_foreach(LOGGER_MAP, __destroyLoggerForeach, NULL); | ||||
|     map_destroy(LOGGER_MAP); | ||||
| } | ||||
							
								
								
									
										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,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; | ||||
| } | ||||
							
								
								
									
										31
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| project(test) | ||||
|  | ||||
| enable_testing() | ||||
|  | ||||
| include_directories(${CMAKE_SOURCE_DIR}/src) | ||||
|  | ||||
| #测试简单基本应用 | ||||
| add_executable(${PROJECT_NAME}simple test-simple.c) | ||||
| target_link_libraries(${PROJECT_NAME}simple logging) | ||||
| 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}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; | ||||
| } | ||||
							
								
								
									
										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