A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/SergiusTheBest/plog below:

SergiusTheBest/plog: Portable, simple and extensible C++ logging library

Plog - portable, simple and extensible C++ logging library

Pretty powerful logging library in about 1000 lines of code

Plog 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 and wide string support.

Here is a minimal hello log sample:

#include <plog/Log.h> // Step1: include the headers
#include "plog/Initializers/RollingFileInitializer.h"

int main()
{
    plog::init(plog::debug, "Hello.txt"); // Step2: initialize the logger

    // Step3: write log messages using a special macro
    // There are several log macros, use the macro you liked the most

    PLOGD << "Hello log!"; // short macro
    PLOG_DEBUG << "Hello log!"; // long macro
    PLOG(plog::debug) << "Hello log!"; // function-style macro
    
    // Also you can use LOG_XXX macro but it may clash with other logging libraries
    LOGD << "Hello log!"; // short macro
    LOG_DEBUG << "Hello log!"; // long macro
    LOG(plog::debug) << "Hello log!"; // function-style macro

    return 0;
}

And its output:

2015-05-18 23:12:43.921 DEBUG [21428] [main@13] Hello log!
2015-05-18 23:12:43.968 DEBUG [21428] [main@14] Hello log!
2015-05-18 23:12:43.968 DEBUG [21428] [main@15] Hello log!

Plog is a header-only C++ library, making it extremely easy to integrate into any project. You do not need to build or link any binaries — just add the headers to your include path. Here are several recommended ways to add Plog to your project:

Simply copy the plog directory into your source tree. For example:

.                           <-- root of your solution
├── README.md
└── src
    ├── 3rd-party           <-- directory for all 3rd-party dependencies
    │   └── plog            <-- plog is copied there
    │       ├── include     <-- add this to your include search path
    │       │   └── plog
    │       ├── LICENSE
    │       └── README.md
    ├── proj1
    └── proj2

Then, add src/3rd-party/plog/include to your project's include directories.

Add Plog as a git submodule to keep it up to date and track its version:

git submodule add https://github.com/SergiusTheBest/plog.git src/3rd-party/plog
git commit -m "Add plog as a submodule"

This approach allows you to easily update Plog and manage its version. Remember to add src/3rd-party/plog/include to your include path.

If you use CMake, you can add Plog directly to your build:

add_subdirectory(3rd-party/plog) # Adds plog to your CMake project

add_executable(myproj main.cpp)
target_link_libraries(myproj plog::plog) # Links and sets include path

Alternatively, use CMake's FetchContent to automatically download Plog at configure time:

include(FetchContent)

FetchContent_Declare(
    plog
    GIT_REPOSITORY https://github.com/SergiusTheBest/plog
    GIT_TAG        1.1.10
    GIT_SHALLOW    true
)
FetchContent_MakeAvailable(plog) # Downloads and adds plog to your CMake project

add_executable(myproj main.cpp)
target_link_libraries(myproj plog::plog) # Links and sets include path

Plog is also available via popular C++ package managers:

Refer to each package manager's documentation for the latest installation instructions and version details.

To start using plog you need to make 3 simple steps.

At first your project needs to know about plog. For that you have to:

  1. Add plog/include to the project include paths
  2. 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)

To use plog, you must initialize the logger by including the appropriate header and calling the corresponding plog::init overload:

Logger& init(Severity maxSeverity, ...

maxSeverity is the logger severity upper limit. Log messages with a severity value higher (less severe) than the limit are dropped.

Plog defines the following severity levels:

enum Severity
{
    none = 0,
    fatal = 1,
    error = 2,
    warning = 3,
    info = 4,
    debug = 5,
    verbose = 6
};

Note Messages with severity level none will always be printed.

Plog provides several convenient initializer functions to simplify logger setup for common use cases. These initializers configure the logger with typical appenders and formatters, so you can get started quickly without manually specifying all template parameters.

Use this when you want to log to a file with automatic rolling (rotation) based on size and count. Add #include <plog/Initializers/RollingFileInitializer.h> and call init:

Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0);

Example:

#include <plog/Log.h>
#include <plog/Initializers/RollingFileInitializer.h>

plog::init(plog::warning, "c:\\logs\\log.csv", 1000000, 5);

Here 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.

Use this to log to the console (stdout or stderr) with color output. Add #include <plog/Initializers/ConsoleInitializer.h> and call init:

Logger& init(Severity maxSeverity, OutputStream outputStream)

Example:

#include <plog/Log.h>
#include <plog/Initializers/ConsoleInitializer.h>

plog::init<plog::TxtFormatter>(plog::error, plog::streamStdErr); // logs error and above to stderr
Manual initialization (Init.h)

For advanced or custom setups add #include <plog/Init.h> and call init:

Logger& init(Severity maxSeverity = none, IAppender* appender = NULL);

You must construct and manage the appender yourself.

Example:

#include <plog/Log.h>
#include <plog/Init.h>

static plog::ConsoleAppender<plog::TxtFormatter> appender;
plog::init(plog::info, &appender); // logs info and above to the specified appender

Note See Custom initialization for advanced usage.

Logging 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.

This is the most used type of logging macros. They do unconditional logging.

PLOG_VERBOSE << "verbose";
PLOG_DEBUG << "debug";
PLOG_INFO << "info";
PLOG_WARNING << "warning";
PLOG_ERROR << "error";
PLOG_FATAL << "fatal";
PLOG_NONE << "none";
PLOGV << "verbose";
PLOGD << "debug";
PLOGI << "info";
PLOGW << "warning";
PLOGE << "error";
PLOGF << "fatal";
PLOGN << "none";
Conditional logging macros

These macros are used to do conditional logging. They accept a condition as a parameter and perform logging if the condition is true.

PLOG_VERBOSE_IF(cond) << "verbose";
PLOG_DEBUG_IF(cond) << "debug";
PLOG_INFO_IF(cond) << "info";
PLOG_WARNING_IF(cond) << "warning";
PLOG_ERROR_IF(cond) << "error";
PLOG_FATAL_IF(cond) << "fatal";
PLOG_NONE_IF(cond) << "none";
PLOGV_IF(cond) << "verbose";
PLOGD_IF(cond) << "debug";
PLOGI_IF(cond) << "info";
PLOGW_IF(cond) << "warning";
PLOGE_IF(cond) << "error";
PLOGF_IF(cond) << "fatal";
PLOGN_IF(cond) << "none";
PLOG_IF(severity, cond) << "msg";

In 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.

Sample:

IF_PLOG(plog::debug) // we want to execute the following statements only at debug severity (and higher)
{
    for (int i = 0; i < vec.size(); ++i)
    {
        PLOGD << "vec[" << i << "]: " << vec[i];
    }
}
Changing severity at runtime

It is possible to set the maximum severity not only at the logger initialization time but at any time later. There are special accessor methods:

Severity Logger::getMaxSeverity() const;
Logger::setMaxSeverity(Severity severity);

To get the logger use plog::get function:

Sample:

plog::get()->setMaxSeverity(plog::debug);

Non-typical log cases require the use of custom initialization. It is done by the following plog::init function:

Logger& init(Severity maxSeverity = none, IAppender* appender = NULL);

You have to construct an Appender parameterized with a Formatter and pass it to the plog::init function.

Note The appender lifetime should be static!

Sample:

static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender;
plog::init(plog::debug, &consoleAppender);

It is possible to have multiple Appenders within a single Logger. In such case log message will be written to all of them. Use the following method to accomplish that:

Logger& Logger::addAppender(IAppender* appender);

Sample:

static plog::RollingFileAppender<plog::CsvFormatter> fileAppender("MultiAppender.csv", 8000, 3); // Create the 1st appender.
static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender; // Create the 2nd appender.
plog::init(plog::debug, &fileAppender).addAppender(&consoleAppender); // Initialize the logger with the both appenders.

Here the logger is initialized in the way when log messages are written to both a file and a console.

Refer to MultiAppender for a complete sample.

Multiple Loggers can be used simultaneously each with their own separate configuration. The Loggers 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:

Logger<instanceId>& init<instanceId>(...);

To get a logger use plog::get function (returns NULL if the logger is not initialized):

Logger<instanceId>* get<instanceId>();

All logging macros have their special versions that accept an instanceId parameter. These kind of macros have an underscore at the end:

PLOGD_(instanceId) << "debug";
PLOGD_IF_(instanceId, condition) << "conditional debug";
IF_PLOG_(instanceId, severity)

Sample:

enum // Define log instanceIds. Default is 0 and is omitted from this enum.
{
    SecondLog = 1
};

int main()
{
    plog::init(plog::debug, "MultiInstance-default.txt"); // Initialize the default logger instance.
    plog::init<SecondLog>(plog::debug, "MultiInstance-second.txt"); // Initialize the 2nd logger instance.

    // Write some messages to the default log.
    PLOGD << "Hello default log!";

    // Write some messages to the 2nd log.
    PLOGD_(SecondLog) << "Hello second log!";

    return 0;
}

Refer to MultiInstance for a complete sample.

Share log instances across modules (exe, dll, so, dylib)

For 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.

Sharing behavior is controlled by the following macros and is OS-dependent:

Macro OS Behavior PLOG_GLOBAL Linux/Unix Shared PLOG_LOCAL Linux/Unix Local PLOG_EXPORT Linux/Unix n/a PLOG_IMPORT Linux/Unix n/a Linux/Unix According to compiler settings PLOG_GLOBAL Windows n/a PLOG_LOCAL Windows Local PLOG_EXPORT Windows Shared (exports) PLOG_IMPORT Windows Shared (imports) Windows Local

For 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).

Refer to Shared for a complete sample.

A Logger can work as an Appender for another Logger. So you can chain several loggers together. This is useful for streaming log messages from a shared library to the main application binary.

Important: don't forget to specify PLOG_LOCAL sharing mode on Linux/Unix systems for this sample.

Sample:

// shared library

// Function that initializes the logger in the shared library.
extern "C" void EXPORT initialize(plog::Severity severity, plog::IAppender* appender)
{
    plog::init(severity, appender); // Initialize the shared library logger.
}

// Function that produces a log message.
extern "C" void EXPORT foo()
{
    PLOGI << "Hello from shared lib!";
}
// main app

// Functions imported from the shared library.
extern "C" void initialize(plog::Severity severity, plog::IAppender* appender);
extern "C" void foo();

int main()
{
    plog::init(plog::debug, "ChainedApp.txt"); // Initialize the main logger.

    PLOGD << "Hello from app!"; // Write a log message.

    initialize(plog::debug, plog::get()); // Initialize the logger in the shared library. Note that it has its own severity.
    foo(); // Call a function from the shared library that produces a log message.

    return 0;
}

Refer to Chained for a complete sample.

Plog is designed to be small but flexible, so it prefers templates to interface inheritance. All main entities are shown on the following UML diagram:

classDiagram

class Logger~instanceId~ {
    <<singleton>>
    +addAppender()
    +getMaxSeverity()
    +setMaxSeverity()
    +checkSeverity()
    -maxSeverity
    -appenders
}

class IAppender {
    <<interface>>
    +write()
}

Logger --|> IAppender
Logger "1" o-- "*" IAppender

IAppender <|-- RollingFileAppender~Formatter, Converter~
IAppender <|-- ConsoleAppender~Formatter~
IAppender <|-- AndroidAppender~Formatter~
IAppender <|-- EventLogAppender~Formatter~
IAppender <|-- DebugOutputAppender~Formatter~
IAppender <|-- DynamicAppender

ConsoleAppender <|-- ColorConsoleAppender~Formatter~

DynamicAppender "1" o-- "*" IAppender
Loading
classDiagram

class Severity {
    <<enumeration>>
    none,
    fatal,
    error,
    warning,
    info,
    debug,
    verbose
}

class Record {
    +operator<<()
    +printf()
    -time
    -severity
    -tid
    -object
    -line
    -message
    -func
    -file
    -instanceId
}    
Loading
classDiagram

class CsvFormatter {
    +header()$
    +format()$
}

class TxtFormatter {
    +header()$
    +format()$
}

class FuncMessageFormatter {
    +header()$
    +format()$
}

class MessageOnlyFormatter {
    +header()$
    +format()$
}
Loading
classDiagram

class UTF8Converter {
    +header()$
    +convert()$
}

class NativeEOLConverter~NextConverter~{
    +header()$
    +convert()$
}
Loading

There are 5 functional parts:

The log data flow is shown below:

flowchart LR;
    ST((start)) --> P[PLOG macro] --> R[Record] --> L[Logger] --> A[Appender]
    A -->|record| F[Formatter] -->|text| C[Converter] -->|binary| A
    A --> FIN(((finish)))
Loading

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 can act as Appender for another 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.

template<int instanceId>
class Logger : public util::Singleton<Logger<instanceId> >, public IAppender
{
public:
    Logger(Severity maxSeverity = none);

    Logger& addAppender(IAppender* appender);

    Severity getMaxSeverity() const;
    void setMaxSeverity(Severity severity);
    bool checkSeverity(Severity severity) const;

    virtual void write(const Record& record);
    void operator+=(const Record& record);
};

Record stores all log data. It includes:

Note Source file name isn't captured by default. To enable it define PLOG_CAPTURE_FILE.

Also Record has a number of overloaded stream output operators to construct a message.

class Record
{
public:
    Record(Severity severity, const char* func, size_t line, const char* file, const void* object, int instanceId);

    //////////////////////////////////////////////////////////////////////////
    // Stream output operators

    Record& operator<<(char data);
    Record& operator<<(wchar_t data);

    template<typename T>
    Record& operator<<(const T& data);

    //////////////////////////////////////////////////////////////////////////
    // Getters

    virtual const util::Time& getTime() const;
    virtual Severity getSeverity() const;
    virtual unsigned int getTid() const;
    virtual const void* getObject() const;
    virtual size_t getLine() const;
    virtual const util::nchar* getMessage() const;
    virtual const char* getFunc() const;
    virtual const char* getFile() const;
    virtual int getInstanceId() const;
};

See Stream improvements over std::ostream.

Refer to Demo sample to see what can be written to the log stream.

Formatter is responsible for formatting log data from 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:

class Formatter
{
public:
    static util::nstring header();
    static util::nstring format(const Record& record);
};

See How to implement a custom formatter.

This 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.

2014-11-11 00:29:06.245 FATAL [4460] [main@22] fatal
2014-11-11 00:29:06.261 ERROR [4460] [main@23] error
2014-11-11 00:29:06.261 INFO  [4460] [main@24] info
2014-11-11 00:29:06.261 WARN  [4460] [main@25] warning
2014-11-11 00:29:06.261 DEBUG [4460] [main@26] debug
2014-11-11 00:29:06.261 INFO  [4460] [main@32] This is a message with "quotes"!
2014-11-11 00:29:06.261 DEBUG [4460] [Object::Object@8]
2014-11-11 00:29:06.261 DEBUG [4460] [Object::~Object@13]

This is a variant of TxtFormatter that uses UTC time instead of local time.

This is the most powerful log format. It can be easily read without any tools (but slighlty harder than TXT format) 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.

Date;Time;Severity;TID;This;Function;Message
2014/11/14;15:22:25.033;FATAL;4188;00000000;main@22;"fatal"
2014/11/14;15:22:25.033;ERROR;4188;00000000;main@23;"error"
2014/11/14;15:22:25.033;INFO;4188;00000000;main@24;"info"
2014/11/14;15:22:25.033;WARN;4188;00000000;main@25;"warning"
2014/11/14;15:22:25.048;DEBUG;4188;00000000;main@26;"debug"
2014/11/14;15:22:25.048;INFO;4188;00000000;main@32;"This is a message with ""quotes""!"
2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::Object@8;
2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::~Object@13;

Note Message size is limited to 32000 chars.

This is a variant of CsvFormatter that uses UTC time instead of local time.

This format is designed to be used with appenders that provide their own timestamps (like AndroidAppender or linux syslog facility).

main@22: fatal
main@23: error
main@24: info
main@25: warning
main@26: debug
main@32: This is a message with "quotes"!
Object::Object@8:
Object::~Object@13:

Use this formatter when you're interested only in a log message.

fatal
error
info
warning
debug
This is a message with "quotes"!

Converter is responsible for conversion of Formatter output data to a raw buffer (represented as std::string). It is used by 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:

class Converter
{
public:
    static std::string header(const util::nstring& str);
    static std::string convert(const util::nstring& str);
};

See How to implement a custom converter.

UTF8Converter is a default converter in plog. It converts string data to UTF-8 with BOM.

This converter converts <LF> line endings to <CRLF> on Windows and does nothing on everything else. As a template parameter it accepts another converter that is called next (by default UTF8Converter).

Sample:

plog::RollingFileAppender<plog::TxtFormatter, plog::NativeEOLConverter<> > fileAppender("NativeEOL.log");

Refer to NativeEOL for a complete sample.

Appender uses Formatter and 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):

class IAppender
{
public:
    virtual ~IAppender();
    virtual void write(const Record& record) = 0;
};

See How to implement a custom appender.

This appender outputs log data to a file with rolling behavior. As template parameters it accepts both Formatter and Converter.

RollingFileAppender<Formatter, Converter>::RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0);

If maxFileSize or maxFiles is 0 then rolling behavior is turned off.

The sample file names produced by this appender:

A 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.

Note The lowest maxFileSize is 1000 bytes.

Note A log file is created on the first log message.

This appender outputs log data to stdout or stderr. As a template parameter it accepts Formatter.

ConsoleAppender<Formatter>::ConsoleAppender(OutputStream outStream = streamStdOut);

This 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.

ColorConsoleAppender<Formatter>::ColorConsoleAppender(OutputStream outStream = streamStdOut);

AndroidAppender uses Android logging system to output log data. It can be viewed with logcat or in a log window of Android IDEs. As a template parameter this appender accepts Formatter (usually FuncMessageFormatter).

AndroidAppender<Formatter>::AndroidAppender(const char* tag);

This 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. The 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.

EventLogAppender<Formatter>::EventLogAppender(const wchar_t* sourceName);

EventLogAppender must be registered in the windows registry before use (before calling the constructor). There is a helper class for that:

bool EventLogAppenderRegistry::add(const wchar_t* sourceName, const wchar_t* logName = L"Application");
bool EventLogAppenderRegistry::exists(const wchar_t* sourceName, const wchar_t* logName = L"Application");
void EventLogAppenderRegistry::remove(const wchar_t* sourceName, const wchar_t* logName = L"Application");

Registry operations are system-wide and require administrator rights. Also they are persistent so can be performed only once (when the application is installed/uninstalled).

DebugOutputAppender sends log data to the debugger (works only on Windows). As a template parameter this appender accepts Formatter.

DebugOutputAppender<Formatter>::DebugOutputAppender();

This appender outputs log data to an Arduino device, typically over a serial connection. As a template parameter, it accepts a Formatter.

ArduinoAppender<Formatter>::ArduinoAppender(Stream& stream);

This appender is useful for embedded systems or IoT projects where you want to monitor logs directly from an Arduino board.

Refer to Arduino sample for a complete sample.

DynamicAppender is a wrapper that can add/remove appenders dynamically (at any point of time) in a thread-safe manner.

DynamicAppender& DynamicAppender::addAppender(IAppender* appender);
DynamicAppender& DynamicAppender::removeAppender(IAppender* appender);

Refer to DynamicAppender sample for a complete sample.

Log 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.

PLOGD << /* the following statements will be executed only when the logger severity is debug or higher */ ...
Stream improvements over std::ostream

Stream output in plog has several improvements over the standard std::ostream:

Automatic 'this' pointer capture

'This' pointer is captured automatically to log data and can be printed by 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.

The core plog functionality is provided by inclusion of plog/Log.h file. Extra components require inclusion of corresponding extra headers after plog/Log.h.

Core components are:

Plog is unicode aware and wide string friendly. All messages are converted to a system native char type:

Also char is treated as:

Internally plog uses nstring, nstringstream and nchar ('n' for native) that are defined as:

#if PLOG_CHAR_IS_UTF8
    typedef std::string nstring;
    typedef std::ostringstream nostringstream;
    typedef std::istringstream nistringstream;
    typedef std::ostream nostream;
    typedef char nchar;
#else
    typedef std::wstring nstring;
    typedef std::wostringstream nostringstream;
    typedef std::wistringstream nistringstream;
    typedef std::wostream nostream;
    typedef wchar_t nchar;
#endif

By default all log files are stored in UTF-8 with BOM thanks to UTF8Converter.

Whether 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.

Note Wide string support requires linking to iconv on macOS.

Plog is not using any asynchronous techniques so it may slow down your application on large volumes of log messages.

Producing a single log message takes the following amount of time:

CPU OS Time per a log call, microsec AMD Phenom II 1055T @3.5GHz Windows 2008 R2 12 AMD Phenom II 1055T @3.5GHz Linux Mint 17.1 8 Intel Core i3-3120M @2.5GHz Windows 2012 R2 25 Intel Core i5-2500K @4.2GHz Windows 2008 R2 8 Intel Atom N270 @1.6GHz Windows 2003 68

Assume 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.

Refer to Performance for a complete sample.

Plog supports printf style formatting:

PLOGI.printf("%d %s", 42, "test");
PLOGI.printf(L"%d %S", 42, "test"); // wchar_t version
LOG_XXX macro name clashes

LOG_XXX macro names may be in conflict with other libraries (for example syslog). In such cases you can disable the LOG_XXX macro by defining PLOG_OMIT_LOG_DEFINES and use PLOG_XXX.

Define PLOG_OMIT_LOG_DEFINES before #include <plog/Log.h> or in the project settings!

Disable logging to reduce binary size

Logging 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.

You can customize the prefix that appears before every log message by defining the PLOG_MESSAGE_PREFIX macro before including plog headers. This is useful for distinguishing log output from different modules or for adding custom tags to every log line.

Example:

#define PLOG_MESSAGE_PREFIX "[MyApp] "
#include <plog/Log.h>
#include <plog/Initializers/RollingFileInitializer.h>

int main() 
{
    plog::init(plog::debug, "log.txt");
    PLOGD << "This is a debug message.";
    return 0;
}

This will produce log lines prefixed with [MyApp] .

Note: The macro must be defined before including any plog headers to take effect.

Plog can be easily extended to support new:

To output a custom data type to a log message implement the following function:

namespace plog
{
    Record& operator<<(Record& record, const MyType& t);
}

Refer to CustomType for a complete sample.

A custom appender must implement the IAppender interface. Also it may accept Formatter and Converter as template parameters however this is optional.

namespace plog
{
    template<class Formatter>
    class MyAppender : public IAppender
    {
    public:
        virtual void write(const Record& record);
    };
}

Refer to CustomAppender for a complete sample.

A formatter that is compatible with existing appenders must be a class with 2 static methods:

namespace plog
{
    class MyFormatter
    {
    public:
        static util::nstring header();
        static util::nstring format(const Record& record);
    };
}

Refer to CustomFormatter for a complete sample.

A converter must be a class with 2 static methods:

namespace plog
{
    class MyConverter
    {
    public:
        static std::string header(const util::nstring& str);
        static std::string convert(const util::nstring& str);
    };
}

Refer to CustomConverter for a complete sample.

There are a number of samples that demonstrate various aspects of using plog. They can be found in the samples folder:

Sample Description Android Shows how to use AndroidAppender. Arduino Arduino sample - shows how to use ArduinoAppender AscDump Shows how to use plog::ascdump to dump binary buffers into ASCII. Chained Shows how to chain a logger in a shared library with the main logger (route messages). ColorConsole Shows how to use ColorConsoleAppender. CustomAppender Shows how to implement a custom appender that stores log messages in memory. CustomConverter Shows how to implement a custom converter that encrypts log messages. CustomFormatter Shows how to implement a custom formatter. CustomType Shows how to print a custom type to the log stream. CXX11 Demonstrates log stream abilities for C++11 features. CXX17 Demonstrates log stream abilities for C++17 features. DebugOutput Shows how to use DebugOutputAppender to write to the windows debug output. Demo Demonstrates log stream abilities, prints various types of messages. DisableLogging Shows how to disable logging (so it will be stripped from the binary). DynamicAppender Shows how to add/remove appenders dynamically). EventLog Shows how to use EventLogAppender to write to the windows event log. Facilities Shows how to use logging per facilities via multiple logger instances (useful for big projects). Hello A minimal introduction sample, shows the basic 3 steps to start using plog. HexDump Shows how to use plog::hexdump to dump binary buffers into hex. Library Shows plog usage in static libraries. MessagePrefix Demonstrates usage of the PLOG_MESSAGE_PREFIX macro to add a custom prefix to every log message. MultiAppender Shows how to use multiple appenders with the same logger. MultiInstance Shows how to use multiple logger instances, each instance has its own independent configuration. 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). ObjectiveC Shows that plog can be used in ObjectiveC++. Path A test sample to check that std::filesystem::path can be logged. Performance Measures time per a log call. PrintVar Shows how to use PLOG_PRINT_VAR to print variables. SetFileName Shows how to change a log file name at arbitrary moment. Shared Shows how to share logger instances across binary modules (this is the default behavior on everything except Windows, so be careful) SkipNativeEOL Shows how to skip NativeEOLConverter. UtcTime Shows how to use UTC time instead of local time. Utf8Everywhere Demonstrates how to use http://utf8everywhere.org on Windows.

This version of plog is licensed under the MIT license. You can freely use it in your commercial or opensource software.

Version 1.1.11 (11 Aug 2025) Version 1.1.10 (20 Aug 2023) Version 1.1.9 (16 Dec 2022) Version 1.1.8 (10 Jun 2022) Version 1.1.7 (09 Jun 2022) Version 1.1.6 (06 Feb 2022) Version 1.1.5 (21 Oct 2019) Version 1.1.4 (26 Mar 2018) Version 1.1.3 (09 Aug 2017) Version 1.1.2 (02 May 2017) Version 1.1.1 (17 Apr 2017) Version 1.1.0 (20 Nov 2016) Version 1.0.2 (19 Nov 2016) Version 1.0.1 (01 Nov 2015) Version 1.0.0 (19 May 2015)

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4