Portable, simple and extensible C++ logging library

Overview

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

Pretty powerful logging library in about 1000 lines of code Build Status Build status CircleCI Build Status

Introduction

Hello log!

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] [[email protected]] Hello log!
2015-05-18 23:12:43.968 DEBUG [21428] [[email protected]] Hello log!
2015-05-18 23:12:43.968 DEBUG [21428] [[email protected]] Hello log!

Features

Usage

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

Step 1: Adding includes

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)

Step 2: Initialization

The next step is to initialize the Logger. This is done by the following plog::init function:

Logger& init(Severity maxSeverity, const char/wchar_t* fileName, size_t maxFileSize = 0, int maxFiles = 0);

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:

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

Note: messages with severity level none will be always printed.

The log format is determined automatically by fileName file extension:

The rolling behavior is controlled by maxFileSize and maxFiles parameters:

  • maxFileSize - the maximum log file size in bytes
  • maxFiles - a number of log files to keep

If one of them is zero then log rolling is disabled.

Sample:

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.

Note: see Custom initialization for advanced usage.

Step 3: Logging

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.

Basic logging macros

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

Long macros:

PLOG_VERBOSE << "verbose";
PLOG_DEBUG << "debug";
PLOG_INFO << "info";
PLOG_WARNING << "warning";
PLOG_ERROR << "error";
PLOG_FATAL << "fatal";
PLOG_NONE << "none";

Short macros:

PLOGV << "verbose";
PLOGD << "debug";
PLOGI << "info";
PLOGW << "warning";
PLOGE << "error";
PLOGF << "fatal";
PLOGN << "none";

Function-style macros:

PLOG(severity) << "msg";

Conditional logging macros

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

Long macros:

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";

Short macros:

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";

Function-style macros:

PLOG_IF(severity, cond) << "msg";

Logger severity checker

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.

IF_PLOG(severity)

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];
    }
}

Advanced usage

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:

Logger* get();

Sample:

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

Custom initialization

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: a lifetime of the appender should be static!

Sample:

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

Multiple appenders

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

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

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

Chained loggers

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

Architecture

Overview

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:

Plog class diagram

There are 5 functional parts:

  • Logger - the main object, implemented as singleton
  • Record - keeps log data: time, message, etc
  • Appender - represents a log data destination: file, console, etc
  • Formatter - formats log data into a string
  • Converter - converts formatter output into a raw buffer

The log data flow is shown below:

Log data flow

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

Record stores all log data. It includes:

  • time
  • severity
  • thread id
  • 'this' pointer (if a log message is written from within an object)
  • source line
  • source file name
  • function name
  • message

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);

    //////////////////////////////////////////////////////////////////////////
    // 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

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.

TxtFormatter

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] [[email protected]] fatal
2014-11-11 00:29:06.261 ERROR [4460] [[email protected]] error
2014-11-11 00:29:06.261 INFO  [4460] [[email protected]] info
2014-11-11 00:29:06.261 WARN  [4460] [[email protected]] warning
2014-11-11 00:29:06.261 DEBUG [4460] [[email protected]] debug
2014-11-11 00:29:06.261 INFO  [4460] [[email protected]] This is a message with "quotes"!
2014-11-11 00:29:06.261 DEBUG [4460] [Object::[email protected]]
2014-11-11 00:29:06.261 DEBUG [4460] [Object::[email protected]]

TxtFormatterUtcTime

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

CsvFormatter

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;[email protected];"fatal"
2014/11/14;15:22:25.033;ERROR;4188;00000000;[email protected];"error"
2014/11/14;15:22:25.033;INFO;4188;00000000;[email protected];"info"
2014/11/14;15:22:25.033;WARN;4188;00000000;[email protected];"warning"
2014/11/14;15:22:25.048;DEBUG;4188;00000000;[email protected];"debug"
2014/11/14;15:22:25.048;INFO;4188;00000000;[email protected];"This is a message with ""quotes""!"
2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::[email protected];
2014/11/14;15:22:25.048;DEBUG;4188;002EF4E3;Object::[email protected];

Note: message size is limited to 32000 chars.

CsvFormatterUtcTime

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

FuncMessageFormatter

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

[email protected]: fatal
[email protected]: error
[email protected]: info
[email protected]: warning
[email protected]: debug
[email protected]: This is a message with "quotes"!
Object::[email protected]:
Object::[email protected]:

MessageOnlyFormatter

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

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

Converter

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

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

NativeEOLConverter

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

Sample:

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

Refer to NativeEOL for a complete sample.

Appender

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.

RollingFileAppender

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

RollingFileAppender<Formatter, Converter>::RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0);
  • fileName - a log file name
  • maxFileSize - the maximum log file size in bytes
  • maxFiles - a number of log files to keep

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

The sample file names produced by this appender:

  • mylog.log <== current log file (size < maxFileSize)
  • mylog.1.log <== previous log file (size >= maxFileSize)
  • mylog.2.log <== previous log file (size >= maxFileSize)

Also a file name can be changed at arbitrary moment by calling setFileName.

Note: the lowest maxFileSize is 1000 bytes.

Note: a log file is created on the first log message.

ConsoleAppender

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

ConsoleAppender<Formatter>::ConsoleAppender();

ColorConsoleAppender

This appender outputs log data to stdout using colors that depends on a log message severity level. As a template parameter it accepts Formatter.

ColorConsoleAppender<Formatter>::ColorConsoleAppender();

AndroidAppender

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);

EventLogAppender

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

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

DebugOutputAppender<Formatter>::DebugOutputAppender();

Miscellaneous notes

Lazy stream evaluation

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:

  • handles wide chars/strings: wchar_t, wchar_t*, std::wstring
  • handles NULL values for C-strings: char* and wchar_t*
  • implicitly casts objects to: std::string and std::wstring (if they have an appropriate cast operator)
  • supports QString and QStringRef (you need to include Qt headers before plog)
  • supports managed C++ System::String^

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.

Headers to include

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:

Unicode

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

  • wchar_t - on Windows
  • char - on all other systems

Also char is treated as:

  • active code page - on Windows
  • UTF-8 - on all other systems

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

#ifdef _WIN32
    typedef std::wstring nstring;
    typedef std::wstringstream nstringstream;
    typedef wchar_t nchar;
#else
    typedef std::string nstring;
    typedef std::stringstream nstringstream;
    typedef char nchar;
#endif

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

Wide string support

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

Note: wide string support requires linking to iconv on macOS.

Performance

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 the most use cases.

Refer to Performance for a complete sample.

Printf style formatting

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 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!

Extending

Plog can be easily extended to support new:

Custom data type

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.

Custom appender

A custom appender must implement 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.

Custom formatter

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

  • header - returns a header for a new log
  • format - formats Record to a string
namespace plog
{
    class MyFormatter
    {
    public:
        static util::nstring header();
        static util::nstring format(const Record& record);
    };
}

Refer to CustomFormatter for a complete sample.

Custom converter

A converter must be a class with 2 static methods:

  • header - converts a header for a new log
  • convert - converts log messages
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.

Samples

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.
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.
CustomFormatter Shows how to implement a custom formatter.
CustomConverter Shows how to implement a custom converter that encrypts log messages.
CustomType Shows how to print a custom type to the log stream.
DebugOutput Shows how to use DebugOutputAppender to write to the windows debug output.
Demo Demonstrates log stream abilities, prints various types of messages.
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.
Library Shows plog usage in static libraries.
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.
ObjectiveC Shows that plog can be used in ObjectiveC++.
Performance Measures time per a log call.
SetFileName Shows how to change a log file name at arbitrary moment.
Shared Shows how to share logger instances across binary modules.
SkipNativeEOL Shows how to skip NativeEOLConverter.
UtcTime Shows how to use UTC time instead of local time.

References

Competing C++ log libraries

Tools and useful info

License

Plog is licensed under the MPL version 2.0. You can freely use it in your commercial or opensource software.

Version history

Version 1.1.5 (21 Oct 2019)

  • New: Use NativeEOLConverter by default (#145)
  • New: Add logger instanceId into Record (#141)
  • New: Add support for the printf style formatting (#139)
  • New: Make severityFromString case-insensitive
  • 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)
  • New: Add option for building samples (ON per default) (#125, #126)
  • New: Add CMake installer (#121, #122)
  • New: Add support for QStringRef
  • New: Modernize CMake (#106)
  • New: Allow rollLogFiles to be called manually (#100, #103)
  • New: Add ability to use UTC time (#101)
  • Fix: Disable PLOG_GET_THIS() by default (#120, #132)
  • Fix: Change RegSetValueExW prototype to match windows native declaration (void* -> BYTE*)
  • Fix: Move System::String^ handler to a free function (#131)
  • Fix: Making sure we can build standalone under Windows (#123)
  • Fix: Parse error by ReSharper (#116)
  • Fix: Parse error by Clang Code Model in Qt Creator (#114)
  • Fix: Printing CustomType at begin of the stream (#94)
  • Fix: Make RollingFileAppender work with maxFiles set to 1 (#70)
  • Fix: Clang-tidy nullable issue

Version 1.1.4 (26 Mar 2018)

  • New: Add -Wundef support
  • New: Add RTEMS support (#87)
  • New: Add Intel C++ Compiler support (#84)
  • New: Add FreeBSD support (#83)
  • New: Add -Wnon-virtual-dtor support (#79)
  • New: Support ostream operator<< on Windows as well as wostream (#66)
  • Fix: Fix compilation for Android (#68)
  • Fix: Fix compiling with CMake 2.8

Version 1.1.3 (09 Aug 2017)

  • New: Introduce LOG_ENABLE_WCHAR_INPUT macro to control wide string support
  • New: Add support for managed C++ System::String^ (#63)
  • New: Add missing macros for logging with severity NONE (#61)
  • Fix: Unable to build NativeEOLConverter/UTF8Converter using Visual Studio (#59)
  • Fix: Use WriteConsoleW instead of global setlocale for writing unicode into Windows console (#58)
  • Fix: Mention about linking to iconv on macOS (#55)
  • Fix: IF_LOG macro didn't work for curly braces blocks

Version 1.1.2 (02 May 2017)

Version 1.1.1 (17 Apr 2017)

  • New: Ability to check whether event log registry entry exists (#36)
  • Fix: Update includes (#47)
  • Fix: Get rid of windows.h dependency (#45, #13)
  • Fix: Signed unsigned assignment warning (#40)
  • Fix: Build warning on macOS 10.12 Sierra (#39)

Version 1.1.0 (20 Nov 2016)

  • Fix: Introduce binary compatible interface to Record (WARNING: this is not compatible with 1.0.x version in Chained mode, so don't mix 1.1.x and 1.0.x) (#34)

Version 1.0.2 (19 Nov 2016)

  • New: Default instanceId can be set via LOG_DEFAULT_INSTANCE (#11)
  • New: Support for QString (#30)
  • New: Support for C++Builder
  • New: severityFromString function (#15)
  • New: Capture source file name (disabled by default) (#21)
  • New: Add DebugOutputAppender (#33)
  • New: Add EventLogAppender (#32)
  • Fix: Crash on processing Obj-C function name (#12)
  • Fix: Compatibility with MinGW (#17)
  • Fix: IF_LOG_ macro in if/else leads to miss else branch (#27)
  • Fix: Thread safety for ConsoleAppender/ColorConsoleAppender (#18, #29)
  • Fix: Support for stream manipulators like std::endl (#31)
  • Fix: Compatibility with old Visual Studio versions

Version 1.0.1 (01 Nov 2015)

  • New: Add ColorConsoleAppender
  • Fix: Compatibility with Mingw-w64 (#6)
  • Fix: Log file not created if file name contains Unicode characters in Windows (#7)
  • Fix: Flush stdout (#4)
  • Fix: IntelliSense error: expected an identifier (#3)

Version 1.0.0 (19 May 2015)

  • Initial public release
Comments
  • How to destroy the plog logger instance?

    How to destroy the plog logger instance?

    Hi, the plog repo is pretty cool and it's quite suitable for cross-platform, and I met some problem when I use it.

    I init the plog instance in my class, something like below:

    class A {
    public:
         A();
         ~A();
    private:
        plog::ConsoleAppender<plog::TxtFormatter> console_appender_;
    };
    
    A::A() {
       plog::init(plog::verbose, &console_appender_);
    }
    
    A::~A() {
    }
    
    A* a = new A();
    delete a;
    A* a = new A();
    

    and I got crash, how to destroy the plog instance? Or how can I re-init the plog instance?

    Thank you!

    question 
    opened by Learningm 11
  • included plog, instantly got error

    included plog, instantly got error "expected expression"

    They way this lib is supposed to work looks great, so I gave it a try. But it does not seem to work for me, with even minimal code. (In my DLL):

    plog::init(plog::debug, "Hello.txt"); // Step2: initialize the logger.
    
    LOGD << "Hello log!"; // short macro
    

    Instantly gives me an error "expected expression" image

    I use Visual Studio 2017 compiler, CMake and Qt Creator as IDE. I don't think this is normal. Any ideas? Maybe it does not work with msvc14.1 compiler? In IDE: image

    bug 
    opened by Amazonasmann 11
  • plog tremendously slow down speed

    plog tremendously slow down speed

    I'm doing a network project. The process has two threads. One thread(thread A) for libpcap capturing data, another thread(thread B) for receiving(passed by threadA throw unix socket) and sending(via raw socket stuff. NOT system socket) data. I meet a very strange problem with plog. Remove some lines of code will tremendously slow network speed macOS. But add them will work fine. ( 1MB/s vs 200KB/s) The full code is here:

    // a very frequent operation
    int RawTcp::RawInput(u_char *args, const pcap_pkthdr *hdr, const u_char *packet) {
        if (hdr->len < 44) {    // ip_len + tcp_len
            return 0;
        }
    
        struct ip *ip = nullptr;
        if (mDatalink == DLT_EN10MB) {    // ethernet
            struct oetherhdr *eth = (struct oetherhdr *) packet;
            if (eth->ether_type != OM_PROTO_IP) {
                LOGE << "ethernet. only ipv4 protocol is supported. proto: " << eth->ether_type;
                return 0;
            }
    
            ip = (struct ip *) (packet + LIBNET_ETH_H);
        } else if (mDatalink == DLT_NULL) {   // loopback
            uint32_t type = 0;
            decode_uint32(&type, reinterpret_cast<const char *>(packet));
            // the link layer header is a 4-byte field, in host byte order, containing a value of 2 for IPv4 packets
            // https://www.tcpdump.org/linktypes.html
            if (2 != type) {
                LOGE << "loopback. only ipv4 protocol is supported. proto: " << type;
                return 0;
            }
            ip = (struct ip *) (packet + 4);
        } else {
            LOGE << "unsupported datalink type: " << mDatalink;
    #ifndef RSOCK_NNDEBUG
            assert(0);
    #else
            return 0;
    #endif
        }
    
        const int proto = ip->ip_p;
    
        if (proto != IPPROTO_TCP) {
            LOGE << "only tcp are supported. proto: " << proto;
            return 0;
        }
    
        struct tcphdr *tcp = (struct tcphdr *) ((const char *) ip + (ip->ip_hl << 2));
        const char *payload = (const char *) tcp + (tcp->th_off << 2);
    
        const int payload_len = ntohs(ip->ip_len) - ((const u_char *) payload - (const u_char *) ip);
    
        if (payload_len >= 0) {
            std::string flag;
            if (tcp->th_flags & TH_SYN) {
                flag += "SYN|";
            }
    
    // Remove this if-else clause will tremendously slow down speed {@
            if (plog::get()->getMaxSeverity() > plog::verbose) {
                if (tcp->th_flags & (~TH_ACK)) {
                    LOGD << "receive " << payload_len << " bytes from " << InAddr2Ip({ip->ip_src}) << ":"
                         << ntohs(tcp->th_sport)
                         << "<->" << InAddr2Ip({ip->ip_dst}) << ":" << ntohs(tcp->th_dport) << ", flag: " << flag;
                }
            } else {
                LOGV << "receive " << payload_len << " bytes from " << InAddr2Ip({ip->ip_src}) << ":"
                     << ntohs(tcp->th_sport)
                     << "<->" << InAddr2Ip({ip->ip_dst}) << ":" << ntohs(tcp->th_dport) << ", flag: " << flag;
            }
        } // @}
    
        TcpInfo info;
        info.src = ip->ip_dst.s_addr;
        info.sp = ntohs(tcp->th_dport);
        info.dst = ip->ip_src.s_addr;
        info.dp = ntohs(tcp->th_sport);
        info.seq = ntohl(tcp->th_seq);
        info.ack = ntohl(tcp->th_ack);
        info.flag = tcp->th_flags;
    
        if ((tcp->th_flags & TH_SYN) && mTcpAckPool) {   // todo: don't process here
            if (mIsServer) {
                info.Reverse();
            }
            // must be called in this thread. because it may cause dead lock if in same thread.
            mTcpAckPool->AddInfoFromPeer(info, tcp->th_flags);
            return 0;
        }
    
        // this check is necessary.
        // because we may receive rst with length zero. if we don't check, we may cause illegal memory access error
        if (payload_len < HASH_BUF_SIZE + 1 && !info.HasCloseFlag()) {  // don't deliver unnecessary data
            return 0;
        }
        info.seq += payload_len;
        return cap2uv(&info, payload, payload_len);
    }
    
    int RawTcp::cap2uv(const TcpInfo *info, const char *payload, int payload_len) {
        if (payload_len + 2 * sizeof(SA4) > OM_MAX_PKT_SIZE) {
            LOGE << "drop payload_len: " << payload_len << ", 2 * sizeof(struct sockaddr_in): " << 2 * sizeof(SA4)
                 << ", buf MAX_LEN: " << OM_MAX_PKT_SIZE;
            return 0;
        }
    
        char buf[OM_MAX_PKT_SIZE] = {0};
        char *p = info->Encode(buf, OM_MAX_PKT_SIZE);
        if (!p) {
            return 0;
        }
        memcpy(p, payload, payload_len);
        p += payload_len;
        return write(mWriteFd, buf, p - buf);    // a unix socket. for thread synchronization
    }
    
    // relative function
    std::string InAddr2Ip(in_addr addr) {
        std::string ip;
        auto iaddr = addr.s_addr;
        for (int i = 0; i < 4; i++) {
            if (i > 0) {
                ip += ".";
            }
            ip += std::to_string(iaddr & 0xff);
            iaddr >>= 8;
        }
    
        return ip;
    }
    

    The way I initialize plog:

    int ISockApp::initLog() {
        if (!mConf.log_path.empty()) {
            if (!FdUtil::FileExists(mConf.log_path.c_str())) {
                int nret = FdUtil::CreateFile(mConf.log_path);
                if (nret < 0) {
                    return nret;
                }
            }
            mFileAppender = new plog::RollingFileAppender<plog::TxtFormatter>(mConf.log_path.c_str(), 100000, 5);
        } else {
            fprintf(stderr, "warning: log path empty\n");
        }
    
        mConsoleAppender = new plog::ConsoleAppender<plog::TxtFormatter>();
        plog::init(mConf.log_level, mConsoleAppender);
        if (mFileAppender) {  // if can log to file
            plog::get()->addAppender(mFileAppender);
        }
    
        return 0;
    }
    

    Since plog use mutex lock to protect file locking. It is normal to slow down speed if add some logging in very frequent operations. But here. Remove(NOT ADD) those lines of code will slow down speed.

    opened by iceonsun 11
  • Conan package

    Conan package

    Hello, Do you know about Conan? Conan is modern dependency manager for C++. And will be great if your library will be available via package manager for other developers.

    Here you can find example, how you can create package for the library.

    If you have any questions, just ask :-)

    enhancement 
    opened by zamazan4ik 11
  • Don't see any log output at all

    Don't see any log output at all

    Like the now-closed #49, I'm doing a fairly simple set-up, and I can see my application working, but there's no logging.

    This seems like it's correct:

    plog::init(plog::verbose, cfg.logFile, 512 * 1024, 4);

    and the actual logging

    LOG_INFO << "email sent";

    appears correct, and when I follow it in the debugger, it seems to do what's required.

    But after multiple runs and tests, there's still no log. It didn't append to the legacy log file already on the drive, and deleting that didn't cause it to generate a new log file.

    Building in VS2013.

    What am I doing wrong?

    question 
    opened by jbmonroe 10
  • const char * : unhandled exception in lib <string>

    const char * : unhandled exception in lib

    When i use plog in my main i have no problems,

    but i wanna use it on other function but i got unhandled exception in visual studio.

    my call was something like that :

    LOGI << "Some text here";

    I correct first the problem by adding always std::string constructor in my debug text but it was really boring

    LOGI << std::string("Some text here");

    Finally I correct the problem by adding this in record.h

    		Record& operator<<(const const char* data)
    		{
    			using namespace plog::detail;
    
    			m_message << std::string(data);
    			return *this;
    		}
    

    Do you have any idea what is wrong ?

    invalid 
    opened by pcorbineau 10
  • Static analysis error

    Static analysis error "Cannot resolve symbol 'ref'"

    I have a similiar problem. Happens when using Visual Studio 2017. On mouse hover error message is "Cannot resolve symbol 'ref'. In error list: class "plog::Record" has no member "ref"

    Happens when using any log macro, for example LOG_DEBUG << "anything"; It is only static analysis error. Compiles and works OK. Macro expands to: if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::debug)) {;} else (*plog::get<0>()) += plog::Record(plog::debug, __FUNCTION__, 25, "", __if_exists(this) { this } __if_not_exists(this) { 0 }).ref() << "anything";

    Originally posted by @domenn in https://github.com/SergiusTheBest/plog/issues/114#issuecomment-450564980

    bug 
    opened by SergiusTheBest 9
  • Support operator<<(std::ostream& os, ...) custom operators on Windows

    Support operator<<(std::ostream& os, ...) custom operators on Windows

    Currently it's difficult to use the same code across platforms because Plog expects operator<< to use std::wostream on Windows, while on Linux (and OSX?) you need to use std::ostream. Thus code that builds on Linux fails to build on Windows and the other way around.

    If there are other ways to have common operators across platforms I'd love to know.

    enhancement 
    opened by DesktopMan 9
  • building on macOS (11.6) fails:

    building on macOS (11.6) fails: "ar: no archive members specified"

    At the cmake --build ./make stage:

    [1%] Linking CXX static library libplog-headers.a
    ar: no archive members specified
    ...
    make[2]: *** [libplog-headers.a] Error 1
    make[1]: *** [CMakeFiles/plog-headers.dir/all] Error 2
    make: *** [all] Error 2
    

    Similar issues with building on macOS are googleable, but I didn't find a solution yet.

    bug 
    opened by pptz 8
  • Qt 'operator <<' is ambiguous

    Qt 'operator <<' is ambiguous

    Hi Sergius,

    Before I was using the Plog's version b15e399e70424845a03be2f8a6d15f387f6f2ca5 but today I want to upgrade to the latest version like dcbcca75faccfbde3ba4aae85a185d042af5a185. I'm using it with

    • Qt 5.4.1
    • Qt Creator 4.5.0.
    • Windows 10
    • Visual Studio 2013 last service pack

    But now when compiling, I'm getting this error

    D:\Data\App\Loader.cpp:2325: error: C2593: 'operator <<' is ambiguous
    D:\Data\App\plog\include\plog/Record.h(144): could be 'plog::Record &plog::Record::operator <<(const QString &)'
    D:\Data\App\plog\include\plog/Record.h(134): or       'plog::Record &plog::Record::operator <<(std::wostream &(__cdecl *)(std::wostream &))'
    D:\Data\App\plog\include\plog/Record.h(126): or       'plog::Record &plog::Record::operator <<(wchar_t)'
    D:\Data\App\plog\include\plog/Record.h(119): or       'plog::Record &plog::Record::operator <<(char)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtquick\qquickitem.h(450): or       'QDebug operator <<(QDebug,QQuickItem *)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qaccessible.h(951): or       'QDebug operator <<(QDebug,const QAccessibleEvent &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qaccessible.h(950): or       'QDebug operator <<(QDebug,const QAccessibleInterface *)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qcolor.h(52): or       'QDataStream &operator <<(QDataStream &,const QColor &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qcolor.h(49): or       'QDebug operator <<(QDebug,const QColor &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qevent.h(885): or       'QDebug operator <<(QDebug,const QTouchEvent::TouchPoint &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qevent.h(741): or       'QDebug operator <<(QDebug,const QEvent *)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qvector2d.h(255): or       'QDataStream &operator <<(QDataStream &,const QVector2D &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qvector2d.h(251): or       'QDebug operator <<(QDebug,const QVector2D &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qkeysequence.h(217): or       'QDebug operator <<(QDebug,const QKeySequence &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qkeysequence.h(51): or       'QDataStream &operator <<(QDataStream &,const QKeySequence &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qregion.h(171): or       'QDebug operator <<(QDebug,const QRegion &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qregion.h(138): or       'QDataStream &operator <<(QDataStream &,const QRegion &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qfont.h(342): or       'QDebug operator <<(QDebug,const QFont &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtGui/qfont.h(303): or       'QDataStream &operator <<(QDataStream &,const QFont &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtQml/qqmlerror.h(72): or       'QDebug operator <<(QDebug,const QQmlError &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qsslkey.h(97): or       'QDebug operator <<(QDebug,const QSslKey &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qsslcipher.h(84): or       'QDebug operator <<(QDebug,const QSslCipher &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qlocalsocket.h(141): or       'QDebug operator <<(QDebug,QLocalSocket::LocalSocketState)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qlocalsocket.h(140): or       'QDebug operator <<(QDebug,QLocalSocket::LocalSocketError)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qnetworkproxy.h(206): or       'QDebug operator <<(QDebug,const QNetworkProxy &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qnetworkinterface.h(125): or       'QDebug operator <<(QDebug,const QNetworkInterface &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qhostaddress.h(133): or       'QDataStream &operator <<(QDataStream &,const QHostAddress &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qhostaddress.h(129): or       'QDebug operator <<(QDebug,const QHostAddress &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qnetworkcookie.h(107): or       'QDebug operator <<(QDebug,const QNetworkCookie &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qsslerror.h(110): or       'QDebug operator <<(QDebug,const QSslError::SslError &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qsslerror.h(109): or       'QDebug operator <<(QDebug,const QSslError &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qsslcertificate.h(160): or       'QDebug operator <<(QDebug,QSslCertificate::SubjectInfo)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qsslcertificate.h(159): or       'QDebug operator <<(QDebug,const QSslCertificate &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qabstractsocket.h(229): or       'QDebug operator <<(QDebug,QAbstractSocket::SocketState)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtNetwork/qabstractsocket.h(228): or       'QDebug operator <<(QDebug,QAbstractSocket::SocketError)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtnetwork\qabstractnetworkcache.h(99): or       'QDataStream &operator <<(QDataStream &,const QNetworkCacheMetaData &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qtimezone.h(155): or       'QDebug operator <<(QDebug,const QTimeZone &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qtimezone.h(138): or       'QDataStream &operator <<(QDataStream &,const QTimeZone &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qregularexpression.h(206): or       'QDebug operator <<(QDebug,const QRegularExpressionMatch &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qregularexpression.h(148): or       'QDebug operator <<(QDebug,QRegularExpression::PatternOptions)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qregularexpression.h(147): or       'QDebug operator <<(QDebug,const QRegularExpression &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qregularexpression.h(142): or       'QDataStream &operator <<(QDataStream &,const QRegularExpression &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qrect.h(868): or       'QDebug operator <<(QDebug,const QRectF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qrect.h(611): or       'QDataStream &operator <<(QDataStream &,const QRectF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qrect.h(489): or       'QDebug operator <<(QDebug,const QRect &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qrect.h(161): or       'QDataStream &operator <<(QDataStream &,const QRect &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qsize.h(367): or       'QDebug operator <<(QDebug,const QSizeF &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qsize.h(257): or       'QDataStream &operator <<(QDataStream &,const QSizeF &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qsize.h(197): or       'QDebug operator <<(QDebug,const QSize &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qsize.h(94): or       'QDataStream &operator <<(QDataStream &,const QSize &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qmargins.h(480): or       'QDebug operator <<(QDebug,const QMarginsF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qmargins.h(321): or       'QDataStream &operator <<(QDataStream &,const QMarginsF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qmargins.h(272): or       'QDebug operator <<(QDebug,const QMargins &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qmargins.h(88): or       'QDataStream &operator <<(QDataStream &,const QMargins &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qline.h(408): or       'QDataStream &operator <<(QDataStream &,const QLineF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qline.h(404): or       'QDebug operator <<(QDebug,const QLineF &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qline.h(194): or       'QDataStream &operator <<(QDataStream &,const QLine &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qline.h(190): or       'QDebug operator <<(QDebug,const QLine &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qbitarray.h(163): or       'QDebug operator <<(QDebug,const QBitArray &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qbitarray.h(45): or       'QDataStream &operator <<(QDataStream &,const QBitArray &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\quuid.h(213): or       'QDebug operator <<(QDebug,const QUuid &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\quuid.h(208): or       'QDataStream &operator <<(QDataStream &,const QUuid &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qmimetype.h(107): or       'QDebug operator <<(QDebug,const QMimeType &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qcoreapplication.h(266): or       'QDebug operator <<(QDebug,const MSG &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qjsonobject.h(208): or       'QDebug operator <<(QDebug,const QJsonObject &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qjsondocument.h(137): or       'QDebug operator <<(QDebug,const QJsonDocument &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qjsonarray.h(225): or       'QDebug operator <<(QDebug,const QJsonArray &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qjsonvalue.h(119): or       'QDebug operator <<(QDebug,const QJsonValue &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qitemselectionmodel.h(239): or       'QDebug operator <<(QDebug,const QItemSelectionRange &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qabstractitemmodel.h(133): or       'QDebug operator <<(QDebug,const QPersistentModelIndex &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qabstractitemmodel.h(88): or       'QDebug operator <<(QDebug,const QModelIndex &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qurl.h(403): or       'QDebug operator <<(QDebug,const QUrl &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qurl.h(398): or       'QDataStream &operator <<(QDataStream &,const QUrl &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qdir.h(224): or       'QDebug operator <<(QDebug,const QDir &)'
    c:\qt\qt5.4.2\5.4\msvc2013\include\qtcore\qdir.h(223): or       'QDebug operator <<(QDebug,QDir::Filters)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(330): or       'QDebug operator <<(QDebug,const QTime &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(329): or       'QDebug operator <<(QDebug,const QDate &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(314): or       'QDebug operator <<(QDebug,const QDateTime &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(309): or       'QDataStream &operator <<(QDataStream &,const QDateTime &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(189): or       'QDataStream &operator <<(QDataStream &,const QTime &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qdatetime.h(124): or       'QDataStream &operator <<(QDataStream &,const QDate &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qeasingcurve.h(118): or       'QDataStream &operator <<(QDataStream &,const QEasingCurve &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qeasingcurve.h(115): or       'QDebug operator <<(QDebug,const QEasingCurve &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qpoint.h(387): or       'QDebug operator <<(QDebug,const QPointF &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qpoint.h(258): or       'QDataStream &operator <<(QDataStream &,const QPointF &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qpoint.h(198): or       'QDebug operator <<(QDebug,const QPoint &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qpoint.h(98): or       'QDataStream &operator <<(QDataStream &,const QPoint &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qtextstream.h(223): or       'QTextStream &operator <<(QTextStream &,QTextStreamManipulator)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qtextstream.h(220): or       'QTextStream &operator <<(QTextStream &,QTextStreamFunction)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qlocale.h(966): or       'QDebug operator <<(QDebug,const QLocale &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qlocale.h(961): or       'QDataStream &operator <<(QDataStream &,const QLocale &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qvariant.h(848): or       'QDebug operator <<(QDebug,const QVariant::Type)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qvariant.h(535): or       'QDataStream &operator <<(QDataStream &,const QVariant::Type)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qvariant.h(533): or       'QDataStream &operator <<(QDataStream &,const QVariant &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qvariant.h(443): or       'QDebug operator <<(QDebug,const QVariant &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qstringlist.h(253): or       'QDataStream &operator <<(QDataStream &,const QStringList &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qregexp.h(119): or       'QDebug operator <<(QDebug,const QRegExp &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qregexp.h(114): or       'QDataStream &operator <<(QDataStream &,const QRegExp &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qiodevice.h(166): or       'QDebug operator <<(QDebug,QIODevice::OpenMode)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qobject.h(547): or       'QDebug operator <<(QDebug,const QObject *)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qstring.h(1246): or       'QDataStream &operator <<(QDataStream &,const QString &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qbytearray.h(634): or       'QDataStream &operator <<(QDataStream &,const QByteArray &)'
    C:\Qt\Qt5.4.2\5.4\msvc2013\include\QtCore/qchar.h(543): or       'QDataStream &operator <<(QDataStream &,QChar)'
    D:\Data\App/UtilsPLog.h(10): or       'plog::Record &plog::operator <<(plog::Record &,const QString &)' [found using argument-dependent lookup]
    D:\Data\App/UtilsPLog.h(13): or       'plog::Record &plog::operator <<(plog::Record &,const QByteArray &)' [found using argument-dependent lookup]
    D:\Data\App/UtilsPLog.h(16): or       'plog::Record &plog::operator <<(plog::Record &,const QStringRef &)' [found using argument-dependent lookup]
    D:\Data\App\plog\include\plog/Record.h(163): or       'plog::Record &plog::Record::operator <<<QString>(const T &)'
    with
    [
        T=QString
    ]
    while trying to match the argument list '(plog::Record, QString)'
    

    about the following code

    QDir directoryPath = QFileInfo("C:\...").absoluteDir();
    LOG_ERROR << "Error when creating path  '" << directoryPath.absolutePath() << "'";
    

    Before, I did not have this problem. I know the meaning of the error but I'm unable to fix it. The compiler must probably interpret the string "Error when creating path '" as wchar_t ?

    So I tried forcing the first string to be interpret as QString to prevent ambiguous

    QDir directoryPath = QFileInfo("C:\...").absoluteDir();
    LOG_ERROR << QString("Error when creating path  '") << directoryPath.absolutePath() << "'";
    

    but it not working too.

    As expected, those one works.

    LOG_ERROR << "Error when creating path  '" << directoryPath.absolutePath().toUtf8() << "'";
    
    LOG_ERROR << "Error when creating path  '" << directoryPath.absolutePath().toStdString() << "'";
    
    LOG_ERROR << "Error when creating path  '" << directoryPath.absolutePath().toStdWString() << "'";
    

    but it will be a little hell to revise all the code with this fix :(

    Best regards,

    question 
    opened by erakis 8
  • Log flushed to disk only at end of my program

    Log flushed to disk only at end of my program

    Hi,

    I call plog::init(plog::verbose, "log.txt") at the beggining of my program. During execution, I call LOG_INFO several times. I want to monitoring the execution of my program by examining the log file (my program runs for a long time), but the log file is flushed to disk only at the end of my program.

    How to force flushing at each logged message (I don't care about the performance)?

    Thanks!

    opened by nilopaim 8
  • Got a __lll_lock_wait when used in multi thread application.

    Got a __lll_lock_wait when used in multi thread application.

    I am using this powerful and easy to use lib in my application. The application is based on Qt 5.12.8 and running on ubuntu 20.04. There is a reproducible phenomenon : my application is frozen sometimes ,I have to kill the process to end application. when I start gdb ann attatch to the process.I found a thread with __lll_lock_wait . here is the stack info:

    (gdb) bt
    #0  __lll_lock_wait (
        [email protected]=0x7f0767c7a608 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender+8>,
        private=0) at lowlevellock.c:52
    #1  0x00007f0766b4d0a3 in __GI___pthread_mutex_lock (
        mutex=0x7f0767c7a608 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender+8>)
        at ../nptl/pthread_mutex_lock.c:80
    #2  0x00007f0767c59530 in plog::util::Mutex::lock (
        this=0x7f0767c7a608 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender+8>)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Util.h:478
    #3  0x00007f0767c5958e in plog::util::MutexLock::MutexLock (this=0x7ffd0ddef7e0, mutex=...)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Util.h:508
    #4  0x00007f0767c5bc23 in plog::RollingFileAppender<plog::TxtFormatter, plog::NativeEOLConverter<plog::UTF8Converter> >::write (
        this=0x7f0767c7a600 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender>, record=...)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Appenders/RollingFileAppender.h:38
    #5  0x00007f0767c59fcf in plog::Logger<0>::operator+= (this=0x7f0767c7a520 <plog::init<0>(plog::Severity, plog::IAppender*)::logger>, record=...)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Logger.h:58
    #6  0x00007f0767c57f61 in LoggerHelper::Record (this=0x7f0767c7a4e0 <LoggerHelper::Instance()::mainObj>, severity=Level::debug,
        func=0x7f0767c615b0 "AutoLogger::AutoLogger(const string&, Level)", line=53, file=0x7f0767c615ab "", object=0x0,
        msg="Start static void BoardSLMDevice::signal_handler(int, siginfo_t*, void*)")
        at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/LoggerHelper.cpp:27
    #7  0x00007f0767c584cf in AutoLogger::AutoLogger (this=0x7ffd0ddefbf0, func="static void BoardSLMDevice::signal_handler(int, siginfo_t*, void*)",
        lvl=Level::debug) at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/LoggerHelper.cpp:53
    #8  0x00007f0767c39f5a in BoardSLMDevice::signal_handler (signum=12, info=0x7ffd0ddefd70, context=0x7ffd0ddefc40)
        at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/BoardSLMDevice.cpp:1041
    #9  <signal handler called>
    #10 __GI___libc_write (nbytes=103, buf=0x55abe5660a70, fd=18) at ../sysdeps/unix/sysv/linux/write.c:26
    #11 __GI___libc_write (fd=18, buf=0x55abe5660a70, nbytes=103) at ../sysdeps/unix/sysv/linux/write.c:24
    #12 0x00007f0767c593f9 in plog::util::File::write (
        this=0x7f0767c7a630 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender+48>,
        buf=0x55abe5660a70, count=103) at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Util.h:381
    #13 0x00007f0767c5c6f3 in plog::util::File::write<char> (
        this=0x7f0767c7a630 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender+48>,
        str="2022-09-05 09:09:49.789 DEBUG [51129] [BoardSLMDevice::[email protected]] target:696bde000 for 7f0646bde000\n")
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Util.h:389
    #14 0x00007f0767c5bcb7 in plog::RollingFileAppender<plog::TxtFormatter, plog::NativeEOLConverter<plog::UTF8Converter> >::write (
        this=0x7f0767c7a600 <plog::init<plog::TxtFormatter, 0>(plog::Severity, char const*, unsigned long, int)::rollingFileAppender>, record=...)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Appenders/RollingFileAppender.h:50
    #15 0x00007f0767c59fcf in plog::Logger<0>::operator+= (this=0x7f0767c7a520 <plog::init<0>(plog::Severity, plog::IAppender*)::logger>, record=...)
        at /home/upolabs/BoardSLMProj2/thirdparty/include/plog/Logger.h:58
    #16 0x00007f0767c57f61 in LoggerHelper::Record (this=0x7f0767c7a4e0 <LoggerHelper::Instance()::mainObj>, severity=Level::debug,
        func=0x7f0767c60720 "resource_size_t BoardSLMDevice::GetPaddr(char*)", line=752, file=0x7f0767c601ca "", object=0x0,
        msg="target:696bde000 for 7f0646bde000") at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/LoggerHelper.cpp:27
    #17 0x00007f0767c380ce in BoardSLMDevice::GetPaddr (this=0x55abe574e830,
        vaddr=0x7f0646bde000 <error: Cannot access memory at address 0x7f0646bde000>)
        at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/BoardSLMDevice.cpp:752
    #18 0x00007f0767c3abfe in BoardSLMDevice::InstantDisplay (this=0x55abe574e830, idx=46, times=1)
        at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/BoardSLMDevice.cpp:1189
    #19 0x00007f0767c3a70a in BoardSLMDevice::InstantDisplay (this=0x55abe574e830, pData=0x55abe5960680, times=1)
        at /home/upolabs/BoardSLMProj2/BoardSLMDrv/src/BoardSLMDevice.cpp:1124
    #20 0x000055abe3986cc1 in BoardSLMCache::on_listWidget_Path_SLM1_Cache_currentRowChanged (this=0x55abe4fd2440, arg1=46)
        at /home/upolabs/BoardSLMProj2/BoardSLMQT/boardslmcache.cpp:143
    #21 0x000055abe3982c72 in BoardSLMCache::qt_static_metacall (_o=0x55abe4fd2440, _c=QMetaObject::InvokeMetaMethod, _id=11, _a=0x7ffd0ddf1120)
        at BoardSLMQT/BoardSLMQT_autogen/EWIEGA46WW/moc_boardslmcache.cpp:134
    #22 0x000055abe3982de8 in BoardSLMCache::qt_metacall (this=0x55abe4fd2440, _c=QMetaObject::InvokeMetaMethod, _id=11, _a=0x7ffd0ddf1120)
        at BoardSLMQT/BoardSLMQT_autogen/EWIEGA46WW/moc_boardslmcache.cpp:179
    #23 0x00007f076735d28c in QMetaObject::activate(QObject*, int, int, void**) () from /lib/x86_64-linux-gnu/libQt5Core.so.5
    #24 0x00007f076aa99315 in QListWidget::currentRowChanged(int) () from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
    #25 0x00007f076aa99cc6 in ?? () from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
    
    question 
    opened by fietiger 1
  • Have option to set the logger id during run time and not just compile time.

    Have option to set the logger id during run time and not just compile time.

    Im at a stage where i need to use multiple copies of a lib that uses Plog. Problem is that since Plog takes ids at compile time, when the libs are running, they all share the same logging ids and log to the same file. To fix this i need to compile each lib with a new id.

    I think it would be an improvement if plog could somehow be able to use logger ids during runtime like taking the logger id as a parameter in its init instead of using template parameters. That way i can pass the ids and set up each lib with a different id during runtime.

    opened by JoelSatkas 20
  • buffered asynchronous logging

    buffered asynchronous logging

    is it possible to implement a buffer that accumulates logs and then writes to file ( either after N number of logs accumulated OR after certain elapse of timer ) using a thread asynchronously ? Could you please provide some insights on how / where in the code can this be achieved?

    question 
    opened by iamshastry 1
  • Compile error on borland c++ builder 6

    Compile error on borland c++ builder 6

    [C++ Error] Util.h(89): E2268 Call to undefined function 'localtime_s' [C++ Error] Util.h(102): E2268 Call to undefined function 'gmtime_s' [C++ Error] Util.h(160): E2268 Call to undefined function '_vscprintf' [C++ Error] Util.h(177): E2268 Call to undefined function '_vsnprintf_s' [C++ Error] Util.h(191): E2268 Call to undefined function '_vscwprintf' [C++ Error] Util.h(208): E2268 Call to undefined function '_vsnwprintf_s' [C++ Error] Record.h(41): E2285 Could not find a match for '_STL::operator << <_CharT,_Traits>(wostringstream,const wchar_t *)' [C++ Error] Record.h(83): E2109 Not an allowed type [C++ Error] Record.h(83): E2453 Size of the type 'T' is unknown or zero

    opened by GithubAlanChao 2
Releases(1.1.8)
  • 1.1.8(Jun 10, 2022)

  • 1.1.7(Jun 9, 2022)

    • New: Add hex dumper (#111)
    • New: Add ASCII dumper (#213)
    • New: Add support for printing std containers (#207)
    • New: Add console initializer
    • New: Add PrintVar helper
    • New: Add CMake find_package support (#171)
    • Enh: Change license to MIT (#212)
    • Fix: Specify calling convention for std stream manipulators (#210)
    • Fix: Compilation on VS2010 (#207)
    • Fix: Use add_custom_target for pseudo-project with headers (#216)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.6(Feb 6, 2022)

    • New: Ability to disable logging to reduce binary size (#130)
    • New: Ability to change maxFiles/maxFileSize after initialization
    • New: Logging std::filesystem::path without explicit conversion to std::string (#168, #185, #183)
    • New: Allow to choose stdout/stderr for console appender (#162, #117)
    • New: Ability to change log file name at runtime (#62)
    • New: Ability to control sharing across modules (#96, #152, #20)
    • New: Building on platforms without thread support (#161, #113)
    • Enh: Change color functions from private to protected (#163)
    • Enh: Do not include plog/Init.h in plog/Log.h (#127, #89)
    • Fix: WideCharToMultiByte bug (#202)
    • Fix: Building with Qt6 (#190)
    • Fix: Compiling on GCC 4.4-4.7 (#176)
    • Fix: Suppress UBSan false positive (#90)
    • Fix: Don't share handle/fd to child process (#170)
    • Fix: MSVC analyzer warnings (#148)
    • Fix: File size truncation > 2GB on Windows (#160)
    • Fix: RTEMS build on newer toolchain (#158, #159)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.5(May 10, 2020)

    Changes

    • New: Use NativeEOLConverter by default (#145)
    • New: Add logger instanceId into Record (#141)
    • New: Add support for the printf style formatting (#139)
    • New: Make severityFromString case-insensitive
    • 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)
    • New: Add option for building samples (ON per default) (#125, #126)
    • New: Add CMake installer (#121, #122)
    • New: Add support for QStringRef
    • New: Modernize CMake (#106)
    • New: Allow rollLogFiles to be called manually (#100, #103)
    • New: Add ability to use UTC time (#101)
    • Fix: Disable PLOG_GET_THIS() by default (#120, #132)
    • Fix: Change RegSetValueExW prototype to match windows native declaration (void* -> BYTE*)
    • Fix: Move System::String^ handler to a free function (#131)
    • Fix: Making sure we can build standalone under Windows (#123)
    • Fix: Parse error by ReSharper (#116)
    • Fix: Parse error by Clang Code Model in Qt Creator (#114)
    • Fix: Printing CustomType at begin of the stream (#94)
    • Fix: Make RollingFileAppender work with maxFiles set to 1 (#70)
    • Fix: Clang-tidy nullable issue
    Source code(tar.gz)
    Source code(zip)
  • 1.1.4(Mar 26, 2018)

    • New: Add -Wundef support
    • New #87: Add RTEMS support
    • New #84: Add Intel C++ Compiler support
    • New #83: Add FreeBSD support
    • New #79: Add -Wnon-virtual-dtor support
    • New #66: Support ostream operator<< on windows as well as wostream
    • Fix #68: Fix compilation for Android
    • Fix: Fix compiling with cmake 2.8
    Source code(tar.gz)
    Source code(zip)
  • 1.1.3(Aug 9, 2017)

    • New: Introduce PLOG_ENABLE_WCHAR_INPUT macro to control wide string support
    • New #63: Add support for managed C++ System::String^
    • New #61: Add missing macros for logging with severity NONE
    • Fix #59: Unable to build NativeEOLConverter/UTF8Converter using Visual Studio
    • Fix #58: Use WriteConsoleW instead of global setlocale for writing unicode into windows console
    • Fix #55: Mention about linking to iconv on macOS
    • Fix: IF_LOG macro didn't work for curly braces blocks
    Source code(tar.gz)
    Source code(zip)
  • 1.1.2(May 2, 2017)

  • 1.1.1(Apr 17, 2017)

    • Fixed #47: Update includes
    • Fixed #45, #13: Get rid of windows.h dependency
    • Fixed #40: Signed unsigned assignment warning
    • Fixed #39: Build warning on macOS 10.12 Sierra
    • New #36: Ability to check whether event log registry entry exists
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Nov 20, 2016)

  • 1.0.2(Nov 19, 2016)

    • New #11: Default instance can be set via PLOG_DEFAULT_INSTANCE
    • New #30: Support for QString
    • New: Support for C++Builder
    • New #15: severityFromString function
    • New #21: Capture source file name (disabled by default)
    • New #33: Add DebugOutputAppender
    • New #32: Add EventLogAppender
    • Fixed #12: Crash on processing Obj-C function name
    • Fixed #17: Compatibility with MinGW
    • Fixed #27: IF_LOG_ macro in if/else leads to miss else branch
    • Fixed #18, #29: Thread safety for ConsoleAppender/ColorConsoleAppender
    • Fixed #31: Support for stream manipulators like std::endl
    • Fixed: Compatibility with old Visual Studio versions
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Nov 1, 2015)

  • 1.0.0(Nov 1, 2015)

Owner
Sergey Podobry
Sergey Podobry
Reckless logging. Low-latency, high-throughput, asynchronous logging library for C++.

Introduction Reckless is an extremely low-latency, high-throughput logging library. It was created because I needed to perform extensive diagnostic lo

Mattias Flodin 441 Sep 22, 2022
logog is a portable C++ library to facilitate logging of real-time events in performance-oriented applications

logog is a portable C++ library to facilitate logging of real-time events in performance-oriented applications, such as games. It is especially appropriate for projects that have constrained memory and constrained CPU requirements.

John Byrd 46 Oct 21, 2020
log4cplus is a simple to use C++ logging API providing thread-safe, flexible, and arbitrarily granular control over log management and configuration. It is modelled after the Java log4j API.

% log4cplus README Short Description log4cplus is a simple to use C++17 logging API providing thread--safe, flexible, and arbitrarily granular control

null 1.3k Sep 23, 2022
Minimalistic logging library with threads and manual callstacks

Minimalistic logging library with threads and manual callstacks

Sergey Kosarevsky 21 Jun 24, 2022
A Fast and Convenient C++ Logging Library for Low-latency or Real-time Environments

xtr What is it? XTR is a C++ logging library aimed at applications with low-latency or real-time requirements. The cost of log statements is minimised

null 10 Jul 17, 2022
Yet another logging library.

Blackhole - eating your logs with pleasure Blackhole is an attribute-based logger with strong focus on gaining maximum performance as possible for suc

Evgeny Safronov 188 Sep 20, 2022
A lightweight C++ logging library

Loguru: a lightweight and flexible C++ logging library. At a glance Documentation Documentation can be found at https://emilk.github.io/loguru/index.h

Emil Ernerfeldt 1.4k Sep 23, 2022
Fast C++ logging library.

spdlog Very fast, header-only/compiled, C++ logging library. Install Header only version Copy the source folder to your build tree and use a C++11 com

Gabi Melman 15.6k Sep 19, 2022
Asynchronous Low Latency C++ Logging Library

Quill Asynchronous Low Latency C++ Logging Library Introduction Features Performance Supported Platforms And Compilers Basic Usage CMake Integration D

Odysseas Georgoudis 650 Sep 16, 2022
Cute Log is a C++ Library that competes to be a unique logging tool.

Cute Log Cute Log is a C++ Library that competes to be a unique logging tool. Version: 2 Installation Click "Code" on the main repo page (This one.).

null 4 Aug 12, 2021
fmtlog is a performant fmtlib-style logging library with latency in nanoseconds.

fmtlog fmtlog is a performant asynchronous logging library using fmt library format. Features Faster - lower runtime latency than NanoLog and higher t

Meng Rao 393 Sep 16, 2022
Boost Logging library

Boost.Log, part of collection of the Boost C++ Libraries, provides tools for adding logging to libraries and applications. Directories build - Boost.L

Boost.org 154 Sep 15, 2022
C++ implementation of the Google logging module

Google Logging Library The Google Logging Library (glog) implements application-level logging. The library provides logging APIs based on C++-style st

Google 5.7k Sep 25, 2022
Uberlog - Cross platform multi-process C++ logging system

uberlog uberlog is a cross platform C++ logging system that is: Small Fast Robust Runs on Linux, Windows, OSX MIT License Small Two headers, and three

IMQS Software 14 Aug 15, 2022
A simple Keystroke logger written in C++

BufferX A simple keylogger written in C++ Disclaimer: This project is made for knowledge and learning purpose. I am not responsible for any damage , i

Ibne Nahian 2 Aug 18, 2022
Simple Keylogger i made in c++

Keylogger Simple Keylogger i made in c++ I am still learning c++ (so the logger will be also update it is not the final release) Run it git clone g++

Asjad 6 Feb 23, 2022