1# Plog - portable, simple and extensible C++ logging library
2Pretty powerful logging library in about 1000 lines of code [![Build Status](https://travis-ci.com/SergiusTheBest/plog.svg?branch=master)](https://travis-ci.com/SergiusTheBest/plog) [![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)
3
4- [Introduction](#introduction)
5  - [Hello log!](#hello-log)
6  - [Features](#features)
7- [Usage](#usage)
8  - [Step 1: Adding includes](#step-1-adding-includes)
9  - [Step 2: Initialization](#step-2-initialization)
10  - [Step 3: Logging](#step-3-logging)
11    - [Basic logging macros](#basic-logging-macros)
12    - [Conditional logging macros](#conditional-logging-macros)
13    - [Logger severity checker](#logger-severity-checker)
14- [Advanced usage](#advanced-usage)
15  - [Changing severity at runtime](#changing-severity-at-runtime)
16  - [Custom initialization](#custom-initialization)
17  - [Multiple appenders](#multiple-appenders)
18  - [Multiple loggers](#multiple-loggers)
19  - [Share log instances across modules (exe, dll, so, dylib)](#share-log-instances-across-modules-exe-dll-so-dylib)
20  - [Chained loggers](#chained-loggers)
21- [Architecture](#architecture)
22  - [Overview](#overview)
23  - [Logger](#logger)
24  - [Record](#record)
25  - [Formatter](#formatter)
26    - [TxtFormatter](#txtformatter)
27    - [TxtFormatterUtcTime](#txtformatterutctime)
28    - [CsvFormatter](#csvformatter)
29    - [CsvFormatterUtcTime](#csvformatterutctime)
30    - [FuncMessageFormatter](#funcmessageformatter)
31    - [MessageOnlyFormatter](#messageonlyformatter)
32  - [Converter](#converter)
33    - [UTF8Converter](#utf8converter)
34    - [NativeEOLConverter](#nativeeolconverter)
35  - [Appender](#appender)
36    - [RollingFileAppender](#rollingfileappender)
37    - [ConsoleAppender](#consoleappender)
38    - [ColorConsoleAppender](#colorconsoleappender)
39    - [AndroidAppender](#androidappender)
40    - [EventLogAppender](#eventlogappender)
41    - [DebugOutputAppender](#debugoutputappender)
42- [Miscellaneous notes](#miscellaneous-notes)
43  - [Lazy stream evaluation](#lazy-stream-evaluation)
44  - [Stream improvements over std::ostream](#stream-improvements-over-stdostream)
45  - [Automatic 'this' pointer capture](#automatic-this-pointer-capture)
46  - [Headers to include](#headers-to-include)
47  - [Unicode](#unicode)
48  - [Wide string support](#wide-string-support)
49  - [Performance](#performance)
50  - [Printf style formatting](#printf-style-formatting)
51  - [LOG_XXX macro name clashes](#log_xxx-macro-name-clashes)
52- [Extending](#extending)
53  - [Custom data type](#custom-data-type)
54  - [Custom appender](#custom-appender)
55  - [Custom formatter](#custom-formatter)
56  - [Custom converter](#custom-converter)
57- [Samples](#samples)
58- [References](#references)
59  - [Competing C++ log libraries](#competing-c-log-libraries)
60  - [Tools and useful info](#tools-and-useful-info)
61- [License](#license)
62- [Version history](#version-history)
63
64# Introduction
65
66## Hello log!
67Plog 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).
68
69Here is a minimal hello log sample:
70
71```cpp
72#include <plog/Log.h> // Step1: include the headers
73#include "plog/Initializers/RollingFileInitializer.h"
74
75int main()
76{
77    plog::init(plog::debug, "Hello.txt"); // Step2: initialize the logger
78
79    // Step3: write log messages using a special macro
80    // There are several log macros, use the macro you liked the most
81
82    PLOGD << "Hello log!"; // short macro
83    PLOG_DEBUG << "Hello log!"; // long macro
84    PLOG(plog::debug) << "Hello log!"; // function-style macro
85
86    // Also you can use LOG_XXX macro but it may clash with other logging libraries
87    LOGD << "Hello log!"; // short macro
88    LOG_DEBUG << "Hello log!"; // long macro
89    LOG(plog::debug) << "Hello log!"; // function-style macro
90
91    return 0;
92}
93```
94
95And its output:
96
97```
982015-05-18 23:12:43.921 DEBUG [21428] [main@13] Hello log!
992015-05-18 23:12:43.968 DEBUG [21428] [main@14] Hello log!
1002015-05-18 23:12:43.968 DEBUG [21428] [main@15] Hello log!
101```
102
103## Features
104- Very small (slightly more than 1000 LOC)
105- Easy to use
106- Headers only
107- No 3rd-party dependencies
108- Cross-platform: Windows, Linux, FreeBSD, macOS, Android, RTEMS (gcc, clang, msvc, mingw, mingw-w64, icc, c++builder)
109- Thread and type safe
110- Formatters: [TXT](#txtformatter), [CSV](#csvformatter), [FuncMessage](#funcmessageformatter), [MessageOnly](#messageonlyformatter)
111- Appenders: [RollingFile](#rollingfileappender), [Console](#consoleappender), [ColorConsole](#colorconsoleappender), [Android](#androidappender), [EventLog](#eventlogappender), [DebugOutput](#debugoutputappender)
112- [Automatic 'this' pointer capture](#automatic-this-pointer-capture) (supported only on msvc)
113- [Lazy stream evaluation](#lazy-stream-evaluation)
114- [Unicode aware](#unicode), files are stored in UTF8
115- Doesn't require C++11
116- [Extendable](#extending)
117- No `windows.h` dependency
118- Can use UTC or local time
119- Uses modern CMake
120
121# Usage
122To start using plog you need to make 3 simple steps.
123
124## Step 1: Adding includes
125At first your project needs to know about plog. For that you have to:
126
1271. Add `plog/include` to the project include paths
1282. Add `#include <plog/Log.h>` into your cpp/h files (if you have precompiled headers it is a good place to add this include there)
129
130## Step 2: Initialization
131The next step is to initialize the [Logger](#logger). This is done by the following `plog::init` function:
132
133```cpp
134Logger& init(Severity maxSeverity, const char/wchar_t* fileName, size_t maxFileSize = 0, int maxFiles = 0);
135```
136
137`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:
138
139```cpp
140enum Severity
141{
142    none = 0,
143    fatal = 1,
144    error = 2,
145    warning = 3,
146    info = 4,
147    debug = 5,
148    verbose = 6
149};
150```
151
152*Note: messages with severity level `none` will be always printed.*
153
154The log format is determined automatically by `fileName` file extension:
155
156- .csv => [CSV format](#csvformatter)
157- anyting else => [TXT format](#txtformatter)
158
159The rolling behavior is controlled by `maxFileSize` and `maxFiles` parameters:
160
161- `maxFileSize` - the maximum log file size in bytes
162- `maxFiles` - a number of log files to keep
163
164If one of them is zero then log rolling is disabled.
165
166Sample:
167
168```cpp
169plog::init(plog::warning, "c:\\logs\\log.csv", 1000000, 5);
170```
171
172Here 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.
173
174*Note: see [Custom initialization](#custom-initialization) for advanced usage.*
175
176## Step 3: Logging
177Logging is performed with the help of special macros. A log message is constructed using stream output operators `<<`. Thus it is type-safe and extendable in contrast to a format string output.
178
179### Basic logging macros
180This is the most used type of logging macros. They do unconditional logging.
181
182#### Long macros:
183
184```cpp
185PLOG_VERBOSE << "verbose";
186PLOG_DEBUG << "debug";
187PLOG_INFO << "info";
188PLOG_WARNING << "warning";
189PLOG_ERROR << "error";
190PLOG_FATAL << "fatal";
191PLOG_NONE << "none";
192```
193
194#### Short macros:
195
196```cpp
197PLOGV << "verbose";
198PLOGD << "debug";
199PLOGI << "info";
200PLOGW << "warning";
201PLOGE << "error";
202PLOGF << "fatal";
203PLOGN << "none";
204```
205
206#### Function-style macros:
207
208```cpp
209PLOG(severity) << "msg";
210```
211
212### Conditional logging macros
213These macros are used to do a conditional logging. They accept a condition as a parameter and perform logging if the condition is true.
214
215#### Long macros:
216
217```cpp
218PLOG_VERBOSE_IF(cond) << "verbose";
219PLOG_DEBUG_IF(cond) << "debug";
220PLOG_INFO_IF(cond) << "info";
221PLOG_WARNING_IF(cond) << "warning";
222PLOG_ERROR_IF(cond) << "error";
223PLOG_FATAL_IF(cond) << "fatal";
224PLOG_NONE_IF(cond) << "none";
225```
226
227#### Short macros:
228
229```cpp
230PLOGV_IF(cond) << "verbose";
231PLOGD_IF(cond) << "debug";
232PLOGI_IF(cond) << "info";
233PLOGW_IF(cond) << "warning";
234PLOGE_IF(cond) << "error";
235PLOGF_IF(cond) << "fatal";
236PLOGN_IF(cond) << "none";
237```
238
239#### Function-style macros:
240
241```cpp
242PLOG_IF(severity, cond) << "msg";
243```
244
245### Logger severity checker
246In 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.
247
248```cpp
249IF_PLOG(severity)
250```
251
252Sample:
253
254```cpp
255IF_PLOG(plog::debug) // we want to execute the following statements only at debug severity (and higher)
256{
257    for (int i = 0; i < vec.size(); ++i)
258    {
259        PLOGD << "vec[" << i << "]: " << vec[i];
260    }
261}
262```
263
264# Advanced usage
265
266## Changing severity at runtime
267It is possible to set the maximum severity not only at the logger initialization time but at any time later. There are special accessor methods:
268
269```cpp
270Severity Logger::getMaxSeverity() const;
271Logger::setMaxSeverity(Severity severity);
272```
273
274To get the logger use `plog::get` function:
275
276```cpp
277Logger* get();
278```
279
280Sample:
281
282```cpp
283plog::get()->setMaxSeverity(plog::debug);
284```
285
286## Custom initialization
287Non-typical log cases require the use of custom initialization. It is done by the following `plog::init` function:
288
289```cpp
290Logger& init(Severity maxSeverity = none, IAppender* appender = NULL);
291```
292
293You have to construct an [Appender](#appender) parameterized with a [Formatter](#formatter) and pass it to the `plog::init` function.
294
295*Note: a lifetime of the appender should be static!*
296
297Sample:
298
299```cpp
300static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender;
301plog::init(plog::debug, &consoleAppender);
302```
303
304## Multiple appenders
305It 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:
306
307```cpp
308Logger& Logger::addAppender(IAppender* appender);
309```
310
311Sample:
312
313```cpp
314static plog::RollingFileAppender<plog::CsvFormatter> fileAppender("MultiAppender.csv", 8000, 3); // Create the 1st appender.
315static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender; // Create the 2nd appender.
316plog::init(plog::debug, &fileAppender).addAppender(&consoleAppender); // Initialize the logger with the both appenders.
317```
318
319Here the logger is initialized in the way when log messages are written to both a file and a console.
320
321*Refer to [MultiAppender](samples/MultiAppender) for a complete sample.*
322
323## Multiple loggers
324Multiple [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:
325
326```cpp
327Logger<instanceId>& init<instanceId>(...);
328```
329
330To get a logger use `plog::get` function (returns `NULL` if the logger is not initialized):
331
332```cpp
333Logger<instanceId>* get<instanceId>();
334```
335
336All logging macros have their special versions that accept an instanceId parameter. These kind of macros have an underscore at the end:
337
338```cpp
339PLOGD_(instanceId) << "debug";
340PLOGD_IF_(instanceId, condition) << "conditional debug";
341IF_PLOG_(instanceId, severity)
342```
343
344Sample:
345
346```cpp
347enum // Define log instanceIds. Default is 0 and is omitted from this enum.
348{
349    SecondLog = 1
350};
351
352int main()
353{
354    plog::init(plog::debug, "MultiInstance-default.txt"); // Initialize the default logger instance.
355    plog::init<SecondLog>(plog::debug, "MultiInstance-second.txt"); // Initialize the 2nd logger instance.
356
357    // Write some messages to the default log.
358    PLOGD << "Hello default log!";
359
360    // Write some messages to the 2nd log.
361    PLOGD_(SecondLog) << "Hello second log!";
362
363    return 0;
364}
365```
366
367*Refer to [MultiInstance](samples/MultiInstance) for a complete sample.*
368
369## Share log instances across modules (exe, dll, so, dylib)
370For applications that consist from 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.
371
372Sharing behavior is controlled by the following macros and is OS-dependent:
373
374|Macro|OS|Behavior|
375|--|--|--|
376|PLOG_GLOBAL|Linux/Unix|Shared|
377|PLOG_LOCAL|Linux/Unix|Local|
378|PLOG_EXPORT|Linux/Unix|n/a|
379|PLOG_IMPORT|Linux/Unix|n/a|
380|<default>|Linux/Unix|According to compiler settings|
381|PLOG_GLOBAL|Windows|n/a|
382|PLOG_LOCAL|Windows|Local|
383|PLOG_EXPORT|Windows|Shared (exports)|
384|PLOG_IMPORT|Windows|Shared (imports)|
385|<default>|Windows|Local|
386
387For sharing on Windows one module should use `PLOG_EXPORT` and others should use `PLOG_IMPORT`. Also be cafeful on Linux/Unix: if you don't specify sharing behavior it will be determined by compiler settings (`-fvisibility`).
388
389*Refer to [Shared](samples/Shared) for a complete sample.*
390
391## Chained loggers
392A [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.
393
394*Important: don't forget to specify `PLOG_LOCAL` sharing mode on Linux/Unix systems for this sample.*
395
396Sample:
397
398```cpp
399// shared library
400
401// Function that initializes the logger in the shared library.
402extern "C" void EXPORT initialize(plog::Severity severity, plog::IAppender* appender)
403{
404    plog::init(severity, appender); // Initialize the shared library logger.
405}
406
407// Function that produces a log message.
408extern "C" void EXPORT foo()
409{
410    PLOGI << "Hello from shared lib!";
411}
412```
413
414```cpp
415// main app
416
417// Functions imported form the shared library.
418extern "C" void initialize(plog::Severity severity, plog::IAppender* appender);
419extern "C" void foo();
420
421int main()
422{
423    plog::init(plog::debug, "ChainedApp.txt"); // Initialize the main logger.
424
425    PLOGD << "Hello from app!"; // Write a log message.
426
427    initialize(plog::debug, plog::get()); // Initialize the logger in the shared library. Note that it has its own severity.
428    foo(); // Call a function from the shared library that produces a log message.
429
430    return 0;
431}
432```
433
434*Refer to [Chained](samples/Chained) for a complete sample.*
435
436# Architecture
437
438## Overview
439Plog is designed to be small but flexible, so it prefers templates to interface inheritance. All main entities are shown on the following UML diagram:
440
441![Plog class diagram](http://gravizo.com/svg?@startuml;class%20Logger<int%20instance>%20<<singleton>>%20{;%20%20%20%20+addAppender%28%29;%20%20%20%20+getMaxSeverity%28%29;%20%20%20%20+setMaxSeverity%28%29;%20%20%20%20+checkSeverity%28%29;%20%20%20%20-maxSeverity;%20%20%20%20-appenders;};package%20Appenders%20<<Frame>>%20{;%20%20%20%20interface%20IAppender%20{;%20%20%20%20%20%20%20%20+write%28%29;%20%20%20%20};%20%20%20%20;%20%20%20%20class%20RollingFileAppender<Formatter,%20Converter>;%20%20%20%20class%20ConsoleAppender<Formatter>;%20%20%20%20class%20ColorConsoleAppender<Formatter>;%20%20%20%20class%20AndroidAppender<Formatter>;%20%20%20%20class%20EventLogAppender<Formatter>;%20%20%20%20class%20DebugOutputAppender<Formatter>;%20%20%20%20ConsoleAppender%20<|--%20ColorConsoleAppender;%20%20%20%20IAppender%20<|-u-%20Logger;%20%20%20%20IAppender%20<|--%20RollingFileAppender;%20%20%20%20IAppender%20<|--%20ConsoleAppender;%20%20%20%20IAppender%20<|--%20AndroidAppender;%20%20%20%20IAppender%20<|--%20EventLogAppender;%20%20%20%20IAppender%20<|--%20DebugOutputAppender;%20%20%20%20;%20%20%20%20Logger%20"1"%20o--%20"0..n"%20IAppender;};package%20Formatters%20<<Frame>>%20{;%20%20%20%20class%20CsvFormatter%20{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20format%28%29;%20%20%20%20};%20%20%20%20class%20TxtFormatter%20{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20format%28%29;%20%20%20%20};%20%20%20%20class%20FuncMessageFormatter%20{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20format%28%29;%20%20%20%20};%20%20%20%20class%20MessageOnlyFormatter%20{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20format%28%29;%20%20%20%20};};package%20Converters%20<<Frame>>%20{;%20%20%20%20class%20UTF8Converter%20{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20convert%28%29;%20%20%20%20};%20%20%20%20class%20NativeEOLConverter%20<NextConverter>{;%20%20%20%20%20%20%20%20{static}%20header%28%29;%20%20%20%20%20%20%20%20{static}%20convert%28%29;%20%20%20%20};};enum%20Severity%20{;%20%20%20%20none,;%20%20%20%20fatal,;%20%20%20%20error,;%20%20%20%20warning,;%20%20%20%20info,;%20%20%20%20debug,;%20%20%20%20verbose;};class%20Record%20{;%20%20%20%20+operator<<%28%29;%20%20%20%20-time;%20%20%20%20-severity;%20%20%20%20-tid;%20%20%20%20-object;%20%20%20%20-line;%20%20%20%20-file;%20%20%20%20-message;%20%20%20%20-func;};hide%20empty%20members;hide%20empty%20fields;@enduml)
442<!--
443@startuml
444
445class Logger<int instance> <<singleton>> {
446    +addAppender();
447    +getMaxSeverity();
448    +setMaxSeverity();
449    +checkSeverity();
450    -maxSeverity;
451    -appenders;
452}
453
454package Appenders <<Frame>> {
455    interface IAppender {
456        +write();
457    }
458
459    class RollingFileAppender<Formatter, Converter>
460    class ConsoleAppender<Formatter>
461    class ColorConsoleAppender<Formatter>
462    class AndroidAppender<Formatter>
463    class EventLogAppender<Formatter>
464    class DebugOutputAppender<Formatter>
465
466    ConsoleAppender <|-- ColorConsoleAppender
467    IAppender <|-u- Logger
468    IAppender <|-- RollingFileAppender
469    IAppender <|-- ConsoleAppender
470    IAppender <|-- AndroidAppender
471    IAppender <|-- EventLogAppender
472    IAppender <|-- DebugOutputAppender
473
474    Logger "1" o-- "0..n" IAppender
475}
476
477package Formatters <<Frame>> {
478    class CsvFormatter {
479        {static} header();
480        {static} format();
481    }
482
483    class TxtFormatter {
484        {static} header();
485        {static} format();
486    }
487
488    class FuncMessageFormatter {
489        {static} header();
490        {static} format();
491    }
492
493    class MessageOnlyFormatter {
494        {static} header();
495        {static} format();
496    }
497}
498
499package Converters <<Frame>> {
500    class UTF8Converter {
501        {static} header();
502        {static} convert();
503    }
504
505    class NativeEOLConverter <NextConverter>{
506        {static} header();
507        {static} convert();
508    }
509}
510
511enum Severity {
512    none,
513    fatal,
514    error,
515    warning,
516    info,
517    debug,
518    verbose
519}
520
521class Record {
522    +operator<<();
523    -time;
524    -severity;
525    -tid;
526    -object;
527    -line;
528    -file;
529    -message;
530    -func;
531}
532
533hide empty members
534hide empty fields
535@enduml
536-->
537
538There are 5 functional parts:
539
540- [Logger](#logger) - the main object, implemented as singleton
541- [Record](#record) - keeps log data: time, message, etc
542- [Appender](#appender) - represents a log data destination: file, console, etc
543- [Formatter](#formatter) - formats log data into a string
544- [Converter](#converter) - converts formatter output into a raw buffer
545
546The log data flow is shown below:
547
548![Log data flow](http://gravizo.com/g?@startuml;%28*%29%20-r->%20"PLOG%20macro";-r->%20"Record";-r->%20"Logger";-r-->%20"Appender";-d->%20"Formatter";-d->%20"Converter";-u->%20"Appender";-r->%20%28*%29;@enduml)
549<!--
550@startuml
551(*) -r-> "PLOG macro"
552-r-> "Record"
553-r-> "Logger"
554-r-> "Appender"
555-d-> "Formatter"
556-d-> "Converter"
557-u-> "Appender"
558-r-> (*)
559@enduml
560-->
561
562## Logger
563[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.
564
565```cpp
566template<int instanceId>
567class Logger : public util::Singleton<Logger<instanceId> >, public IAppender
568{
569public:
570    Logger(Severity maxSeverity = none);
571
572    Logger& addAppender(IAppender* appender);
573
574    Severity getMaxSeverity() const;
575    void setMaxSeverity(Severity severity);
576    bool checkSeverity(Severity severity) const;
577
578    virtual void write(const Record& record);
579    void operator+=(const Record& record);
580};
581```
582
583## Record
584[Record](#record) stores all log data. It includes:
585
586- time
587- severity
588- thread id
589- 'this' pointer (if a log message is written from within an object)
590- source line
591- source file name
592- function name
593- message
594
595*Note: Source file name isn't captured by default. To enable it define PLOG_CAPTURE_FILE.*
596
597Also [Record](#record) has a number of overloaded stream output operators to construct a message.
598
599```cpp
600class Record
601{
602public:
603    Record(Severity severity, const char* func, size_t line, const char* file, const void* object);
604
605    //////////////////////////////////////////////////////////////////////////
606    // Stream output operators
607
608    Record& operator<<(char data);
609    Record& operator<<(wchar_t data);
610
611    template<typename T>
612    Record& operator<<(const T& data);
613
614    //////////////////////////////////////////////////////////////////////////
615    // Getters
616
617    virtual const util::Time& getTime() const;
618    virtual Severity getSeverity() const;
619    virtual unsigned int getTid() const;
620    virtual const void* getObject() const;
621    virtual size_t getLine() const;
622    virtual const util::nchar* getMessage() const;
623    virtual const char* getFunc() const;
624    virtual const char* getFile() const;
625    virtual int getInstanceId() const;
626};
627```
628
629*See [Stream improvements over std::ostream](#stream-improvements-over-stdostream).*
630
631*Refer to [Demo](samples/Demo) sample to see what can be written to the log stream.*
632
633## Formatter
634[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`:
635
636```cpp
637class Formatter
638{
639public:
640    static util::nstring header();
641    static util::nstring format(const Record& record);
642};
643```
644
645*See [How to implement a custom formatter](#custom-formatter).*
646
647### TxtFormatter
648This 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.
649
650```
6512014-11-11 00:29:06.245 FATAL [4460] [main@22] fatal
6522014-11-11 00:29:06.261 ERROR [4460] [main@23] error
6532014-11-11 00:29:06.261 INFO  [4460] [main@24] info
6542014-11-11 00:29:06.261 WARN  [4460] [main@25] warning
6552014-11-11 00:29:06.261 DEBUG [4460] [main@26] debug
6562014-11-11 00:29:06.261 INFO  [4460] [main@32] This is a message with "quotes"!
6572014-11-11 00:29:06.261 DEBUG [4460] [Object::Object@8]
6582014-11-11 00:29:06.261 DEBUG [4460] [Object::~Object@13]
659```
660
661### TxtFormatterUtcTime
662This is a variant of [TxtFormatter](#txtformatter) that uses UTC time instead of local time.
663
664### CsvFormatter
665This 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.
666
667```
668Date;Time;Severity;TID;This;Function;Message
6692014/11/14;15:22:25.033;FATAL;4188;00000000;main@22;"fatal"
6702014/11/14;15:22:25.033;ERROR;4188;00000000;main@23;"error"
6712014/11/14;15:22:25.033;INFO;4188;00000000;main@24;"info"
6722014/11/14;15:22:25.033;WARN;4188;00000000;main@25;"warning"
6732014/11/14;15:22:25.048;DEBUG;4188;00000000;main@26;"debug"
6742014/11/14;15:22:25.048;INFO;4188;00000000;main@32;"This is a message with ""quotes""!"
6752014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::Object@8;
6762014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::~Object@13;
677```
678
679*Note: message size is limited to 32000 chars.*
680
681### CsvFormatterUtcTime
682This is a variant of [CsvFormatter](#csvformatter) that uses UTC time instead of local time.
683
684### FuncMessageFormatter
685This format is designed to be used with appenders that provide their own timestamps (like [AndroidAppender](#androidappender) or linux syslog facility).
686
687```
688main@22: fatal
689main@23: error
690main@24: info
691main@25: warning
692main@26: debug
693main@32: This is a message with "quotes"!
694Object::Object@8:
695Object::~Object@13:
696```
697
698### MessageOnlyFormatter
699Use this formatter when you're interested only in a log message.
700
701```
702fatal
703error
704info
705warning
706debug
707This is a message with "quotes"!
708```
709
710## Converter
711[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`:
712
713```cpp
714class Converter
715{
716public:
717    static std::string header(const util::nstring& str);
718    static std::string convert(const util::nstring& str);
719};
720```
721
722*See [How to implement a custom converter](#custom-converter).*
723
724### UTF8Converter
725[UTF8Converter](#utf8converter) is a default converter in plog. It converts string data to UTF-8 with BOM.
726
727### NativeEOLConverter
728This converter converts `<LF>` line endings to `<CRLF>` on Windows and do nothing on everything else. As a template parameter it accepts another converter that is called next (by default [UTF8Converter](#utf8converter)).
729
730Sample:
731
732```cpp
733plog::RollingFileAppender<plog::TxtFormatter, plog::NativeEOLConverter<> > fileAppender("NativeEOL.log");
734```
735
736*Refer to [NativeEOL](samples/NativeEOL) for a complete sample.*
737
738## Appender
739[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):
740
741```cpp
742class IAppender
743{
744public:
745    virtual ~IAppender();
746    virtual void write(const Record& record) = 0;
747};
748```
749
750*See [How to implement a custom appender](#custom-appender).*
751
752### RollingFileAppender
753This appender outputs log data to a file with rolling behaviour. As template parameters it accepts both [Formatter](#formatter) and [Converter](#converter).
754
755```cpp
756RollingFileAppender<Formatter, Converter>::RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0);
757```
758
759- `fileName` - a log file name
760- `maxFileSize` - the maximum log file size in bytes
761- `maxFiles` - a number of log files to keep
762
763If `maxFileSize` or `maxFiles` is 0 then rolling behaviour is turned off.
764
765The sample file names produced by this appender:
766
767- mylog.log <== current log file (size < maxFileSize)
768- mylog.1.log <== previous log file (size >= maxFileSize)
769- mylog.2.log <== previous log file (size >= maxFileSize)
770
771Also a file name can be changed at arbitrary moment by calling `setFileName`.
772
773*Note: the lowest `maxFileSize` is 1000 bytes.*
774
775*Note: a log file is created on the first log message.*
776
777### ConsoleAppender
778This appender outputs log data to `stdout`.  As a template parameter it accepts [Formatter](#formatter).
779
780```cpp
781ConsoleAppender<Formatter>::ConsoleAppender();
782```
783
784### ColorConsoleAppender
785This appender outputs log data to `stdout` using colors that depends on a log message severity level.  As a template parameter it accepts [Formatter](#formatter).
786
787```cpp
788ColorConsoleAppender<Formatter>::ColorConsoleAppender();
789```
790
791### AndroidAppender
792[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)).
793
794```cpp
795AndroidAppender<Formatter>::AndroidAppender(const char* tag);
796```
797### EventLogAppender
798This 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).
799The 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.
800
801```cpp
802EventLogAppender<Formatter>::EventLogAppender(const wchar_t* sourceName);
803```
804
805[EventLogAppender](#eventlogappender) must be registered in the windows registry before use (before calling the constructor). There is a helper class for that:
806
807```cpp
808bool EventLogAppenderRegistry::add(const wchar_t* sourceName, const wchar_t* logName = L"Application");
809bool EventLogAppenderRegistry::exists(const wchar_t* sourceName, const wchar_t* logName = L"Application");
810void EventLogAppenderRegistry::remove(const wchar_t* sourceName, const wchar_t* logName = L"Application");
811```
812
813Registry operations are system-wide and require administrator rights. Also they are persistent so can be performed only once (when the application is installed/uninstalled).
814
815### DebugOutputAppender
816[DebugOutputAppender](#debugoutputappender) sends log data to the debugger (works only on Windows). As a template parameter this appender accepts [Formatter](#formatter).
817
818```cpp
819DebugOutputAppender<Formatter>::DebugOutputAppender();
820```
821
822# Miscellaneous notes
823
824## Lazy stream evaluation
825Log 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.
826
827```cpp
828PLOGD << /* the following statements will be executed only when the logger severity is debug or higher */ ...
829```
830
831## Stream improvements over std::ostream
832Stream output in plog has several improvements over the standard `std::ostream`:
833
834- handles wide chars/strings: `wchar_t`, `wchar_t*`, `std::wstring`
835- handles `NULL` values for C-strings: `char*` and `wchar_t*`
836- implicitly casts objects to: `std::string` and `std::wstring` (if they have an appropriate cast operator)
837- supports `QString` and `QStringRef` (you need to include Qt headers before plog)
838- supports managed C++ `System::String^`
839
840## Automatic 'this' pointer capture
841'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`.
842
843## Headers to include
844The core plog functionality is provided by inclusion of `plog/Log.h` file. Extra components require inclusion of corresponding extra headers after `plog/Log.h`.
845
846Core components are:
847- [TxtFormatter](#txtformatter)/[TxtFormatterUtcTime](#txtformatterutctime)
848- [CsvFormatter](#csvformatter)/[CsvFormatterUtcTime](#csvformatterutctime)
849- [UTF8Converter](#utf8converter)
850- [NativeEOLConverter](#nativeeolconverter)
851- [RollingFileAppender](#rollingfileappender)
852
853## Unicode
854Plog is unicode aware and wide string friendly. All messages are converted to a system native char type:
855
856- `wchar_t` - on Windows
857- `char` - on all other systems
858
859Also `char` is treated as:
860
861- active code page - on Windows
862- UTF-8 - on all other systems
863
864Internally plog uses `nstring`, `nstringstream` and `nchar` ('n' for native) that are defined as:
865
866```cpp
867#ifdef _WIN32
868    typedef std::wstring nstring;
869    typedef std::wstringstream nstringstream;
870    typedef wchar_t nchar;
871#else
872    typedef std::string nstring;
873    typedef std::stringstream nstringstream;
874    typedef char nchar;
875#endif
876```
877
878By default all log files are stored in UTF-8 with BOM thanks to [UTF8Converter](#utf8converter).
879
880## Wide string support
881
882Whether `wchar_t`, `wchar_t*`, `std::wstring` can be streamed to log messages or not is controlled by `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.
883
884*Note: wide string support requires linking to `iconv` on macOS.*
885
886## Performance
887Plog is not using any asynchronous techniques so it may slow down your application on large volumes of log messages.
888
889Producing a single log message takes the following amount of time:
890
891|CPU|OS|Time per a log call, microsec|
892|----|----|:----:|
893|AMD Phenom II 1055T @3.5GHz|Windows 2008 R2|12|
894|AMD Phenom II 1055T @3.5GHz|Linux Mint 17.1|8|
895|Intel Core i3-3120M @2.5GHz|Windows 2012 R2|25|
896|Intel Core i5-2500K @4.2GHz|Windows 2008 R2|8|
897|Intel Atom N270 @1.6GHz|Windows 2003|68|
898
899Assume 20 microsec per a log call then 500 log calls per a second will slow down an application by 1%. It is acceptable for the most use cases.
900
901*Refer to [Performance](samples/Performance) for a complete sample.*
902
903## Printf style formatting
904Plog supports printf style formatting:
905
906```cpp
907PLOGI.printf("%d %s", 42, "test");
908PLOGI.printf(L"%d %S", 42, "test"); // wchar_t version
909```
910
911## LOG_XXX macro name clashes
912`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 `LOG_XXX` macro by defining `PLOG_OMIT_LOG_DEFINES` and use `PLOG_XXX`.
913
914*Define `PLOG_OMIT_LOG_DEFINES` before `#include <plog/Log.h>` or in the project settings!*
915
916# Extending
917Plog can be easily extended to support new:
918
919- [custom data type](#custom-data-type)
920- [custom appender](#custom-appender)
921- [custom formatter](#custom-formatter)
922- [custom converter](#custom-converter)
923
924## Custom data type
925To output a custom data type to a log message implement the following function:
926
927```cpp
928namespace plog
929{
930    Record& operator<<(Record& record, const MyType& t);
931}
932```
933
934*Refer to [CustomType](samples/CustomType) for a complete sample.*
935
936## Custom appender
937A custom appender must implement `IAppender` interface. Also it may accept [Formatter](#formatter) and [Converter](#converter) as template parameters however this is optional.
938
939```cpp
940namespace plog
941{
942    template<class Formatter>
943    class MyAppender : public IAppender
944    {
945    public:
946        virtual void write(const Record& record);
947    };
948}
949```
950
951*Refer to [CustomAppender](samples/CustomAppender) for a complete sample.*
952
953## Custom formatter
954A formatter that is compatible with existing appenders must be a class with 2 static methods:
955
956- `header` - returns a header for a new log
957- `format` - formats [Record](#record) to a string
958
959```cpp
960namespace plog
961{
962    class MyFormatter
963    {
964    public:
965        static util::nstring header();
966        static util::nstring format(const Record& record);
967    };
968}
969```
970
971*Refer to [CustomFormatter](samples/CustomFormatter) for a complete sample.*
972
973## Custom converter
974A converter must be a class with 2 static methods:
975
976- `header` - converts a header for a new log
977- `convert` - converts log messages
978
979```cpp
980namespace plog
981{
982    class MyConverter
983    {
984    public:
985        static std::string header(const util::nstring& str);
986        static std::string convert(const util::nstring& str);
987    };
988}
989```
990
991*Refer to [CustomConverter](samples/CustomConverter) for a complete sample.*
992
993# Samples
994There are a number of samples that demonstrate various aspects of using plog. They can be found in the [samples](samples) folder:
995
996|Sample|Description|
997|------|-----------|
998|[Android](samples/Android)|Shows how to use [AndroidAppender](#androidappender).|
999|[Chained](samples/Chained)|Shows how to chain a logger in a shared library with the main logger (route messages).|
1000|[ColorConsole](samples/ColorConsole)|Shows how to use [ColorConsoleAppender](#colorconsoleappender).|
1001|[CustomAppender](samples/CustomAppender)|Shows how to implement a custom appender that stores log messages in memory.|
1002|[CustomFormatter](samples/CustomFormatter)|Shows how to implement a custom formatter.|
1003|[CustomConverter](samples/CustomConverter)|Shows how to implement a custom converter that encrypts log messages.|
1004|[CustomType](samples/CustomType)|Shows how to print a custom type to the log stream.|
1005|[DebugOutput](samples/DebugOutput)|Shows how to use [DebugOutputAppender](#debugoutputappender) to write to the windows debug output.|
1006|[Demo](samples/Demo)|Demonstrates log stream abilities, prints various types of messages.|
1007|[EventLog](samples/EventLog)|Shows how to use [EventLogAppender](#eventlogappender) to write to the windows event log.|
1008|[Facilities](samples/Facilities)|Shows how to use logging per facilities via multiple logger instances (useful for big projects).|
1009|[Hello](samples/Hello)|A minimal introduction sample, shows the basic 3 steps to start using plog.|
1010|[Library](samples/Library)|Shows plog usage in static libraries.|
1011|[MultiAppender](samples/MultiAppender)|Shows how to use multiple appenders with the same logger.|
1012|[MultiInstance](samples/MultiInstance)|Shows how to use multiple logger instances, each instance has its own independent configuration.|
1013|[ObjectiveC](samples/ObjectiveC)|Shows that plog can be used in ObjectiveC++.|
1014|[Performance](samples/Performance)|Measures time per a log call.|
1015|[SetFileName](samples/SetFileName)|Shows how to change a log file name at arbitrary moment.|
1016|[Shared](samples/Shared)|Shows how to share logger instances across binary modules.|
1017|[SkipNativeEOL](samples/SkipNativeEOL)|Shows how to skip [NativeEOLConverter](#nativeeolconverter).|
1018|[UtcTime](samples/UtcTime)|Shows how to use UTC time instead of local time.|
1019
1020# References
1021
1022## Competing C++ log libraries
1023
1024- [Boost::Log](http://www.boost.org/doc/libs/release/libs/log/)
1025- [EasyLogging++](https://github.com/easylogging/easyloggingpp)
1026- [g2log](http://www.codeproject.com/Articles/288827/g-log-An-efficient-asynchronous-logger-using-Cplus)
1027- [g3log](https://github.com/KjellKod/g3log)
1028- [glog](https://code.google.com/p/google-glog/)
1029- [Log4cplus](http://sourceforge.net/projects/log4cplus/)
1030- [Log4cpp](http://log4cpp.sourceforge.net/)
1031- [Log4cxx](http://logging.apache.org/log4cxx/)
1032- [Pantheios](http://pantheios.sourceforge.net/)
1033- [spdlog](https://github.com/gabime/spdlog/)
1034- [reckless](https://github.com/mattiasflodin/reckless)
1035- [loguru](https://github.com/emilk/loguru)
1036- [blackhole](https://github.com/3Hren/blackhole)
1037
1038## Tools and useful info
1039
1040- [__if_exists Statement](https://msdn.microsoft.com/en-us/library/x7wy9xh3.aspx)
1041- [Controlling Symbol Visibility](https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html)
1042- [Gravizo](http://gravizo.com)
1043- [PlantUML](http://plantuml.sourceforge.net)
1044- [DocToc](https://github.com/thlorenz/doctoc)
1045- [CMake](http://www.cmake.org)
1046
1047# License
1048Plog is licensed under the [MPL version 2.0](http://mozilla.org/MPL/2.0/). You can freely use it in your commercial or opensource software.
1049
1050# Version history
1051
1052## Version 1.1.5 (21 Oct 2019)
1053- New: Use `NativeEOLConverter` by default (#145)
1054- New: Add logger `instanceId` into `Record` (#141)
1055- New: Add support for the printf style formatting (#139)
1056- New: Make `severityFromString` case-insensitive
1057- 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)
1058- New: Add option for building samples (ON per default) (#125, #126)
1059- New: Add CMake installer (#121, #122)
1060- New: Add support for `QStringRef`
1061- New: Modernize CMake (#106)
1062- New: Allow rollLogFiles to be called manually (#100, #103)
1063- New: Add ability to use UTC time (#101)
1064- Fix: Disable `PLOG_GET_THIS()` by default (#120, #132)
1065- Fix: Change `RegSetValueExW` prototype to match windows native declaration (void* -> BYTE*)
1066- Fix: Move `System::String^` handler to a free function (#131)
1067- Fix: Making sure we can build standalone under Windows (#123)
1068- Fix: Parse error by ReSharper (#116)
1069- Fix: Parse error by Clang Code Model in Qt Creator (#114)
1070- Fix: Printing CustomType at begin of the stream (#94)
1071- Fix: Make `RollingFileAppender` work with maxFiles set to 1 (#70)
1072- Fix: Clang-tidy nullable issue
1073
1074## Version 1.1.4 (26 Mar 2018)
1075- New: Add `-Wundef` support
1076- New: Add [RTEMS](https://www.rtems.org) support (#87)
1077- New: Add Intel C++ Compiler support (#84)
1078- New: Add FreeBSD support (#83)
1079- New: Add `-Wnon-virtual-dtor` support (#79)
1080- New: Support `ostream` operator<< on Windows as well as `wostream` (#66)
1081- Fix: Fix compilation for Android (#68)
1082- Fix: Fix compiling with CMake 2.8
1083
1084## Version 1.1.3 (09 Aug 2017)
1085- New: Introduce `LOG_ENABLE_WCHAR_INPUT` macro to control wide string support
1086- New: Add support for managed C++ `System::String^` (#63)
1087- New: Add missing macros for logging with severity NONE (#61)
1088- Fix: Unable to build [NativeEOLConverter](#nativeeolconverter)/[UTF8Converter](#utf8converter) using Visual Studio (#59)
1089- Fix: Use `WriteConsoleW` instead of global `setlocale` for writing unicode into Windows console (#58)
1090- Fix: Mention about linking to `iconv` on macOS (#55)
1091- Fix: `IF_LOG` macro didn't work for curly braces blocks
1092
1093## Version 1.1.2 (02 May 2017)
1094- New: Add [NativeEOLConverter](#nativeeolconverter)
1095- New: Add [MessageOnlyFormatter](#messageonlyformatter)
1096- New: Slightly increase log performance on Windows (about 9%).
1097
1098## Version 1.1.1 (17 Apr 2017)
1099- New: Ability to check whether event log registry entry exists (#36)
1100- Fix: Update includes (#47)
1101- Fix: Get rid of `windows.h` dependency (#45, #13)
1102- Fix: Signed unsigned assignment warning (#40)
1103- Fix: Build warning on macOS 10.12 Sierra (#39)
1104
1105## Version 1.1.0 (20 Nov 2016)
1106- 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)
1107
1108## Version 1.0.2 (19 Nov 2016)
1109- New: Default instanceId can be set via `LOG_DEFAULT_INSTANCE` (#11)
1110- New: Support for `QString` (#30)
1111- New: Support for C++Builder
1112- New: `severityFromString` function (#15)
1113- New: Capture source file name (disabled by default) (#21)
1114- New: Add [DebugOutputAppender](#debugoutputappender) (#33)
1115- New: Add [EventLogAppender](#eventlogappender) (#32)
1116- Fix: Crash on processing Obj-C function name (#12)
1117- Fix: Compatibility with [MinGW](http://www.mingw.org/) (#17)
1118- Fix: `IF_LOG_` macro in if/else leads to miss else branch (#27)
1119- Fix: Thread safety for [ConsoleAppender](#consoleappender)/[ColorConsoleAppender](#colorconsoleappender) (#18, #29)
1120- Fix: Support for stream manipulators like `std::endl` (#31)
1121- Fix: Compatibility with old Visual Studio versions
1122
1123## Version 1.0.1 (01 Nov 2015)
1124- New: Add [ColorConsoleAppender](#colorconsoleappender)
1125- Fix: Compatibility with [Mingw-w64](http://mingw-w64.org/) (#6)
1126- Fix: Log file not created if file name contains Unicode characters in Windows (#7)
1127- Fix: Flush stdout (#4)
1128- Fix: IntelliSense error: expected an identifier (#3)
1129
1130## Version 1.0.0 (19 May 2015)
1131- Initial public release
1132