├── .clang-format ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── Qml.qrc ├── Qml ├── FPSItem.qml └── main.qml ├── README.md ├── Src ├── Logger.cpp ├── Logger.h ├── LoggerTemplate.h └── main.cpp ├── TaoLogger.pro ├── appveyor.yml └── scripts ├── macos ├── build.sh └── install.sh └── ubuntu ├── build.sh └── install.sh /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: AlwaysBreak 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlines: Right 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: Empty 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: false 19 | AlwaysBreakTemplateDeclarations: Yes 20 | BinPackArguments: false 21 | BinPackParameters: false 22 | BraceWrapping: 23 | AfterClass: true 24 | AfterControlStatement: true 25 | AfterEnum: true 26 | AfterFunction: true 27 | AfterNamespace: true 28 | AfterObjCDeclaration: true 29 | AfterStruct: true 30 | AfterUnion: false 31 | AfterExternBlock: true 32 | BeforeCatch: true 33 | BeforeElse: true 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: All 39 | BreakBeforeBraces: Allman 40 | BreakBeforeInheritanceComma: false 41 | BreakInheritanceList: BeforeColon 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakConstructorInitializers: BeforeComma 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 160 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: false 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 65 | Priority: 2 66 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 67 | Priority: 3 68 | - Regex: '.*' 69 | Priority: 1 70 | IncludeIsMainRegex: '(Test)?$' 71 | IndentCaseLabels: true 72 | IndentPPDirectives: None 73 | IndentWidth: 4 74 | IndentWrappedFunctionNames: false 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepLineBreaksForNonEmptyLines: false 78 | KeepEmptyLinesAtTheStartOfBlocks: true 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: Inner 83 | ObjCBinPackProtocolList: Auto 84 | ObjCBlockIndentWidth: 4 85 | ObjCSpaceAfterProperty: true 86 | ObjCSpaceBeforeProtocolList: true 87 | PenaltyBreakAssignment: 2 88 | PenaltyBreakBeforeFirstCallParameter: 19 89 | PenaltyBreakComment: 300 90 | PenaltyBreakFirstLessLess: 120 91 | PenaltyBreakString: 1000 92 | PenaltyBreakTemplateDeclaration: 10 93 | PenaltyExcessCharacter: 1000000 94 | PenaltyReturnTypeOnItsOwnLine: 60 95 | PointerAlignment: Right 96 | ReflowComments: true 97 | SortIncludes: true 98 | SortUsingDeclarations: true 99 | SpaceAfterCStyleCast: false 100 | SpaceAfterTemplateKeyword: true 101 | SpaceBeforeAssignmentOperators: true 102 | SpaceBeforeCpp11BracedList: false 103 | SpaceBeforeCtorInitializerColon: true 104 | SpaceBeforeInheritanceColon: true 105 | SpaceBeforeParens: ControlStatements 106 | SpaceBeforeRangeBasedForLoopColon: true 107 | SpaceInEmptyParentheses: false 108 | SpacesBeforeTrailingComments: 1 109 | SpacesInAngles: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | TabWidth: 4 116 | UseTab: Never 117 | ... 118 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | build/ 5 | run/ 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | *.VC.db 87 | *.VC.VC.opendb 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | *.sap 94 | 95 | # TFS 2012 Local Workspace 96 | $tf/ 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | *.DotSettings.user 105 | 106 | # JustCode is a .NET coding add-in 107 | .JustCode 108 | 109 | # TeamCity is a build add-in 110 | _TeamCity* 111 | 112 | # DotCover is a Code Coverage Tool 113 | *.dotCover 114 | 115 | # NCrunch 116 | _NCrunch_* 117 | .*crunch*.local.xml 118 | nCrunchTemp_* 119 | 120 | # MightyMoose 121 | *.mm.* 122 | AutoTest.Net/ 123 | 124 | # Web workbench (sass) 125 | .sass-cache/ 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.[Pp]ublish.xml 145 | *.azurePubxml 146 | # TODO: Comment the next line if you want to checkin your web deploy settings 147 | # but database connection strings (with potential passwords) will be unencrypted 148 | #*.pubxml 149 | *.publishproj 150 | 151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 152 | # checkin your Azure Web App publish settings, but sensitive information contained 153 | # in these scripts will be unencrypted 154 | PublishScripts/ 155 | 156 | # NuGet Packages 157 | *.nupkg 158 | # The packages folder can be ignored because of Package Restore 159 | **/packages/* 160 | # except build/, which is used as an MSBuild target. 161 | !**/packages/build/ 162 | # Uncomment if necessary however generally it will be regenerated when needed 163 | #!**/packages/repositories.config 164 | # NuGet v3's project.json files produces more ignoreable files 165 | *.nuget.props 166 | *.nuget.targets 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Windows Store app package directories and files 177 | AppPackages/ 178 | BundleArtifacts/ 179 | Package.StoreAssociation.xml 180 | _pkginfo.txt 181 | 182 | # Visual Studio cache files 183 | # files ending in .cache can be ignored 184 | *.[Cc]ache 185 | # but keep track of directories ending in .cache 186 | !*.[Cc]ache/ 187 | 188 | # Others 189 | ClientBin/ 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.jfm 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | 258 | # CodeRush 259 | .cr/ 260 | 261 | # Python Tools for Visual Studio (PTVS) 262 | __pycache__/ 263 | *.pyc 264 | /.vscode/settings.json 265 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | compiler: gcc 4 | env: QT_BASE="512" 5 | matrix: 6 | include: 7 | - os: linux 8 | dist: xenial 9 | cache: 10 | apt: true 11 | directories: 12 | - /opt/qt512/ 13 | - os: osx 14 | osx_image: xcode10.2 15 | 16 | group: deprecated-2019Q1 17 | before_install: 18 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then chmod a+x ./scripts/macos/install.sh; ./scripts/macos/install.sh; fi 19 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod a+x ./scripts/ubuntu/install.sh; ./scripts/ubuntu/install.sh; fi 20 | script: 21 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then chmod a+x ./scripts/macos/build.sh; ./scripts/macos/build.sh; fi 22 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod a+x ./scripts/ubuntu/build.sh; ./scripts/ubuntu/build.sh; fi 23 | notifications: 24 | email: false 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 贾文涛 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Qml/main.qml 4 | Qml/FPSItem.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /Qml/FPSItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | Item { 4 | id: fpsRoot 5 | property int fps: 60 6 | property int frameCount: 0 7 | property bool running: true 8 | 9 | Rectangle { 10 | width: 32 11 | height: 32 12 | color: "red" 13 | RotationAnimation on rotation { 14 | from: 0 15 | to: 360 16 | running: true 17 | loops: Animation.Infinite 18 | duration: 1000 19 | } 20 | onRotationChanged: frameCount++ 21 | } 22 | Timer { 23 | interval: 1000 24 | repeat: true 25 | running: fpsRoot.running 26 | onRunningChanged: { 27 | if (running) { 28 | fps = 60 29 | frameCount = 0 30 | } 31 | } 32 | onTriggered: { 33 | fps = frameCount 34 | frameCount = 0 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | Item { 4 | Text { 5 | text: "TaoLogger " + fpsItem.fps + " fps" 6 | anchors.centerIn: parent 7 | } 8 | FPSItem { 9 | id: fpsItem 10 | } 11 | Button { 12 | y: 100 13 | text: "log" 14 | onClicked: { 15 | console.log("Clicked") 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TaoLogger 2 | 3 | ## 简介 4 | 5 | Qt制作的简易、好看的Log系统 6 | 7 | 代码量极少 8 | 9 | 麻雀虽小五脏俱全 10 | 11 | ![预览](https://jaredtao.github.io/images/Logger/1.png) 12 | 13 | ## status 14 | | [Ubuntu/MacOS][lin-link] | [Windows][win-link] |[License][license-link] | 15 | | :---------------: | :-----------------: | :-----------------: | 16 | | ![lin-badge] | ![win-badge] | ![license-badge] | 17 | 18 | [lin-badge]: https://travis-ci.org/jaredtao/TaoLogger.svg?branch=master "Travis build status" 19 | [lin-link]: https://travis-ci.org/jaredtao/TaoLogger "Travis build status" 20 | [win-badge]: https://ci.appveyor.com/api/projects/status/biawnp5xfulvkwbw?svg=true "AppVeyor build status" 21 | [win-link]: https://ci.appveyor.com/project/jiawentao/taologger "AppVeyor build status" 22 | [license-link]: https://github.com/jaredtao/TaoLogger/blob/master/LICENSE "LICENSE" 23 | [license-badge]: https://img.shields.io/badge/license-MIT-blue.svg "MIT" 24 | 25 | ## 使用 26 | 27 | 源代码拷过去,在main函数的QCoreApplication/QApplication构造之后,调用一下init函数就行了。 28 | 29 | 例如: 30 | ```C++ 31 | #include "TaoLogger.h" 32 | //省略其它头文件 33 | ... 34 | ... 35 | int main(int argc, char *argv[]) 36 | { 37 | QApplication app(argc, argv); 38 | initLog(); 39 | ... 40 | return app.exec(); 41 | } 42 | ``` 43 | 44 | initLog函数的定义如下: 45 | ``` 46 | void initLog(const QString &logPath = QStringLiteral("Log"), int logMaxCount = 1024, bool async = true); 47 | ``` 48 | 其中logPath为log存储路径,默认为Log文件夹。 49 | 50 | logMaxCount最大文件数,默认为1024。 51 | 52 | async为异步存储,默认为true。 53 | 54 | ## 开发环境 55 | 56 | * Qt 5.9.x Windows 57 | 58 | ## 原理 59 | 详细的说明看我博客: 60 | [Qt自制简易好看的日志系统](https://jaredtao.github.io/2019/04/30/Qt%E8%87%AA%E5%88%B6%E7%AE%80%E6%98%93%E5%A5%BD%E7%9C%8B%E7%9A%84%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/) 61 | 62 | 63 | 64 | ### 联系方式: 65 | 66 | *** 67 | 68 | | 作者 | 涛哥 | 69 | | ---- | -------------------------------- | 70 | | QQ | 759378563 | 71 | | 微信 | xsd2410421 | 72 | | 邮箱 | jared2020@163.com | 73 | | blog | https://jaredtao.github.io | 74 | 75 | *** 76 | 77 | QQ(TIM)、微信二维码 78 | 79 | 80 | 81 | 82 | ###### 请放心联系我,乐于提供咨询服务,也可洽谈有偿技术支持相关事宜。 83 | 84 | *** 85 | #### **打赏** 86 | 87 | 88 | ###### 觉得分享的内容还不错, 就请作者喝杯奶茶吧~~ 89 | *** 90 | -------------------------------------------------------------------------------- /Src/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | #include "LoggerTemplate.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #ifdef Q_OS_WIN 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | namespace Logger 19 | { 20 | static QString gLogDir; 21 | static int gLogMaxCount; 22 | 23 | static void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg); 24 | static void outputMessageAsync(QtMsgType type, const QMessageLogContext& context, const QString& msg); 25 | 26 | void initLog(const QString &logPath, int logMaxCount, bool async) 27 | { 28 | if (async) 29 | { 30 | qInstallMessageHandler(outputMessageAsync); 31 | } 32 | else 33 | { 34 | qInstallMessageHandler(outputMessage); 35 | } 36 | 37 | gLogDir = QCoreApplication::applicationDirPath() + "/" + logPath; 38 | gLogMaxCount = logMaxCount; 39 | QDir dir(gLogDir); 40 | if (!dir.exists()) 41 | { 42 | dir.mkpath(dir.absolutePath()); 43 | } 44 | QStringList infoList = dir.entryList(QDir::Files, QDir::Name); 45 | while (infoList.size() > gLogMaxCount) 46 | { 47 | dir.remove(infoList.first()); 48 | infoList.removeFirst(); 49 | } 50 | } 51 | static void outputMessageAsync(QtMsgType type, const QMessageLogContext &context, const QString &msg) 52 | { 53 | static const QString messageTemp = QString("
%2
\r\n"); 54 | static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' }; 55 | static QMutex mutex; 56 | static QFile file; 57 | static QTextStream textStream; 58 | static uint count = 0; 59 | static const uint maxCount = 512; 60 | Q_UNUSED(context); 61 | QDateTime dt = QDateTime::currentDateTime(); 62 | //每小时一个文件 63 | QString fileNameDt = dt.toString("yyyy-MM-dd_hh"); 64 | 65 | //每分钟一个文件 66 | //QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm"); 67 | 68 | QString contentDt = dt.toString("yyyy-MM-dd hh:mm:ss"); 69 | QString message = QString("%1 %2").arg(contentDt).arg(msg); 70 | QString htmlMessage = messageTemp.arg(typeList[static_cast(type)]).arg(message); 71 | QString newfileName = QString("%1/%2_log.html").arg(gLogDir).arg(fileNameDt); 72 | mutex.lock(); 73 | if (file.fileName() != newfileName) 74 | { 75 | if (file.isOpen()) 76 | { 77 | file.close(); 78 | } 79 | file.setFileName(newfileName); 80 | bool exist = file.exists(); 81 | file.open(QIODevice::WriteOnly | QIODevice::Append); 82 | textStream.setDevice(&file); 83 | textStream.setCodec("UTF-8"); 84 | if (!exist) 85 | { 86 | textStream << logTemplate << "\r\n"; 87 | } 88 | } 89 | textStream << htmlMessage; 90 | textStream.flush(); 91 | count += static_cast(htmlMessage.length()); 92 | if (count >= maxCount) 93 | { 94 | file.close(); 95 | file.open(QIODevice::WriteOnly | QIODevice::Append); 96 | } 97 | mutex.unlock(); 98 | #ifdef Q_OS_WIN 99 | ::OutputDebugString(message.toStdWString().data()); 100 | ::OutputDebugString(L"\r\n"); 101 | #else 102 | fprintf(stderr, message.toStdString().data()); 103 | #endif 104 | } 105 | static void outputMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg) 106 | { 107 | static const QString messageTemp = QString("
%2
\r\n"); 108 | static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' }; 109 | static QMutex mutex; 110 | 111 | Q_UNUSED(context); 112 | QDateTime dt = QDateTime::currentDateTime(); 113 | 114 | //每小时一个文件 115 | QString fileNameDt = dt.toString("yyyy-MM-dd_hh"); 116 | 117 | //每分钟一个文件 118 | //QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm"); 119 | 120 | QString contentDt = dt.toString("yyyy-MM-dd hh:mm:ss"); 121 | QString message = QString("%1 %2").arg(contentDt).arg(msg); 122 | QString htmlMessage = messageTemp.arg(typeList[static_cast(type)]).arg(message); 123 | QFile file(QString("%1/%2_log.html").arg(gLogDir).arg(fileNameDt)); 124 | mutex.lock(); 125 | 126 | bool exist = file.exists(); 127 | file.open(QIODevice::WriteOnly | QIODevice::Append); 128 | QTextStream textStream(&file); 129 | textStream.setCodec("UTF-8"); 130 | if (!exist) 131 | { 132 | textStream << logTemplate << "\r\n"; 133 | } 134 | textStream << htmlMessage; 135 | file.close(); 136 | mutex.unlock(); 137 | #ifdef Q_OS_WIN 138 | ::OutputDebugString(message.toStdWString().data()); 139 | ::OutputDebugString(L"\r\n"); 140 | #else 141 | fprintf(stderr, message.toStdString().data()); 142 | #endif 143 | } 144 | } // namespace Logger 145 | -------------------------------------------------------------------------------- /Src/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Logger 5 | { 6 | 7 | #define LOG_DEBUG qDebug() << __FILE__ << __FUNCTION__ << __LINE__ 8 | #define LOG_INFO qInfo() << __FILE__ << __FUNCTION__ << __LINE__ 9 | #define LOG_WARN qWarning() << __FILE__ << __FUNCTION__ << __LINE__ 10 | #define LOG_CRIT qCritical() << __FILE__ << __FUNCTION__ << __LINE__ 11 | 12 | void initLog(const QString &logPath = QStringLiteral("Log"), int logMaxCount = 1024, bool async = true); 13 | 14 | } // namespace Logger 15 | -------------------------------------------------------------------------------- /Src/LoggerTemplate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | namespace Logger 5 | { 6 | const static QString logTemplate = u8R"logTemplate( 7 | 8 | 9 | 10 | 11 | 12 | TaoLogger 13 | 14 | 86 | 87 | 88 | 89 |

TaoLogger 日志文件

90 | 117 | 125 | )logTemplate"; 126 | } 127 | -------------------------------------------------------------------------------- /Src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace Logger; 15 | using namespace std; 16 | const int N = 7; 17 | 18 | //原子计数器。不要用普通的int,多线程情况下不准确。 19 | static atomic_int gCount(0); 20 | static QString currentThreadId() 21 | { 22 | 23 | stringstream ss; 24 | ss << this_thread::get_id(); 25 | return QString::fromStdString(ss.str()); 26 | } 27 | //输出log的函数,随便打印一点信息 28 | static void showSomeLogger() 29 | { 30 | //在文件本身的编码是utf-8的前提下,以下三种方式都可以直接输出中文。 31 | //u8是c++11标准支持的字符串字面量写法,可以参考https://zh.cppreference.com/w/cpp/language/string_literal 32 | //QStringLiteral是Qt特有的宏,用来在编译期生成字符串字面量 33 | //QString::fromLocal8Bit可以在运行过程中,动态处理中文字符串。 34 | for (int i = 0; i < 1000; ++i) 35 | { 36 | gCount++; 37 | int count = gCount; 38 | LOG_DEBUG << currentThreadId() << u8"山有木兮木有枝,心悦君兮君不知。"; 39 | LOG_DEBUG << currentThreadId() << QStringLiteral("黄河远上白云间,一片孤城万仞山。"); 40 | LOG_DEBUG << currentThreadId() << QString::fromLocal8Bit("人生若只如初见,何事秋风悲画扇。"); 41 | LOG_INFO << currentThreadId() << u8"玲珑骰子安红豆,入骨相思知不知。"; 42 | LOG_WARN << currentThreadId() << u8"此情可待成追忆,只是当时已惘然。"; 43 | LOG_CRIT << currentThreadId() << u8"严重的事情发生了,股票跌了!" << count; 44 | qApp->processEvents(); 45 | } 46 | } 47 | static void logThread() 48 | { 49 | vector threads; 50 | 51 | //创建N个线程 52 | for (unsigned long long i = 0; i < N; ++i) { 53 | threads.emplace_back(thread(showSomeLogger)); 54 | } 55 | 56 | //join,等线程结束。 57 | for (unsigned long long i = 0; i < N; ++i) 58 | { 59 | threads[i].join(); 60 | } 61 | LOG_INFO << currentThreadId() << u8"故事到这就结束了,总共输出log" << gCount; 62 | 63 | } 64 | int main(int argc, char *argv[]) 65 | { 66 | QGuiApplication app(argc, argv); 67 | //app创建之后,调一下initLog就行了 68 | initLog(); 69 | 70 | LOG_INFO << currentThreadId() << u8"故事就是从这里开始的"; 71 | QQuickView view; 72 | view.setResizeMode(QQuickView::SizeRootObjectToView); 73 | view.resize(800, 600); 74 | view.setSource(QUrl(QStringLiteral("qrc:/Qml/main.qml"))); 75 | view.show(); 76 | // //延迟创建 logger 77 | QTimer::singleShot(2000, [&](){ 78 | std::thread logger(logThread); 79 | logger.detach(); 80 | 81 | }); 82 | app.exec(); 83 | } 84 | -------------------------------------------------------------------------------- /TaoLogger.pro: -------------------------------------------------------------------------------- 1 | QT += quick 2 | CONFIG += c++11 console 3 | 4 | # The following define makes your compiler emit warnings if you use 5 | # any Qt feature that has been marked deprecated (the exact warnings 6 | # depend on your compiler). Refer to the documentation for the 7 | # deprecated API to know how to port your code away from it. 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | 10 | # You can also make your code fail to compile if it uses deprecated APIs. 11 | # In order to do so, uncomment the following line. 12 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 13 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 14 | 15 | HEADERS += \ 16 | Src/Logger.h \ 17 | Src/LoggerTemplate.h 18 | 19 | SOURCES += \ 20 | Src/Logger.cpp \ 21 | Src/main.cpp 22 | 23 | RESOURCES += Qml.qrc 24 | 25 | # Additional import path used to resolve QML modules in Qt Creator's code model 26 | QML_IMPORT_PATH = 27 | 28 | # Additional import path used to resolve QML modules just for Qt Quick Designer 29 | QML_DESIGNER_IMPORT_PATH = 30 | 31 | OTHER_FILES += README.md \ 32 | .clang-format \ 33 | LICENSE \ 34 | appveyor.yml \ 35 | .travis.yml 36 | macos { 37 | OTHER_FILES += \ 38 | scripts/macos/install.sh \ 39 | scripts/macos/build.sh 40 | } 41 | 42 | linux { 43 | OTHER_FILES += \ 44 | scripts/ubuntu/install.sh \ 45 | scripts/ubuntu/build.sh \ 46 | } 47 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build{build} 2 | 3 | branches: 4 | except: 5 | - project/travis 6 | 7 | environment: 8 | matrix: 9 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 10 | platform: x86 11 | qt: 5.9 12 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 13 | platform: x64 14 | qt: 5.9 15 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 16 | platform: x64 17 | qt: 5.9 18 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 19 | platform: x64 20 | qt: 5.12 21 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 22 | platform: x64 23 | qt: 5.12 24 | before_build: 25 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set msvc=msvc2015 26 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set vs=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC 27 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set msvc=msvc2017 28 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set vs=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build 29 | - if "%platform%"=="x86" set QTDIR=C:\Qt\%qt%\%msvc% 30 | - if "%platform%"=="x64" set QTDIR=C:\Qt\%qt%\%msvc%_64 31 | - set PATH=%PATH%;%QTDIR%\bin; 32 | - if "%platform%"=="x86" set vcvarsall=%vs%\vcvarsall.bat 33 | - if "%platform%"=="x64" set vcvarsall=%vs%\vcvarsall.bat 34 | - if "%platform%"=="x86" call "%vcvarsall%" x86 35 | - if "%platform%"=="x64" call "%vcvarsall%" x64 36 | build_script: 37 | - qmake 38 | - nmake 39 | -------------------------------------------------------------------------------- /scripts/macos/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | /usr/local/opt/qt/bin/qmake 3 | make 4 | -------------------------------------------------------------------------------- /scripts/macos/install.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | brew update 3 | brew install qt 4 | -------------------------------------------------------------------------------- /scripts/ubuntu/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | source /opt/qt512/bin/qt512-env.sh 3 | qmake 4 | make -j$(nproc) -------------------------------------------------------------------------------- /scripts/ubuntu/install.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | sudo add-apt-repository ppa:beineri/opt-qt-5.12.3-xenial -y 3 | sudo apt-get update -qq 4 | sudo apt-get install -y libglew-dev libglfw3-dev 5 | sudo apt-get install -y qt512-meta-minimal 6 | 7 | --------------------------------------------------------------------------------