Code Monkey home page Code Monkey logo

plog's Introduction

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

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

image

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

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 always be 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 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 The appender lifetime 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 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.

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

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:

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:

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

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

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
  • instance id

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

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

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

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

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:

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

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

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.

ConsoleAppender

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

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

ColorConsoleAppender

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

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

DynamicAppender

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.

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 std::filesystem::path
  • 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:

  • Windows
    • wchar_t - by default
    • char - if compiling with /utf-8 switch or set PLOG_CHAR_IS_UTF8 to 1
  • all other systems
    • char

Also char is treated as:

  • Windows
    • active code page - be default
    • UTF-8 - if compiling with /utf-8 switch or set PLOG_CHAR_IS_UTF8 to 1
  • all other systems
    • UTF-8

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.

Wide string support

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.

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

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

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.
Arduino Arduino sample - not finished yet!
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.
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.

References

Competing C++ log libraries

Tools and useful info

License

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

Version history

Version 1.1.10 (20 Aug 2023)

  • New: Add support for UTF-8 char encoding on Windows (#76, #69, #238, #239)
    This allows to use Utf8Everywhere approach
  • New: Add ArduinoAppender
  • New: Publish on PlatformIO Registry for embedded development (#244)
  • New: Add support for char8_t strings
  • New: Add tests
  • Enh: Add rudimentary support of VS2005 (#232)
  • Enh: Implementation of vasprintf emulation (#243)
  • Fix: Parsing of templated classes (#251)
  • Fix: Compiling with MSVC using C++20 (#236)
  • Fix: No newline error with '-Wnewline-eof' build flag (#263)

Version 1.1.9 (16 Dec 2022)

  • New: Add ability to truncate log file using > in shell (#155)
  • New: Add override specifier (to be able to build with -Wsuggest-override) (#231)
  • New: Add nuget specs (#86)
  • New: Add ability to add/remove appenders (#226)
  • Fix: Printing boost::filesystem::path (#227)
  • Fix: Building on C++ Builder 10.4 (#225)
  • Fix: PLOG_LOCAL mode if symbol visibility set to default (#219)

Version 1.1.8 (10 Jun 2022)

  • Fix: 'operator <<' is ambiguous for string_view on Windows (#217)
  • Fix: CMake + vcpkg: find_package (#211)

Version 1.1.7 (09 Jun 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)

Version 1.1.6 (06 Feb 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)

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

plog's People

Contributors

bastianseeleib avatar bitmeal avatar chenjianlong avatar civetosh avatar dejan1024 avatar dmgk avatar fbriol avatar foreverr avatar ghostvaibhav avatar gordhub avatar gwankyun avatar hanseuljun avatar hutch avatar jenglamlow avatar kohnech avatar majiclin626 avatar oleksandrtens0r avatar rhd avatar seanchas116 avatar sergiusthebest avatar smorin-primero avatar syaojun avatar thesummer avatar thirtysomething avatar u-1f992 avatar variar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plog's Issues

__FILE__

Hello !

Is there any reason why the LOG_ macro (and the LogRecord object) does not record the original file where the LOG_ statement happened, using FILE ?

Thank you

Changing global locale in ConsoleAppender

On windows ConsoleAppender constructor changes locale with ::setlocale(LC_ALL, ""). That may cause troubles. https://github.com/SergiusTheBest/plog/blob/master/include/plog/Appenders/ConsoleAppender.h#L15
We are using PLOG in a dynamic library. It may be linked to a binary that may depend on locale settings (in our case it sets and expects "C" locale).

In case changing locale is required for PLOG library I believe it can be done locally using imbue http://en.cppreference.com/w/cpp/io/basic_ios/imbue.

EventLogAppender not working

Hi Sergey,

looks that the EventLogAppender is no longer working. I was not able to create event log entries. More worse is that the chaining of RollingFileAppender and EventLogAppender will result in nothing logged at all.

I'm using the following code for init:

std::string ProgName = _T("PlogTest");
CString LogFileName;
LogFileName.Format(_T("C:\\Temp\\%s.log"), ProgName.c_str());
static plog::RollingFileAppender<plog::TxtFormatter> LogFile(LogFileName, 1000000, 5);
std::wstring EventLog = std::wstring(ProgName.begin(), ProgName.end());
if (false == plog::EventLogAppenderRegistry::exists(EventLog.c_str()))
{
	plog::EventLogAppenderRegistry::add(EventLog.c_str());
}
static plog::EventLogAppender<plog::TxtFormatter> LogEvent(EventLog.c_str());
plog::init(plog::verbose, &LogFile).addAppender(&LogEvent);

I've tested both, with and without admin privileges and got the same result. The OS user has local admin privileges.

The project specific settings are:

  • Platformtoolset Visual Studio 2010 (v100)
  • Usage of MFC in a common used DLL
  • Using Multibyte character set
  • No optimizing

The OS is Win7 Pro 64 and I'm working with Visual Studio 2013.

Time based rolling file appender

Hi,
I needed a time based rolling file appender.
I attach the modified files to achieve this functionality.

I ask you to review it and to include in the next version on plog with the all related adjustments.

plog.zip

Plog in library

Hi, i'm trying to init plog in both my library and demo executable. Like this:

plog::init(plog::warning, FileUtil::Instance()->GetAbsPath("Log.txt").c_str()).addAppender(
    new plog::ConsoleAppender<plog::FuncMessageFormatter>());
// my library using plog
Engine::InitPlog(plog::warning, plog::get());
// Engine::initPlog function
static void InitPlog(plog::Severity severity, plog::IAppender* appender)
{
    plog::init(severity, appender);
}

On windows everything is fine, but the same code report errors on osx.
Assertion failed: (appender != this), function addAppender, file /Users/xinhou/Documents/Sdk/Plog/include/plog/Logger.h, line 18.

Compiler:
Apple LLVM version 7.0.2 (clang-700.1.81)

What could possiblly be wrong ?

Error: ::_wsopen_s has not been defined

Relevant section from my console output on compile

C:\Users\heybr\plog-1.0.1\include/plog/Util.h:220:17: error: '::_wsopen_s' has not been declared
             ::_wsopen_s(&m_file, fileName, _O_CREAT | _O_WRONLY | _O_BINARY, _SH_DENYWR, _S_IREAD | _S_IWRITE);
             ^

Code used is the hello log code from the readme, compiled on MinGW G++

static library logging

Hi,

I've seen your static library example. Is it possible to turn off logging from a library of I'm not interested in seeing its output?

For example: If the library does LOGD << "debug message" a lot and I have a bunch of LOGD << "some other messages" in my main app - is it possible to quite down the logging from the library? Or is it all or nothing?

Thanks!

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!

Severity level from string?

I'm writing some code where I want to be able to set the severity at runtime based on an input parameter. Looking at Severity.h, I see that there is a way to convert from a Severity to a string, but there is no way to get a Severity from a string.

Obviously I could write my own function to do such a conversion, but do you think it would be valuable to provide such a conversion inside of plog itself? That is, something like: plog::Severity severity_from_string(const string &severity_str)

Chained loggers assetion failed

Hello. I'm trying to use plog in my application and static library (as in example):

// In library
void GL::enableLogging(plog::Severity maxSeverity, plog::IAppender* appender)
{
	plog::init(maxSeverity, appender);
}
// In application
void initializeLogging(const std::string& filename, plog::Severity maxSeverity)
{
	static plog::RollingFileAppender<Formatter> fileAppender(filename.c_str(), 8000, 1);
	static plog::ConsoleAppender<Formatter> consoleAppender;
	plog::init(maxSeverity, &fileAppender).addAppender(&consoleAppender);

	GL::enableLogging(maxSeverity, plog::get());
}

And I got folowing assertion failed:

Logger<instance> &plog::Logger<0>::addAppender(plog::IAppender *) [instance = 0]: Assertion `appender != this' failed.

If I pass &consoleAppender instead of plog::get, all messages are duplicated in console.
Am I doing something wrong?

Best regards.

Loggin with QT (QString)

Hi,

What is the better way to introduce QT (QString) support with plog ? Do I have to add a implement a Custom converter ?

Also, is there any problem using this library with multiple project ? Ex : I have a main application that is loading a DLL. I want the DLL to output to the same log file as the main application.

multiple loggers - different log levels

Hi,

If I want to log info to the console and debug to a file I might do something like this:

    plog::ConsoleAppender<plog::TxtFormatter> consoleAppender;
    plog::init<0>(plog::info, &consoleAppender);

    static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("MultiAppender.txt", 8000, 3);
    plog::init<1>(plog::debug, &fileAppender);

Now hook them up:

plog::get<0>()->addAppender(plog::get<1>());

The problem is that the debug data never makes it to the 2nd logger because it's filtered by the first one.

Is there a workaround for this? Seems appenders are really for logging the same data to multiple sinks.

The only thing that works is if I make sure to have the most verbose logger as logger <0> - then data flows to the 2nd logger.

Thanks for the great library!

DebugOutputAppender (Support linux to avoid compilation error)

What do you think of :

#pragma once

namespace plog
{
    template<class Formatter>
    class DebugOutputAppender : public IAppender
    {
    public:
        virtual void write(const Record& record)
        {
#if defined(_WIN32) && defined(_MSC_VER)  // Win32 and Visual Studio
            ::OutputDebugStringW(Formatter::format(record).c_str());
#elif defined(QT_VERSION) // Linux on Qt
            qDebug() << record; 
#else // Anything else...
            std::cerr << record;
#endif
        }
    };
}

WIN32_LEAN_AND_MEAN

Hi,

What do you think about including

#ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
#endif
#include <window.h>

before including#include <window.h> in Util.h?

This could prevent many headache of juggling with order of inclusion of plog.h when preceding headers already include (winsock.h | winsock2.h) ?

Related problems :
http://stackoverflow.com/questions/1372480/c-redefinition-header-files-winsock2-h
http://stackoverflow.com/questions/11726958/cant-include-winsock2-h-in-msvc-2010
http://stackoverflow.com/questions/11495589/winsock-redefinition-errors
https://connect.microsoft.com/VisualStudio/feedback/details/3123533/c-problem-windows-h-win32-mean-and-lean ?!?
microsoft/vcpkg#591
There a many many many other like this...

I already tried to replace window.h from Util.h as we should always avoid including window.h as it's a mess. But (in a short time) I did not succeed because of functions depending on WinBase.h and this former can't be included without including The Bad and the Ugly Windows.h.

Best regards,

try test the demo with google test and Visual Leak Detector

hi
I try test your sample - demo with Google test and vld for visual studio 2015.

I have memory leak issue need your help. If you could help me to look this issue. I could send you my simple google plog test project code to you.

Thanks

const char * : unhandled exception in lib <string>

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 ?

Signed unsigned assignment warning

RollingFileAppender.h
Line 76 should have explicit type casting to avoid warnings on platforms like osX
m_fileSize = **(size_t)**m_file.open(fileName.c_str());

osx error: "xxxxx.h" file not found

ide: xocde

  • .c
#include <stdio.h>
#include <plog/Log.h>

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!\n");
    return 0;
}
  • build settings - header search paths:
/Users/xoraxrax/Downloads/plog-1.1.3/include
  • error log:

Showing Recent Messages
CompileC /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/Objects-normal/x86_64/main.o test/main.c normal x86_64 c com.apple.compilers.llvm.clang.1_0.compiler
    cd /Users/xoraxrax/Documents/project/test
    export LANG=en_US.US-ASCII
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x c -arch x86_64 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu99 -fmodules -gmodules -fmodules-cache-path=/Users/xoraxrax/Library/Developer/Xcode/DerivedData/ModuleCache -fmodules-prune-interval=86400 -fmodules-prune-after=345600 -fbuild-session-file=/Users/xoraxrax/Library/Developer/Xcode/DerivedData/ModuleCache/Session.modulevalidation -fmodules-validate-once-per-build-session -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -Wno-trigraphs -fpascal-strings -O0 -fno-common -Wno-missing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code -Werror=deprecated-objc-isa-usage -Werror=objc-root-class -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -DDEBUG=1 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations -mmacosx-version-min=10.12 -g -Wno-sign-conversion -Winfinite-recursion -iquote /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/test-generated-files.hmap -I/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/test-own-target-headers.hmap -I/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/test-all-target-headers.hmap -iquote /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/test-project-headers.hmap -I/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Products/Debug/include -I/Users/xoraxrax/Downloads/plog-1.1.3/include -I/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/DerivedSources/x86_64 -I/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/DerivedSources -F/Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Products/Debug -MMD -MT dependencies -MF /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/Objects-normal/x86_64/main.d --serialize-diagnostics /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/Objects-normal/x86_64/main.dia -c /Users/xoraxrax/Documents/project/test/test/main.c -o /Users/xoraxrax/Library/Developer/Xcode/DerivedData/test-dvgvdptghlqeyfgegjjcugbsmepj/Build/Intermediates/test.build/Debug/test.build/Objects-normal/x86_64/main.o

In file included from /Users/xoraxrax/Documents/project/test/test/main.c:10:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Log.h:7:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Logger.h:2:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Appenders/IAppender.h:2:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Record.h:2:
/Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Severity.h:3:1: error: unknown type name 'namespace'
namespace plog
^
/Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Severity.h:3:15: error: expected ';' after top level declarator
namespace plog
              ^
              ;
In file included from /Users/xoraxrax/Documents/project/test/test/main.c:10:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Log.h:7:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Logger.h:2:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Appenders/IAppender.h:2:
In file included from /Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Record.h:3:
/Users/xoraxrax/Downloads/plog-1.1.3/include/plog/Util.h:2:10: fatal error: 'cassert' file not found
#include <cassert>
         ^
3 errors generated.

plog::Logger construction problem

Please could you explain under what circumstances will the logger not be constructed correctly? (I am using plog in an injected dll)

Code is as per docs:

plog::init(plog::verbose, logFilename, LOG_FILE_SIZE, NO_OF_LOG_FILES);
DebugTrace(L"plog::get<0>=%p", plog::get<0>());

Output:
plog::get<0>=0000000000000000

I inserted trace statements into object constructors and determined that plog::init is being called ok but Logger constructor is not. Debug output shows LOGGER INIT but not LOGGER CONSTRUCTOR from edits below. Why?

inline Logger<instance>& init(Severity maxSeverity = none, IAppender* appender = NULL)
 {
  static Logger<instance> logger(maxSeverity);

  OutputDebugStringW(L"LOGGER INIT");

  return appender ? logger.addAppender(appender) : logger;
}

Logger(Severity maxSeverity = none) : m_maxSeverity(maxSeverity)
{
  OutputDebugStringW(L"LOGGER CONSTRUCTOR");
}

Visual Studio or QT console

Hi,

May I suggest to add this

#if defined(_DEBUG) && defined(_WIN32)
    OutputDebugString( ...)
#endif

to the ColorConsoleAppender for allowing outputting text in the VS or QT console ? Of course we will loose coloring but it is more convenient when debugging.

Truncating file when creating RollingFileAppender?

Is there a way to truncate an existing log file when creating a RollingFileAppender? That is, I have a foo.log from a previous execution and when I execute the program again, I want foo.log to be overwritten.

It appears that plog specifically seeks to the end of the file when opening it. Is it worthwhile to have a flag that overrides this behavior?

No documented way to de-initialize

I really like this library. There's only one thing I"m missing though, it doesn't seem to be possible to de-initialize (close/shutdown) a log. Would it be possible to implement this?

Use case, I want a logger to start when the initialize function in my library is used. It is possible to run terminate in my library and than rerun initialize, but from that point on, the logger is printing every single log message twice. So, in my terminate function, I need to shut down the log.

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.

Crash when logging inside an Objective-C function.

Plog crashes when using LOG_INFO inside an Objective-C function. Here is the crash report call stack:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 plog::util::processFuncName(char const*) + 89 (Util.h:166)
1 plog::Record::getFunc() const + 35 (Record.h:120)
2 plog::TxtFormatter::format(plog::Record const&) + 5139 (TxtFormatter.h:25)
3 plog::RollingFileAppender<plog::TxtFormatter, plog::UTF8Converter>::write(plog::Record const&) + 223 (RollingFileAppender.h:35)
4 plog::Logger<0>::operator+=(plog::Record const&) + 408 (Logger.h:50)
5 -[MyCocoaView mouseDown:] + 62 (toolkitview_cocoa.mm:345)
...

ColorConsoleAppender thread safe

Hi there!
Currently the ColorConsolAppender is not thread safe. The colors can be mixed together during console printing.
Then you should introduce a mutex, as done in RollingFileAppender.

Thank you!

Apender request

Can you please create an appender that does the same as default (just logs to file) but also does the colour console appender at the same time, so that I don't have to have two loggers, but just one that both outputs to a file and the console in colour at the same time. Thank you

IF_LOG_ macro in if/else leads to miss else branch

The code below expects to output 'false'.

#include "plog/Log.h"

int main()
{
    plog::init(plog::info, "test.txt");

    LOG_INFO << "start";

    if (false)
        LOG_INFO << "true";
    else
        LOG_INFO << "false";

    LOG_INFO << "end";
}

2016-09-23 10:27:44.875 INFO [1820] [main@13] start
2016-09-23 10:27:44.876 INFO [1820] [main@20] end

It seems that the IF_LOG_ macro which has 'if ' leads to miss else branch.

Log not flushed

I seen that "util::File" class not flushes text.
I see that pLog uses "open" and "close" functions that are not POSIX compliant and, at least in Linux, the "close" function only close file descriptor without flushing text: so the output maybe truncated.

Is it better to use the "fopen" and "fclose" functions?

Can you fix this issue? It is a big problem for me.

Kind regards

Macro name conflict

While it is convenience to use the short name macro however they are very easy to conflict with other code, especially:

  • LOG
  • LOGD

It's better that plog provide a longer macro name with PLOG_ prefix or something to avoid such conflict and let user to define there short hand name if needed:

#include <plog/Log.h>

#define MY_LOG PLOG_LOG

MY_LOG(info) << "Will not conflict any more :)";

How to write to stdout

Hi!
Every time I use the "LOG_VERBOSE<<1;" it seems to write it to a new line.
Also, in "LOG_VERBOSE<<1<<2;" timestamp and other info are printed twice.
Is there a functionality with which I can control when the newlines are inserted?
In other words, I need something very close to standard 'cout', but with timestamp inserted just once in a line...

More parsimonius inclusion of system header files

Currently, including Log.h gives me lots of system header files, most only useful for file appenders or for obtaining the current thread ID. This is not always appropriate. Consider not including the file appenders and the code they require for operation by default, or making their inclusion conditional. Looks like this requires splitting Init.h and Utils.h, and somehow making the thread ID optional.

My scenario requires cross-platform compatibility, I have built an R package that serves only as container for your library. I don't need the file appenders, and splitting took me too long, but I'd be happy to incorporate upstream changes if the library builds on Windows (MinGW), OS X, and Linux.

Thanks for providing the library!

Error macro

Hi,
I use CLION JetBrains IDE C / C ++.

  1. plog::init(plog::info, x.substr(6, x.size()).append("/").append("createfp.log").c_str());

  2. LOGI << "INIT\n";
    ....
    The compile and run program is ok. but there is program :

Problem synopsis   Error after macro substitution: Pointer type is required at line xxxx

Help me?
Thanks.

Missing header includes

When installing to /usr/include/plog on a linux box, RollingFileAppender.h seems to be missing

#include <plog/Appenders/IAppender.h>

and IAppender.h

#include <plog/Record.h>

Stream manipulators support

Hi,
you can find attached my proposal to add stream manipulators support to plog.

plog.zip

I have tried with the following manipulators and it works: std::dec, std::hex, std::oct, std::endl, std::left, std::setfill, std::setprecision, std::setw.

Can you review and include it in the next version of plog?

Error with String^

Hello,

First, i want to thank you for this log system.
Your addon is very cool and i wouldn't drop it to another one.
But i got an error which forbids me to continue.
I can't use String in any project or i get an error.
The compile debug says that i need to put an "^" after String.

It is working fine. But, if i want to "log" a string^ variable nammed "port" with "LOGI", i get an error.
I also tried "&port" but in the log i got an var adress (Pointer) instead of variable.

I'm Visual Studio 2017 and C++ language.

My Code : https://pastebin.com/P1cRMR8S
The error : https://pastebin.com/CGviZRbe

Thanks really for service,
Tom

-liconv needed for compilation on Mac OS X 10.10

Just a minor suggestion: it might be useful to note somewhere that in order to get compilation on Mac OS X 10.10 (and possibly later, though I haven't checked) to work, you need to explicitly link to the iconv library ("-liconv").

Chained sample crashes if DLL and EXE are built with different version of Visual Studio

@purell found that binary compatibility is broken:

I properly follow the instruction for Chained Loggers but now I'm getting a crash (Access violation) when the shared library is doing the first log operation.

App

QString sApplicationFilePath = QCoreApplication::instance()->applicationFilePath();
QFileInfo fileInfo(sApplicationFilePath);
QString sLogFilePath = QDir::cleanPath( QDir( fileInfo.path() ).filePath( fileInfo.baseName() + ".log" ) );
static plog::RollingFileAppender<plog::TxtFormatter> fileAppender(sLogFilePath.toUtf8(), 1048576, 1);
plog::init(plog::debug, &fileAppender)

// Initialize the logger in the shared library.
CacheInitializePLog(plog::debug, plog::get());

Shared library

void CacheInitializePLog(plog::Severity severity, plog::IAppender* appender) {

    // Initialize the library logger
    plog::init(severity, appender);
}

Stack trace

MyApp.exe!std::char_traits<char>::length(const char * _First) Line 523	C++
MyApp.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const char * _Ptr) Line 1169	C++
MyApp.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(const char * _Ptr) Line 783	C++
MyApp.exe!plog::util::processFuncName(const char * func) Line 149	C++
MyApp.exe!plog::Record::getFunc() Line 122	C++
MyApp.exe!plog::TxtFormatter::format(const plog::Record & record) Line 25	C++
MyApp.exe!plog::RollingFileAppender<plog::TxtFormatter,plog::UTF8Converter>::write(const plog::Record & record) Line 46	C++
MyApp.exe!plog::Logger<0>::operator+=(const plog::Record & record) Line 54	C++
MyApp.exe!plog::Logger<0>::write(const plog::Record & record) Line 48	C++
MyShared.dll!plog::Logger<0>::operator+=(const plog::Record & record) Line 54	C++
MyShared.dll!DoSomething() Line 61	C++

The stack around Record seem to be corrupted on the line

MyApp.exe!plog::Logger<0>::write(const plog::Record & record) Line 48   C++

Converter on the QT side

plog::Record& plog::operator << (plog::Record& record, const QString& msg)
{
	return record << msg.toStdString();
}

QT Configuration

win32 {
    DEFINES -= UNICODE _UNICODE
    DEFINES += _MBCS _WIN32
}

I'm on this problem since yesterday and I've never found the solution yet. I'm about to give up.

The shared library and the app are build without _UNICODE support/defined. Thus, at the beginning I though that the problem could be here :

    namespace util
    {
#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

No test are done for _UNICODE macro, but I finally conclude those typedef are probably for your internal string operation. When we are using the << operator for logging, you convert it according the user input type.

I found that compiling the shared library with Visual Studio 2013 instead of Visual Studio 2008 do not produce the crash. But I'm stuck with VS 2008 for the time being.

Maybe this ?
Visual C++ change history 2003 - 2015

To implement various optimizations and debugging checks, the C++ Standard Library implementation intentionally breaks binary compatibility among versions of Visual Studio (2005, 2008, 2010, 2012). When the C++ Standard Library is used, this forbids the mixing of object files and static libraries that are compiled by using different versions into one binary (EXE or DLL), and forbids the passing of C++ Standard Library objects between binaries that are compiled by using different versions. The mixing of object files and static libraries (using the C++ Standard Library) that were compiled by using Visual C++ 2010 with those that were compiled by using Visual C++ in Visual Studio 2012 emits linker errors about _MSC_VER mismatch, where _MSC_VER is the macro that contains the compiler's major version (1700 for Visual C++ in Visual Studio 2012). This check cannot detect DLL mixing, and cannot detect mixing that involves Visual C++ 2008 or earlier.

error on ConsoleAppender

I'm trying to use multi appender sample

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

but I get the error:
error: ‘ConsoleAppender’ in namespace ‘plog’ does not name a template type

I'm using gcc 4.9.4 on ubuntu 14.04 wiht Eclipse 3.8

Issue in Qt callbacks

Hello,

First of all, thanks for this pretty useful and easy-to-use lib. :)

I'm having an issue using it with Qt, the calls to LOG_DEBUG within a Qt callback (and subsequent calls) are not written in my output file.

I wonder if this is due to threads (possibly) created by Qt to manage its callbacks.

Is there something specific to do in order to use the logger in these callbacks ? Am I missing something ?

Thank you,

d!

expected an identifier?

Hi, i'm using VS2012, my program complies&runs fine.
But the editor continues to report errors like:
IntelliSense: expected an identifier path_to_cpp_file_where_calls_LOGD

What's going on there?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.