{"id":13418417,"url":"https://github.com/SergiusTheBest/plog","last_synced_at":"2025-03-15T03:31:09.286Z","repository":{"id":23996487,"uuid":"27380078","full_name":"SergiusTheBest/plog","owner":"SergiusTheBest","description":"Portable, simple and extensible C++ logging library","archived":false,"fork":false,"pushed_at":"2024-06-29T09:21:51.000Z","size":711,"stargazers_count":2210,"open_issues_count":56,"forks_count":391,"subscribers_count":68,"default_branch":"master","last_synced_at":"2024-10-29T15:03:23.635Z","etag":null,"topics":["c-plus-plus","cross-platform","header-only","library","log","logger","logging"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SergiusTheBest.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-01T13:11:47.000Z","updated_at":"2024-10-27T14:59:57.000Z","dependencies_parsed_at":"2023-02-19T10:31:12.121Z","dependency_job_id":"3064ab7d-5685-487d-a262-2dc19c775609","html_url":"https://github.com/SergiusTheBest/plog","commit_stats":{"total_commits":538,"total_committers":34,"mean_commits":"15.823529411764707","dds":0.0985130111524164,"last_synced_commit":"348785326a9e248d25853ff34f624e132c8e43ab"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergiusTheBest%2Fplog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergiusTheBest%2Fplog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergiusTheBest%2Fplog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SergiusTheBest%2Fplog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SergiusTheBest","download_url":"https://codeload.github.com/SergiusTheBest/plog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243681024,"owners_count":20330152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","cross-platform","header-only","library","log","logger","logging"],"created_at":"2024-07-30T22:01:02.061Z","updated_at":"2025-03-15T03:31:06.804Z","avatar_url":"https://github.com/SergiusTheBest.png","language":"C++","readme":"# Plog - portable, simple and extensible C++ logging library\nPretty powerful logging library in about 1000 lines of code [![CI](https://github.com/SergiusTheBest/plog/actions/workflows/ci.yml/badge.svg)](https://github.com/SergiusTheBest/plog/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/rna5gwhqjb13wovr/branch/master?svg=true)](https://ci.appveyor.com/project/SergiusTheBest/plog/branch/master) [![CircleCI](https://circleci.com/gh/SergiusTheBest/plog.svg?style=svg)](https://circleci.com/gh/SergiusTheBest/plog) [![Build Status](https://api.cirrus-ci.com/github/SergiusTheBest/plog.svg)](https://cirrus-ci.com/github/SergiusTheBest/plog)\n\n![image](doc/color-console.png)\n\n- [Introduction](#introduction)\n  - [Hello log!](#hello-log)\n  - [Features](#features)\n- [Usage](#usage)\n  - [Step 1: Adding includes](#step-1-adding-includes)\n  - [Step 2: Initialization](#step-2-initialization)\n  - [Step 3: Logging](#step-3-logging)\n    - [Basic logging macros](#basic-logging-macros)\n    - [Conditional logging macros](#conditional-logging-macros)\n    - [Logger severity checker](#logger-severity-checker)\n- [Advanced usage](#advanced-usage)\n  - [Changing severity at runtime](#changing-severity-at-runtime)\n  - [Custom initialization](#custom-initialization)\n  - [Multiple appenders](#multiple-appenders)\n  - [Multiple loggers](#multiple-loggers)\n  - [Share log instances across modules (exe, dll, so, dylib)](#share-log-instances-across-modules-exe-dll-so-dylib)\n  - [Chained loggers](#chained-loggers)\n- [Architecture](#architecture)\n  - [Overview](#overview)\n  - [Logger](#logger)\n  - [Record](#record)\n  - [Formatter](#formatter)\n    - [TxtFormatter](#txtformatter)\n    - [TxtFormatterUtcTime](#txtformatterutctime)\n    - [CsvFormatter](#csvformatter)\n    - [CsvFormatterUtcTime](#csvformatterutctime)\n    - [FuncMessageFormatter](#funcmessageformatter)\n    - [MessageOnlyFormatter](#messageonlyformatter)\n  - [Converter](#converter)\n    - [UTF8Converter](#utf8converter)\n    - [NativeEOLConverter](#nativeeolconverter)\n  - [Appender](#appender)\n    - [RollingFileAppender](#rollingfileappender)\n    - [ConsoleAppender](#consoleappender)\n    - [ColorConsoleAppender](#colorconsoleappender)\n    - [AndroidAppender](#androidappender)\n    - [EventLogAppender](#eventlogappender)\n    - [DebugOutputAppender](#debugoutputappender)\n    - [DynamicAppender](#dynamicappender)\n- [Miscellaneous notes](#miscellaneous-notes)\n  - [Lazy stream evaluation](#lazy-stream-evaluation)\n  - [Stream improvements over std::ostream](#stream-improvements-over-stdostream)\n  - [Automatic 'this' pointer capture](#automatic-this-pointer-capture)\n  - [Headers to include](#headers-to-include)\n  - [Unicode](#unicode)\n  - [Wide string support](#wide-string-support)\n  - [Performance](#performance)\n  - [Printf style formatting](#printf-style-formatting)\n  - [LOG_XXX macro name clashes](#log_xxx-macro-name-clashes)\n  - [Disable logging to reduce binary size](#disable-logging-to-reduce-binary-size)\n- [Extending](#extending)\n  - [Custom data type](#custom-data-type)\n  - [Custom appender](#custom-appender)\n  - [Custom formatter](#custom-formatter)\n  - [Custom converter](#custom-converter)\n- [Samples](#samples)\n- [References](#references)\n  - [Competing C++ log libraries](#competing-c-log-libraries)\n  - [Tools and useful info](#tools-and-useful-info)\n- [License](#license)\n- [Version history](#version-history)\n\n# Introduction\n\n## Hello log!\nPlog is a C++ logging library that is designed to be as simple, small and flexible as possible. It is created as an alternative to existing large libraries and provides some unique features as [CSV log format]((#csvformatter)) and [wide string support](#wide-string-support).\n\nHere is a minimal hello log sample:\n\n```cpp\n#include \u003cplog/Log.h\u003e // Step1: include the headers\n#include \"plog/Initializers/RollingFileInitializer.h\"\n\nint main()\n{\n    plog::init(plog::debug, \"Hello.txt\"); // Step2: initialize the logger\n\n    // Step3: write log messages using a special macro\n    // There are several log macros, use the macro you liked the most\n\n    PLOGD \u003c\u003c \"Hello log!\"; // short macro\n    PLOG_DEBUG \u003c\u003c \"Hello log!\"; // long macro\n    PLOG(plog::debug) \u003c\u003c \"Hello log!\"; // function-style macro\n    \n    // Also you can use LOG_XXX macro but it may clash with other logging libraries\n    LOGD \u003c\u003c \"Hello log!\"; // short macro\n    LOG_DEBUG \u003c\u003c \"Hello log!\"; // long macro\n    LOG(plog::debug) \u003c\u003c \"Hello log!\"; // function-style macro\n\n    return 0;\n}\n```\n\nAnd its output:\n\n```\n2015-05-18 23:12:43.921 DEBUG [21428] [main@13] Hello log!\n2015-05-18 23:12:43.968 DEBUG [21428] [main@14] Hello log!\n2015-05-18 23:12:43.968 DEBUG [21428] [main@15] Hello log!\n```\n\n## Features\n- Very small (slightly more than 1000 LOC)\n- Easy to use\n- Headers only\n- No 3rd-party dependencies\n- Cross-platform: Windows, Linux, FreeBSD, macOS, Android, RTEMS (gcc, clang, msvc, mingw, mingw-w64, icc, c++builder)\n- Thread and type safe\n- Formatters: [TXT](#txtformatter), [CSV](#csvformatter), [FuncMessage](#funcmessageformatter), [MessageOnly](#messageonlyformatter)\n- Appenders: [RollingFile](#rollingfileappender), [Console](#consoleappender), [ColorConsole](#colorconsoleappender), [Android](#androidappender), [EventLog](#eventlogappender), [DebugOutput](#debugoutputappender), [DynamicAppender](#dynamicappender)\n- [Automatic 'this' pointer capture](#automatic-this-pointer-capture) (supported only on msvc)\n- [Lazy stream evaluation](#lazy-stream-evaluation)\n- [Unicode aware](#unicode), files are stored in UTF-8, supports [Utf8Everywhere](http://utf8everywhere.org)\n- Doesn't require C++11\n- [Extendable](#extending)\n- No `windows.h` dependency\n- Can use UTC or local time\n- Can print buffers in HEX or ASCII\n- Can print `std` containers\n- Uses modern CMake\n\n# Usage\nTo start using plog you need to make 3 simple steps.\n\n## Step 1: Adding includes\nAt first your project needs to know about plog. For that you have to:\n\n1. Add `plog/include` to the project include paths\n2. Add `#include \u003cplog/Log.h\u003e` into your cpp/h files (if you have precompiled headers it is a good place to add this include there)\n\n## Step 2: Initialization\nThe next step is to initialize the [Logger](#logger). This is done by the following `plog::init` function:\n\n```cpp\nLogger\u0026 init(Severity maxSeverity, const char/wchar_t* fileName, size_t maxFileSize = 0, int maxFiles = 0);\n```\n\n`maxSeverity` is the logger severity upper limit. All log messages have its own severity and if it is higher than the limit those messages are dropped. Plog defines the following severity levels:\n\n```cpp\nenum Severity\n{\n    none = 0,\n    fatal = 1,\n    error = 2,\n    warning = 3,\n    info = 4,\n    debug = 5,\n    verbose = 6\n};\n```\n\n\u003e **Note** Messages with severity level `none` will always be printed.\n\nThe log format is determined automatically by `fileName` file extension:\n\n- .csv =\u003e [CSV format](#csvformatter)\n- anything else =\u003e [TXT format](#txtformatter)\n\nThe rolling behavior is controlled by `maxFileSize` and `maxFiles` parameters:\n\n- `maxFileSize` - the maximum log file size in bytes\n- `maxFiles` - a number of log files to keep\n\nIf one of them is zero then log rolling is disabled.\n\nSample:\n\n```cpp\nplog::init(plog::warning, \"c:\\\\logs\\\\log.csv\", 1000000, 5);\n```\n\nHere the logger is initialized to write all messages with up to warning severity to a file in csv format. Maximum log file size is set to 1'000'000 bytes and 5 log files are kept.\n\n\u003e **Note** See [Custom initialization](#custom-initialization) for advanced usage.\n\n## Step 3: Logging\nLogging is performed with the help of special macros. A log message is constructed using stream output operators `\u003c\u003c`. Thus it is type-safe and extendable in contrast to a format string output.\n\n### Basic logging macros\nThis is the most used type of logging macros. They do unconditional logging.\n\n#### Long macros:\n\n```cpp\nPLOG_VERBOSE \u003c\u003c \"verbose\";\nPLOG_DEBUG \u003c\u003c \"debug\";\nPLOG_INFO \u003c\u003c \"info\";\nPLOG_WARNING \u003c\u003c \"warning\";\nPLOG_ERROR \u003c\u003c \"error\";\nPLOG_FATAL \u003c\u003c \"fatal\";\nPLOG_NONE \u003c\u003c \"none\";\n```\n\n#### Short macros:\n\n```cpp\nPLOGV \u003c\u003c \"verbose\";\nPLOGD \u003c\u003c \"debug\";\nPLOGI \u003c\u003c \"info\";\nPLOGW \u003c\u003c \"warning\";\nPLOGE \u003c\u003c \"error\";\nPLOGF \u003c\u003c \"fatal\";\nPLOGN \u003c\u003c \"none\";\n```\n\n#### Function-style macros:\n\n```cpp\nPLOG(severity) \u003c\u003c \"msg\";\n```\n\n### Conditional logging macros\nThese macros are used to do conditional logging. They accept a condition as a parameter and perform logging if the condition is true.\n\n#### Long macros:\n\n```cpp\nPLOG_VERBOSE_IF(cond) \u003c\u003c \"verbose\";\nPLOG_DEBUG_IF(cond) \u003c\u003c \"debug\";\nPLOG_INFO_IF(cond) \u003c\u003c \"info\";\nPLOG_WARNING_IF(cond) \u003c\u003c \"warning\";\nPLOG_ERROR_IF(cond) \u003c\u003c \"error\";\nPLOG_FATAL_IF(cond) \u003c\u003c \"fatal\";\nPLOG_NONE_IF(cond) \u003c\u003c \"none\";\n```\n\n#### Short macros:\n\n```cpp\nPLOGV_IF(cond) \u003c\u003c \"verbose\";\nPLOGD_IF(cond) \u003c\u003c \"debug\";\nPLOGI_IF(cond) \u003c\u003c \"info\";\nPLOGW_IF(cond) \u003c\u003c \"warning\";\nPLOGE_IF(cond) \u003c\u003c \"error\";\nPLOGF_IF(cond) \u003c\u003c \"fatal\";\nPLOGN_IF(cond) \u003c\u003c \"none\";\n```\n\n#### Function-style macros:\n\n```cpp\nPLOG_IF(severity, cond) \u003c\u003c \"msg\";\n```\n\n### Logger severity checker\nIn some cases there is a need to perform a group of actions depending on the current logger severity level. There is a special macro for that. It helps to minimize performance penalty when the logger is inactive.\n\n```cpp\nIF_PLOG(severity)\n```\n\nSample:\n\n```cpp\nIF_PLOG(plog::debug) // we want to execute the following statements only at debug severity (and higher)\n{\n    for (int i = 0; i \u003c vec.size(); ++i)\n    {\n        PLOGD \u003c\u003c \"vec[\" \u003c\u003c i \u003c\u003c \"]: \" \u003c\u003c vec[i];\n    }\n}\n```\n\n# Advanced usage\n\n## Changing severity at runtime\nIt is possible to set the maximum severity not only at the logger initialization time but at any time later. There are special accessor methods:\n\n```cpp\nSeverity Logger::getMaxSeverity() const;\nLogger::setMaxSeverity(Severity severity);\n```\n\nTo get the logger use `plog::get` function:\n\n```cpp\nLogger* get();\n```\n\nSample:\n\n```cpp\nplog::get()-\u003esetMaxSeverity(plog::debug);\n```\n\n## Custom initialization\nNon-typical log cases require the use of custom initialization. It is done by the following `plog::init` function:\n\n```cpp\nLogger\u0026 init(Severity maxSeverity = none, IAppender* appender = NULL);\n```\n\nYou have to construct an [Appender](#appender) parameterized with a [Formatter](#formatter) and pass it to the `plog::init` function.\n\n\u003e **Note** The appender lifetime should be static!\n\nSample:\n\n```cpp\nstatic plog::ConsoleAppender\u003cplog::TxtFormatter\u003e consoleAppender;\nplog::init(plog::debug, \u0026consoleAppender);\n```\n\n## Multiple appenders\nIt is possible to have multiple [Appenders](#appender) within a single [Logger](#logger). In such case log message will be written to all of them. Use the following method to accomplish that:\n\n```cpp\nLogger\u0026 Logger::addAppender(IAppender* appender);\n```\n\nSample:\n\n```cpp\nstatic plog::RollingFileAppender\u003cplog::CsvFormatter\u003e fileAppender(\"MultiAppender.csv\", 8000, 3); // Create the 1st appender.\nstatic plog::ConsoleAppender\u003cplog::TxtFormatter\u003e consoleAppender; // Create the 2nd appender.\nplog::init(plog::debug, \u0026fileAppender).addAppender(\u0026consoleAppender); // Initialize the logger with the both appenders.\n```\n\nHere the logger is initialized in the way when log messages are written to both a file and a console.\n\n*Refer to [MultiAppender](samples/MultiAppender) for a complete sample.*\n\n## Multiple loggers\nMultiple [Loggers](#logger) can be used simultaneously each with their own separate configuration. The [Loggers](#logger) differ by their instanceId (that is implemented as a template parameter). The default instanceId is zero. Initialization is done by the appropriate template `plog::init` functions:\n\n```cpp\nLogger\u003cinstanceId\u003e\u0026 init\u003cinstanceId\u003e(...);\n```\n\nTo get a logger use `plog::get` function (returns `NULL` if the logger is not initialized):\n\n```cpp\nLogger\u003cinstanceId\u003e* get\u003cinstanceId\u003e();\n```\n\nAll logging macros have their special versions that accept an instanceId parameter. These kind of macros have an underscore at the end:\n\n```cpp\nPLOGD_(instanceId) \u003c\u003c \"debug\";\nPLOGD_IF_(instanceId, condition) \u003c\u003c \"conditional debug\";\nIF_PLOG_(instanceId, severity)\n```\n\nSample:\n\n```cpp\nenum // Define log instanceIds. Default is 0 and is omitted from this enum.\n{\n    SecondLog = 1\n};\n\nint main()\n{\n    plog::init(plog::debug, \"MultiInstance-default.txt\"); // Initialize the default logger instance.\n    plog::init\u003cSecondLog\u003e(plog::debug, \"MultiInstance-second.txt\"); // Initialize the 2nd logger instance.\n\n    // Write some messages to the default log.\n    PLOGD \u003c\u003c \"Hello default log!\";\n\n    // Write some messages to the 2nd log.\n    PLOGD_(SecondLog) \u003c\u003c \"Hello second log!\";\n\n    return 0;\n}\n```\n\n*Refer to [MultiInstance](samples/MultiInstance) for a complete sample.*\n\n## Share log instances across modules (exe, dll, so, dylib)\nFor applications that consist of several binary modules, plog instances can be local (each module has its own instance) or shared (all modules use the same instance). In case of shared you have to initialize plog only in one module, other modules will reuse that instance.\n\nSharing behavior is controlled by the following macros and is OS-dependent:\n\n|Macro|OS|Behavior|\n|--|--|--|\n|PLOG_GLOBAL|Linux/Unix|Shared|\n|PLOG_LOCAL|Linux/Unix|Local|\n|PLOG_EXPORT|Linux/Unix|n/a|\n|PLOG_IMPORT|Linux/Unix|n/a|\n|\u003cdefault\u003e|Linux/Unix|According to compiler settings|\n|PLOG_GLOBAL|Windows|n/a|\n|PLOG_LOCAL|Windows|Local|\n|PLOG_EXPORT|Windows|Shared (exports)|\n|PLOG_IMPORT|Windows|Shared (imports)|\n|\u003cdefault\u003e|Windows|Local|\n\nFor sharing on Windows one module should use `PLOG_EXPORT` and others should use `PLOG_IMPORT`. Also be careful on Linux/Unix: if you don't specify sharing behavior it will be determined by compiler settings (`-fvisibility`).\n\n*Refer to [Shared](samples/Shared) for a complete sample.*\n\n## Chained loggers\nA [Logger](#logger) can work as an [Appender](#appender) for another [Logger](#logger). So you can chain several loggers together. This is useful for streaming log messages from a shared library to the main application binary.\n\n*Important: don't forget to specify `PLOG_LOCAL` sharing mode on Linux/Unix systems for this sample.*\n\nSample:\n\n```cpp\n// shared library\n\n// Function that initializes the logger in the shared library.\nextern \"C\" void EXPORT initialize(plog::Severity severity, plog::IAppender* appender)\n{\n    plog::init(severity, appender); // Initialize the shared library logger.\n}\n\n// Function that produces a log message.\nextern \"C\" void EXPORT foo()\n{\n    PLOGI \u003c\u003c \"Hello from shared lib!\";\n}\n```\n\n```cpp\n// main app\n\n// Functions imported from the shared library.\nextern \"C\" void initialize(plog::Severity severity, plog::IAppender* appender);\nextern \"C\" void foo();\n\nint main()\n{\n    plog::init(plog::debug, \"ChainedApp.txt\"); // Initialize the main logger.\n\n    PLOGD \u003c\u003c \"Hello from app!\"; // Write a log message.\n\n    initialize(plog::debug, plog::get()); // Initialize the logger in the shared library. Note that it has its own severity.\n    foo(); // Call a function from the shared library that produces a log message.\n\n    return 0;\n}\n```\n\n*Refer to [Chained](samples/Chained) for a complete sample.*\n\n# Architecture\n\n## Overview\nPlog is designed to be small but flexible, so it prefers templates to interface inheritance. All main entities are shown on the following UML diagram:\n\n```mermaid\nclassDiagram\n\nclass Logger~instanceId~ {\n    \u003c\u003csingleton\u003e\u003e\n    +addAppender()\n    +getMaxSeverity()\n    +setMaxSeverity()\n    +checkSeverity()\n    -maxSeverity\n    -appenders\n}\n\nclass IAppender {\n    \u003c\u003cinterface\u003e\u003e\n    +write()\n}\n\nLogger --|\u003e IAppender\nLogger \"1\" o-- \"*\" IAppender\n\nIAppender \u003c|-- RollingFileAppender~Formatter, Converter~\nIAppender \u003c|-- ConsoleAppender~Formatter~\nIAppender \u003c|-- AndroidAppender~Formatter~\nIAppender \u003c|-- EventLogAppender~Formatter~\nIAppender \u003c|-- DebugOutputAppender~Formatter~\nIAppender \u003c|-- DynamicAppender\n\nConsoleAppender \u003c|-- ColorConsoleAppender~Formatter~\n\nDynamicAppender \"1\" o-- \"*\" IAppender\n```\n    \n```mermaid    \nclassDiagram\n\nclass Severity {\n    \u003c\u003cenumeration\u003e\u003e\n    none,\n    fatal,\n    error,\n    warning,\n    info,\n    debug,\n    verbose\n}\n\nclass Record {\n    +operator\u003c\u003c()\n    +printf()\n    -time\n    -severity\n    -tid\n    -object\n    -line\n    -message\n    -func\n    -file\n    -instanceId\n}    \n```\n\n```mermaid\nclassDiagram\n\nclass CsvFormatter {\n    +header()$\n    +format()$\n}\n\nclass TxtFormatter {\n    +header()$\n    +format()$\n}\n\nclass FuncMessageFormatter {\n    +header()$\n    +format()$\n}\n\nclass MessageOnlyFormatter {\n    +header()$\n    +format()$\n}\n```\n\n```mermaid\nclassDiagram\n\nclass UTF8Converter {\n    +header()$\n    +convert()$\n}\n\nclass NativeEOLConverter~NextConverter~{\n    +header()$\n    +convert()$\n}\n```\n\nThere are 5 functional parts:\n\n- [Logger](#logger) - the main object, implemented as singleton\n- [Record](#record) - keeps log data: time, message, etc\n- [Appender](#appender) - represents a log data destination: file, console, etc\n- [Formatter](#formatter) - formats log data into a string\n- [Converter](#converter) - converts formatter output into a raw buffer\n\nThe log data flow is shown below:\n\n```mermaid\nflowchart LR;\n    ST((start)) --\u003e P[PLOG macro] --\u003e R[Record] --\u003e L[Logger] --\u003e A[Appender]\n    A --\u003e|record| F[Formatter] --\u003e|text| C[Converter] --\u003e|binary| A\n    A --\u003e FIN(((finish)))\n```\n\n## Logger\n[Logger](#logger) is a center object of the whole logging system. It is a singleton and thus it forms a known single entry point for configuration and processing log data. [Logger](#logger) can act as [Appender](#appender) for another [Logger](#logger) because it implements `IAppender` interface. Also there can be several independent loggers that are parameterized by an integer instanceId number. The default instanceId is 0.\n\n```cpp\ntemplate\u003cint instanceId\u003e\nclass Logger : public util::Singleton\u003cLogger\u003cinstanceId\u003e \u003e, public IAppender\n{\npublic:\n    Logger(Severity maxSeverity = none);\n\n    Logger\u0026 addAppender(IAppender* appender);\n\n    Severity getMaxSeverity() const;\n    void setMaxSeverity(Severity severity);\n    bool checkSeverity(Severity severity) const;\n\n    virtual void write(const Record\u0026 record);\n    void operator+=(const Record\u0026 record);\n};\n```\n\n## Record\n[Record](#record) stores all log data. It includes:\n\n- time\n- severity\n- thread id\n- 'this' pointer (if a log message is written from within an object)\n- source line\n- source file name\n- function name\n- message\n- instance id\n\n\u003e **Note** Source file name isn't captured by default. To enable it define PLOG_CAPTURE_FILE.\n\nAlso [Record](#record) has a number of overloaded stream output operators to construct a message.\n\n```cpp\nclass Record\n{\npublic:\n    Record(Severity severity, const char* func, size_t line, const char* file, const void* object, int instanceId);\n\n    //////////////////////////////////////////////////////////////////////////\n    // Stream output operators\n\n    Record\u0026 operator\u003c\u003c(char data);\n    Record\u0026 operator\u003c\u003c(wchar_t data);\n\n    template\u003ctypename T\u003e\n    Record\u0026 operator\u003c\u003c(const T\u0026 data);\n\n    //////////////////////////////////////////////////////////////////////////\n    // Getters\n\n    virtual const util::Time\u0026 getTime() const;\n    virtual Severity getSeverity() const;\n    virtual unsigned int getTid() const;\n    virtual const void* getObject() const;\n    virtual size_t getLine() const;\n    virtual const util::nchar* getMessage() const;\n    virtual const char* getFunc() const;\n    virtual const char* getFile() const;\n    virtual int getInstanceId() const;\n};\n```\n\n*See [Stream improvements over std::ostream](#stream-improvements-over-stdostream).*\n\n*Refer to [Demo](samples/Demo) sample to see what can be written to the log stream.*\n\n## Formatter\n[Formatter](#formatter) is responsible for formatting log data from [Record](#record) into various string representations (binary forms can be used too). There is no base class for formatters, they are implemented as classes with static functions `format` and `header`:\n\n```cpp\nclass Formatter\n{\npublic:\n    static util::nstring header();\n    static util::nstring format(const Record\u0026 record);\n};\n```\n\n*See [How to implement a custom formatter](#custom-formatter).*\n\n### TxtFormatter\nThis is a classic log format available in almost any log library. It is good for console output and it is easy to read without any tools.\n\n```\n2014-11-11 00:29:06.245 FATAL [4460] [main@22] fatal\n2014-11-11 00:29:06.261 ERROR [4460] [main@23] error\n2014-11-11 00:29:06.261 INFO  [4460] [main@24] info\n2014-11-11 00:29:06.261 WARN  [4460] [main@25] warning\n2014-11-11 00:29:06.261 DEBUG [4460] [main@26] debug\n2014-11-11 00:29:06.261 INFO  [4460] [main@32] This is a message with \"quotes\"!\n2014-11-11 00:29:06.261 DEBUG [4460] [Object::Object@8]\n2014-11-11 00:29:06.261 DEBUG [4460] [Object::~Object@13]\n```\n\n### TxtFormatterUtcTime\nThis is a variant of [TxtFormatter](#txtformatter) that uses UTC time instead of local time.\n\n### CsvFormatter\nThis is the most powerful log format. It can be easily read without any tools (but slighlty harder than [TXT format](#txtformatter)) and can be heavily analyzed if it is opened with a CSV-aware tool (like Excel). One rows can be highlighted according to their cell values, another rows can be hidden, columns can be manipulated and you can even run SQL queries on log data! This is a recommended format if logs are big and require heavy analysis. Also 'this' pointer is shown so object instances can be told apart.\n\n```\nDate;Time;Severity;TID;This;Function;Message\n2014/11/14;15:22:25.033;FATAL;4188;00000000;main@22;\"fatal\"\n2014/11/14;15:22:25.033;ERROR;4188;00000000;main@23;\"error\"\n2014/11/14;15:22:25.033;INFO;4188;00000000;main@24;\"info\"\n2014/11/14;15:22:25.033;WARN;4188;00000000;main@25;\"warning\"\n2014/11/14;15:22:25.048;DEBUG;4188;00000000;main@26;\"debug\"\n2014/11/14;15:22:25.048;INFO;4188;00000000;main@32;\"This is a message with \"\"quotes\"\"!\"\n2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::Object@8;\n2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::~Object@13;\n```\n\n\u003e **Note** Message size is limited to 32000 chars.\n\n### CsvFormatterUtcTime\nThis is a variant of [CsvFormatter](#csvformatter) that uses UTC time instead of local time.\n\n### FuncMessageFormatter\nThis format is designed to be used with appenders that provide their own timestamps (like [AndroidAppender](#androidappender) or linux syslog facility).\n\n```\nmain@22: fatal\nmain@23: error\nmain@24: info\nmain@25: warning\nmain@26: debug\nmain@32: This is a message with \"quotes\"!\nObject::Object@8:\nObject::~Object@13:\n```\n\n### MessageOnlyFormatter\nUse this formatter when you're interested only in a log message.\n\n```\nfatal\nerror\ninfo\nwarning\ndebug\nThis is a message with \"quotes\"!\n```\n\n## Converter\n[Converter](#converter) is responsible for conversion of [Formatter](#formatter) output data to a raw buffer (represented as `std::string`). It is used by [RollingFileAppender](#rollingfileappender) to perform a conversion before writing to a file. There is no base class for converters, they are implemented as classes with static functions `convert` and `header`:\n\n```cpp\nclass Converter\n{\npublic:\n    static std::string header(const util::nstring\u0026 str);\n    static std::string convert(const util::nstring\u0026 str);\n};\n```\n\n*See [How to implement a custom converter](#custom-converter).*\n\n### UTF8Converter\n[UTF8Converter](#utf8converter) is a default converter in plog. It converts string data to UTF-8 with BOM.\n\n### NativeEOLConverter\nThis converter converts `\u003cLF\u003e` line endings to `\u003cCRLF\u003e` on Windows and does nothing on everything else. As a template parameter it accepts another converter that is called next (by default [UTF8Converter](#utf8converter)).\n\nSample:\n\n```cpp\nplog::RollingFileAppender\u003cplog::TxtFormatter, plog::NativeEOLConverter\u003c\u003e \u003e fileAppender(\"NativeEOL.log\");\n```\n\n*Refer to [NativeEOL](samples/NativeEOL) for a complete sample.*\n\n## Appender\n[Appender](#appender) uses [Formatter](#formatter) and [Converter](#converter) to get a desired representation of log data and outputs (appends) it to a file/console/etc. All appenders must implement `IAppender` interface (the only interface in plog):\n\n```cpp\nclass IAppender\n{\npublic:\n    virtual ~IAppender();\n    virtual void write(const Record\u0026 record) = 0;\n};\n```\n\n*See [How to implement a custom appender](#custom-appender).*\n\n### RollingFileAppender\nThis appender outputs log data to a file with rolling behavior. As template parameters it accepts both [Formatter](#formatter) and [Converter](#converter).\n\n```cpp\nRollingFileAppender\u003cFormatter, Converter\u003e::RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0);\n```\n\n- `fileName` - a log file name\n- `maxFileSize` - the maximum log file size in bytes\n- `maxFiles` - a number of log files to keep\n\nIf `maxFileSize` or `maxFiles` is 0 then rolling behavior is turned off.\n\nThe sample file names produced by this appender:\n\n- mylog.log \u003c== current log file (size \u003c maxFileSize)\n- mylog.1.log \u003c== previous log file (size \u003e= maxFileSize)\n- mylog.2.log \u003c== previous log file (size \u003e= maxFileSize)\n\nA file name can be changed at an arbitrary moment by calling `setFileName` as well as `maxFiles` and `maxFileSize` can be changed by calling `setMaxFiles` and `setMaxFileSize`.\n\n\u003e **Note** The lowest `maxFileSize` is 1000 bytes.\n\n\u003e **Note** A log file is created on the first log message.\n\n### ConsoleAppender\nThis appender outputs log data to `stdout` or `stderr`.  As a template parameter it accepts [Formatter](#formatter).\n\n```cpp\nConsoleAppender\u003cFormatter\u003e::ConsoleAppender(OutputStream outStream = streamStdOut);\n```\n\n### ColorConsoleAppender\nThis appender outputs log data to `stdout` or `stderr` using colors that depend on a log message severity level.  As a template parameter it accepts [Formatter](#formatter).\n\n```cpp\nColorConsoleAppender\u003cFormatter\u003e::ColorConsoleAppender(OutputStream outStream = streamStdOut);\n```\n\n### AndroidAppender\n[AndroidAppender](#androidappender) uses Android logging system to output log data. It can be viewed with [logcat](http://developer.android.com/tools/help/logcat.html) or in a log window of Android IDEs. As a template parameter this appender accepts [Formatter](#formatter) (usually [FuncMessageFormatter](#funcmessageformatter)).\n\n```cpp\nAndroidAppender\u003cFormatter\u003e::AndroidAppender(const char* tag);\n```\n### EventLogAppender\nThis appender outputs log data to the windows event log. It can be viewed with the windows event log viewer.  As a template parameter it accepts [Formatter](#formatter).\nThe constructor parameter is the event source name - typically it is the name of the application or a subcomponent of the application. It must be unique for the whole system.\n\n```cpp\nEventLogAppender\u003cFormatter\u003e::EventLogAppender(const wchar_t* sourceName);\n```\n\n[EventLogAppender](#eventlogappender) must be registered in the windows registry before use (before calling the constructor). There is a helper class for that:\n\n```cpp\nbool EventLogAppenderRegistry::add(const wchar_t* sourceName, const wchar_t* logName = L\"Application\");\nbool EventLogAppenderRegistry::exists(const wchar_t* sourceName, const wchar_t* logName = L\"Application\");\nvoid EventLogAppenderRegistry::remove(const wchar_t* sourceName, const wchar_t* logName = L\"Application\");\n```\n\nRegistry operations are system-wide and require administrator rights. Also they are persistent so can be performed only once (when the application is installed/uninstalled).\n\n### DebugOutputAppender\n[DebugOutputAppender](#debugoutputappender) sends log data to the debugger (works only on Windows). As a template parameter this appender accepts [Formatter](#formatter).\n\n```cpp\nDebugOutputAppender\u003cFormatter\u003e::DebugOutputAppender();\n```\n\n### DynamicAppender\n[DynamicAppender](#dynamicappender) is a wrapper that can add/remove appenders dynamically (at any point of time) in a thread-safe manner.\n\n```cpp\nDynamicAppender\u0026 DynamicAppender::addAppender(IAppender* appender);\nDynamicAppender\u0026 DynamicAppender::removeAppender(IAppender* appender);\n```\n\n*Refer to [DynamicAppender sample](samples/DynamicAppender) for a complete sample.*\n\n# Miscellaneous notes\n\n## Lazy stream evaluation\nLog messages are constructed using lazy stream evaluation. It means that if a log message will be dropped (because of its severity) then stream output operators are not executed. Thus performance penalty of unprinted log messages is negligible.\n\n```cpp\nPLOGD \u003c\u003c /* the following statements will be executed only when the logger severity is debug or higher */ ...\n```\n\n## Stream improvements over std::ostream\nStream output in plog has several improvements over the standard `std::ostream`:\n\n- handles wide chars/strings: `wchar_t`, `wchar_t*`, `std::wstring`\n- handles `NULL` values for C-strings: `char*` and `wchar_t*`\n- implicitly casts objects to: `std::string` and `std::wstring` (if they have an appropriate cast operator)\n- supports `QString` and `QStringRef` (you need to include Qt headers before plog)\n- supports `std::filesystem::path`\n- supports managed C++ `System::String^`\n\n## Automatic 'this' pointer capture\n'This' pointer is captured automatically to log data and can be printed by [CsvFormatter](#csvformatter). Unfortunately this feature is supported only on msvc 2010 and higher. It's disabled by default (due to some compatibility issues with `__if_exists` C++ extension), to enable it define `PLOG_ENABLE_GET_THIS`.\n\n## Headers to include\nThe core plog functionality is provided by inclusion of `plog/Log.h` file. Extra components require inclusion of corresponding extra headers after `plog/Log.h`.\n\nCore components are:\n- [TxtFormatter](#txtformatter)/[TxtFormatterUtcTime](#txtformatterutctime)\n- [CsvFormatter](#csvformatter)/[CsvFormatterUtcTime](#csvformatterutctime)\n- [UTF8Converter](#utf8converter)\n- [NativeEOLConverter](#nativeeolconverter)\n- [RollingFileAppender](#rollingfileappender)\n\n## Unicode\nPlog is unicode aware and wide string friendly. All messages are converted to a system native char type:\n\n- Windows\n  - `wchar_t` - by default \n  - `char` - if compiling with `/utf-8` switch or set `PLOG_CHAR_IS_UTF8` to 1\n- all other systems\n  - `char`\n\nAlso `char` is treated as:\n\n- Windows\n  - active code page - be default\n  - UTF-8 - if compiling with `/utf-8` switch or set `PLOG_CHAR_IS_UTF8` to 1\n- all other systems  \n  - UTF-8\n\nInternally plog uses `nstring`, `nstringstream` and `nchar` ('n' for native) that are defined as:\n\n```cpp\n#if PLOG_CHAR_IS_UTF8\n    typedef std::string nstring;\n    typedef std::ostringstream nostringstream;\n    typedef std::istringstream nistringstream;\n    typedef std::ostream nostream;\n    typedef char nchar;\n#else\n    typedef std::wstring nstring;\n    typedef std::wostringstream nostringstream;\n    typedef std::wistringstream nistringstream;\n    typedef std::wostream nostream;\n    typedef wchar_t nchar;\n#endif\n```\n\nBy default all log files are stored in UTF-8 with BOM thanks to [UTF8Converter](#utf8converter).\n\n## Wide string support\n\nWhether `wchar_t`, `wchar_t*`, `std::wstring` can be streamed to log messages or not is controlled by the `PLOG_ENABLE_WCHAR_INPUT` macro. Set it to a non-zero value to enable wide string support. By default wide string support is enabled for Windows and disabled for all non-Windows systems.\n\n\u003e **Note** Wide string support requires linking to `iconv` on macOS.\n\n## Performance\nPlog is not using any asynchronous techniques so it may slow down your application on large volumes of log messages.\n\nProducing a single log message takes the following amount of time:\n\n|CPU|OS|Time per a log call, microsec|\n|----|----|:----:|\n|AMD Phenom II 1055T @3.5GHz|Windows 2008 R2|12|\n|AMD Phenom II 1055T @3.5GHz|Linux Mint 17.1|8|\n|Intel Core i3-3120M @2.5GHz|Windows 2012 R2|25|\n|Intel Core i5-2500K @4.2GHz|Windows 2008 R2|8|\n|Intel Atom N270 @1.6GHz|Windows 2003|68|\n\nAssume 20 microsec per a log call then 500 log calls per a second will slow down an application by 1%. It is acceptable for most use cases.\n\n*Refer to [Performance](samples/Performance) for a complete sample.*\n\n## Printf style formatting\nPlog supports printf style formatting:\n\n```cpp\nPLOGI.printf(\"%d %s\", 42, \"test\");\nPLOGI.printf(L\"%d %S\", 42, \"test\"); // wchar_t version\n```\n\n## LOG_XXX macro name clashes\n`LOG_XXX` macro names may be in conflict with other libraries (for example [syslog](https://linux.die.net/man/3/syslog)). In such cases you can disable the `LOG_XXX` macro by defining `PLOG_OMIT_LOG_DEFINES` and use `PLOG_XXX`.\n\n*Define `PLOG_OMIT_LOG_DEFINES` before `#include \u003cplog/Log.h\u003e` or in the project settings!*\n\n## Disable logging to reduce binary size\nLogging code makes binary files larger. If you use it for debugging you can remove all logging code from release builds by defining the macro `PLOG_DISABLE_LOGGING`.\n\n# Extending\nPlog can be easily extended to support new:\n\n- [custom data type](#custom-data-type)\n- [custom appender](#custom-appender)\n- [custom formatter](#custom-formatter)\n- [custom converter](#custom-converter)\n\n## Custom data type\nTo output a custom data type to a log message implement the following function:\n\n```cpp\nnamespace plog\n{\n    Record\u0026 operator\u003c\u003c(Record\u0026 record, const MyType\u0026 t);\n}\n```\n\n*Refer to [CustomType](samples/CustomType) for a complete sample.*\n\n## Custom appender\nA custom appender must implement the `IAppender` interface. Also it may accept [Formatter](#formatter) and [Converter](#converter) as template parameters however this is optional.\n\n```cpp\nnamespace plog\n{\n    template\u003cclass Formatter\u003e\n    class MyAppender : public IAppender\n    {\n    public:\n        virtual void write(const Record\u0026 record);\n    };\n}\n```\n\n*Refer to [CustomAppender](samples/CustomAppender) for a complete sample.*\n\n## Custom formatter\nA formatter that is compatible with existing appenders must be a class with 2 static methods:\n\n- `header` - returns a header for a new log\n- `format` - formats [Record](#record) to a string\n\n```cpp\nnamespace plog\n{\n    class MyFormatter\n    {\n    public:\n        static util::nstring header();\n        static util::nstring format(const Record\u0026 record);\n    };\n}\n```\n\n*Refer to [CustomFormatter](samples/CustomFormatter) for a complete sample.*\n\n## Custom converter\nA converter must be a class with 2 static methods:\n\n- `header` - converts a header for a new log\n- `convert` - converts log messages\n\n```cpp\nnamespace plog\n{\n    class MyConverter\n    {\n    public:\n        static std::string header(const util::nstring\u0026 str);\n        static std::string convert(const util::nstring\u0026 str);\n    };\n}\n```\n\n*Refer to [CustomConverter](samples/CustomConverter) for a complete sample.*\n\n# Samples\nThere are a number of samples that demonstrate various aspects of using plog. They can be found in the [samples](samples) folder:\n\n|Sample|Description|\n|------|-----------|\n|[Android](samples/Android)|Shows how to use [AndroidAppender](#androidappender).|\n|[Arduino](samples/Arduino)|Arduino sample - not finished yet!|\n|[AscDump](samples/AscDump)|Shows how to use `plog::ascdump` to dump binary buffers into ASCII.|\n|[Chained](samples/Chained)|Shows how to chain a logger in a shared library with the main logger (route messages).|\n|[ColorConsole](samples/ColorConsole)|Shows how to use [ColorConsoleAppender](#colorconsoleappender).|\n|[CustomAppender](samples/CustomAppender)|Shows how to implement a custom appender that stores log messages in memory.|\n|[CustomConverter](samples/CustomConverter)|Shows how to implement a custom converter that encrypts log messages.|\n|[CustomFormatter](samples/CustomFormatter)|Shows how to implement a custom formatter.|\n|[CustomType](samples/CustomType)|Shows how to print a custom type to the log stream.|\n|[CXX11](samples/CXX11)|Demonstrates log stream abilities for C++11 features.|\n|[CXX17](samples/CXX17)|Demonstrates log stream abilities for C++17 features.|\n|[DebugOutput](samples/DebugOutput)|Shows how to use [DebugOutputAppender](#debugoutputappender) to write to the windows debug output.|\n|[Demo](samples/Demo)|Demonstrates log stream abilities, prints various types of messages.|\n|[DisableLogging](samples/DisableLogging)|Shows how to disable logging (so it will be stripped from the binary).|\n|[DynamicAppender](samples/DynamicAppender)|Shows how to add/remove appenders dynamically).|\n|[EventLog](samples/EventLog)|Shows how to use [EventLogAppender](#eventlogappender) to write to the windows event log.|\n|[Facilities](samples/Facilities)|Shows how to use logging per facilities via multiple logger instances (useful for big projects).|\n|[Hello](samples/Hello)|A minimal introduction sample, shows the basic 3 steps to start using plog.|\n|[HexDump](samples/HexDump)|Shows how to use `plog::hexdump` to dump binary buffers into hex.|\n|[Library](samples/Library)|Shows plog usage in static libraries.|\n|[MultiAppender](samples/MultiAppender)|Shows how to use multiple appenders with the same logger.|\n|[MultiInstance](samples/MultiInstance)|Shows how to use multiple logger instances, each instance has its own independent configuration.|\n|[NotShared](samples/NotShared)|Shows how to make logger instances local across binary modules (this is the default behavior on Windows but not on other platforms, so be careful).|\n|[ObjectiveC](samples/ObjectiveC)|Shows that plog can be used in ObjectiveC++.|\n|[Path](samples/Path)|A test sample to check that `std::filesystem::path` can be logged.|\n|[Performance](samples/Performance)|Measures time per a log call.|\n|[PrintVar](samples/PrintVar)|Shows how to use `PLOG_PRINT_VAR` to print variables.|\n|[SetFileName](samples/SetFileName)|Shows how to change a log file name at arbitrary moment.|\n|[Shared](samples/Shared)|Shows how to share logger instances across binary modules (this is the default behavior on everything except Windows, so be careful)|\n|[SkipNativeEOL](samples/SkipNativeEOL)|Shows how to skip [NativeEOLConverter](#nativeeolconverter).|\n|[UtcTime](samples/UtcTime)|Shows how to use UTC time instead of local time.|\n|[Utf8Everywhere](samples/Utf8Everywhere)|Demonstrates how to use http://utf8everywhere.org on Windows.|\n\n# References\n\n## Competing C++ log libraries\n\n- [Boost::Log](http://www.boost.org/doc/libs/release/libs/log/)\n- [EasyLogging++](https://github.com/easylogging/easyloggingpp)\n- [g2log](http://www.codeproject.com/Articles/288827/g-log-An-efficient-asynchronous-logger-using-Cplus)\n- [g3log](https://github.com/KjellKod/g3log)\n- [glog](https://code.google.com/p/google-glog/)\n- [Log4cplus](http://sourceforge.net/projects/log4cplus/)\n- [Log4cpp](http://log4cpp.sourceforge.net/)\n- [Log4cxx](http://logging.apache.org/log4cxx/)\n- [Pantheios](http://pantheios.sourceforge.net/)\n- [spdlog](https://github.com/gabime/spdlog/)\n- [reckless](https://github.com/mattiasflodin/reckless)\n- [loguru](https://github.com/emilk/loguru)\n- [blackhole](https://github.com/3Hren/blackhole)\n\n## Tools and useful info\n\n- [__if_exists Statement](https://msdn.microsoft.com/en-us/library/x7wy9xh3.aspx)\n- [Controlling Symbol Visibility](https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html)\n- [Mermaid](https://mermaid-js.github.io/mermaid/)\n- [DocToc](https://github.com/thlorenz/doctoc)\n- [CMake](http://www.cmake.org)\n- [Compiler support for C++11](https://en.cppreference.com/w/cpp/compiler_support/11)\n- [Guide to predefined macros in C++ compilers (gcc, clang, msvc etc.)](https://blog.kowalczyk.info/article/j/guide-to-predefined-macros-in-c-compilers-gcc-clang-msvc-etc..html)\n\n# License\nThis version of plog is licensed under the [MIT license](https://choosealicense.com/licenses/mit). You can freely use it in your commercial or opensource software.\n\n# Version history\n\n## Version 1.1.10 (20 Aug 2023)\n- New: Add support for UTF-8 char encoding on Windows (#76, #69, #238, #239)\\\n *This allows to use [Utf8Everywhere](http://utf8everywhere.org) approach*\n- New: Add ArduinoAppender\n- New: Publish on [PlatformIO Registry](https://registry.platformio.org) for embedded development (#244)\n- New: Add support for `char8_t` strings\n- New: Add tests\n- Enh: Add rudimentary support of VS2005 (#232)\n- Enh: Implementation of `vasprintf` emulation (#243)\n- Fix: Parsing of templated classes (#251)\n- Fix: Compiling with MSVC using C++20 (#236)\n- Fix: No newline error with '-Wnewline-eof' build flag (#263)\n\n## Version 1.1.9 (16 Dec 2022)\n- New: Add ability to truncate log file using `\u003e` in shell (#155)\n- New: Add override specifier (to be able to build with `-Wsuggest-override`) (#231)\n- New: Add nuget specs (#86)\n- New: Add ability to add/remove appenders (#226)\n- Fix: Printing `boost::filesystem::path` (#227)\n- Fix: Building on C++ Builder 10.4 (#225)\n- Fix: `PLOG_LOCAL` mode if symbol visibility set to default (#219)\n\n## Version 1.1.8 (10 Jun 2022)\n- Fix: 'operator \u003c\u003c' is ambiguous for string_view on Windows (#217)\n- Fix: CMake + vcpkg: find_package (#211)\n    \n## Version 1.1.7 (09 Jun 2022)\n- New: Add hex dumper (#111)\n- New: Add ASCII dumper (#213)\n- New: Add support for printing std containers (#207)\n- New: Add console initializer\n- New: Add PrintVar helper\n- New: Add CMake find_package support (#171)\n- Enh: Change license to MIT (#212)\n- Fix: Specify calling convention for std stream manipulators (#210)\n- Fix: Compilation on VS2010 (#207)\n- Fix: Use add_custom_target for pseudo-project with headers (#216)\n\n## Version 1.1.6 (06 Feb 2022)\n- New: Ability to disable logging to reduce binary size (#130)\n- New: Ability to change `maxFiles`/`maxFileSize` after initialization\n- New: Logging `std::filesystem::path` without explicit conversion to `std::string` (#168, #185, #183)\n- New: Allow to choose `stdout`/`stderr` for console appender (#162, #117)\n- New: Ability to change log file name at runtime (#62)\n- New: Ability to control sharing across modules (#96, #152, #20)\n- New: Building on platforms without thread support (#161, #113)\n- Enh: Change color functions from private to protected (#163)\n- Enh: Do not include `plog/Init.h` in `plog/Log.h` (#127, #89)\n- Fix: WideCharToMultiByte bug (#202)\n- Fix: Building with Qt6 (#190)\n- Fix: Compiling on GCC 4.4-4.7 (#176)\n- Fix: Suppress UBSan false positive (#90)\n- Fix: Don't share handle/fd to child process (#170)\n- Fix: MSVC analyzer warnings (#148)\n- Fix: File size truncation \u003e 2GB on Windows (#160)\n- Fix: [RTEMS](https://www.rtems.org) build on newer toolchain (#158, #159)\n\n## Version 1.1.5 (21 Oct 2019)\n- New: Use `NativeEOLConverter` by default (#145)\n- New: Add logger `instanceId` into `Record` (#141)\n- New: Add support for the printf style formatting (#139)\n- New: Make `severityFromString` case-insensitive\n- New: Define macro names with \"PLOG\" instead of \"LOG\" in order to avoid conflicts with \"LOG\" names defined in other packages or in system headers (#25, #129)\n- New: Add option for building samples (ON per default) (#125, #126)\n- New: Add CMake installer (#121, #122)\n- New: Add support for `QStringRef`\n- New: Modernize CMake (#106)\n- New: Allow rollLogFiles to be called manually (#100, #103)\n- New: Add ability to use UTC time (#101)\n- Fix: Disable `PLOG_GET_THIS()` by default (#120, #132)\n- Fix: Change `RegSetValueExW` prototype to match windows native declaration (void* -\u003e BYTE*)\n- Fix: Move `System::String^` handler to a free function (#131)\n- Fix: Making sure we can build standalone under Windows (#123)\n- Fix: Parse error by ReSharper (#116)\n- Fix: Parse error by Clang Code Model in Qt Creator (#114)\n- Fix: Printing CustomType at begin of the stream (#94)\n- Fix: Make `RollingFileAppender` work with maxFiles set to 1 (#70)\n- Fix: Clang-tidy nullable issue\n\n## Version 1.1.4 (26 Mar 2018)\n- New: Add `-Wundef` support\n- New: Add [RTEMS](https://www.rtems.org) support (#87)\n- New: Add Intel C++ Compiler support (#84)\n- New: Add FreeBSD support (#83)\n- New: Add `-Wnon-virtual-dtor` support (#79)\n- New: Support `ostream` operator\u003c\u003c on Windows as well as `wostream` (#66)\n- Fix: Fix compilation for Android (#68)\n- Fix: Fix compiling with CMake 2.8\n\n## Version 1.1.3 (09 Aug 2017)\n- New: Introduce `LOG_ENABLE_WCHAR_INPUT` macro to control wide string support\n- New: Add support for managed C++ `System::String^` (#63)\n- New: Add missing macros for logging with severity NONE (#61)\n- Fix: Unable to build [NativeEOLConverter](#nativeeolconverter)/[UTF8Converter](#utf8converter) using Visual Studio (#59)\n- Fix: Use `WriteConsoleW` instead of global `setlocale` for writing unicode into Windows console (#58)\n- Fix: Mention about linking to `iconv` on macOS (#55)\n- Fix: `IF_LOG` macro didn't work for curly braces blocks\n\n## Version 1.1.2 (02 May 2017)\n- New: Add [NativeEOLConverter](#nativeeolconverter)\n- New: Add [MessageOnlyFormatter](#messageonlyformatter)\n- New: Slightly increase log performance on Windows (about 9%).\n\n## Version 1.1.1 (17 Apr 2017)\n- New: Ability to check whether event log registry entry exists (#36)\n- Fix: Update includes (#47)\n- Fix: Get rid of `windows.h` dependency (#45, #13)\n- Fix: Signed unsigned assignment warning (#40)\n- Fix: Build warning on macOS 10.12 Sierra (#39)\n\n## Version 1.1.0 (20 Nov 2016)\n- Fix: Introduce binary compatible interface to `Record` (WARNING: this is not compatible with 1.0.x version in [Chained mode](#chained-loggers), so don't mix 1.1.x and 1.0.x) (#34)\n\n## Version 1.0.2 (19 Nov 2016)\n- New: Default instanceId can be set via `LOG_DEFAULT_INSTANCE` (#11)\n- New: Support for `QString` (#30)\n- New: Support for C++Builder\n- New: `severityFromString` function (#15)\n- New: Capture source file name (disabled by default) (#21)\n- New: Add [DebugOutputAppender](#debugoutputappender) (#33)\n- New: Add [EventLogAppender](#eventlogappender) (#32)\n- Fix: Crash on processing Obj-C function name (#12)\n- Fix: Compatibility with [MinGW](http://www.mingw.org/) (#17)\n- Fix: `IF_LOG_` macro in if/else leads to miss else branch (#27)\n- Fix: Thread safety for [ConsoleAppender](#consoleappender)/[ColorConsoleAppender](#colorconsoleappender) (#18, #29)\n- Fix: Support for stream manipulators like `std::endl` (#31)\n- Fix: Compatibility with old Visual Studio versions\n\n## Version 1.0.1 (01 Nov 2015)\n- New: Add [ColorConsoleAppender](#colorconsoleappender)\n- Fix: Compatibility with [Mingw-w64](http://mingw-w64.org/) (#6)\n- Fix: Log file not created if file name contains Unicode characters in Windows (#7)\n- Fix: Flush stdout (#4)\n- Fix: IntelliSense error: expected an identifier (#3)\n\n## Version 1.0.0 (19 May 2015)\n- Initial public release\n","funding_links":[],"categories":["C++","TODO scan for Android support in followings","Logging","进程间通信"],"sub_categories":["日志"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSergiusTheBest%2Fplog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSergiusTheBest%2Fplog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSergiusTheBest%2Fplog/lists"}