锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C++开源技术 / Plog使用体验和开发指导
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品开源,禁止转载和任何形式的非法内容使用,违者必究


Plog使用体验和开发指导


体验

Plog用于生成日志内容,从www.codeproject.com上下载。把它的目录加入到项目里,可以直接使用,目录里是头文件。它用流的方式来生成日志,操作方便。日志内容里还有写日志的函数信息,很直观。跨线程使用也支持,我在主线程和子线程里都进行了日志输出,可以正常完成。Plog可以指定文件组来当做输出目标,当一个文件满了或占用时,自动生成新的日志文件,此功能体现了Plog的全面性。

Introduction介绍

前言


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 automatic 'this' pointer capture. Plog是一个C ++ 日志库,设计目标是尽可能简单、小巧和灵活。它是作为现有大型库的替代创建的,并提供一些独特的功能,如  CSV 日志格式  和  自动”this”指针捕获。
Here is a minimal hello log sample: 这是一个最小的hello 日志示例:

  #include <plog/log.h> // Step1:  include the header.
  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.
      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特点

  • Very small (less than 1000 LOC)
  • Easy to use
  • Headers only
  • No 3rd-party dependencies
  • Cross-platform: Windows, Linux, Mac OS X, Android (gcc, clang, msvc)
  • Thread and type safe
  • Formatters: TXTCSVFuncMessage
  • Appenders: RollingFileConsoleAndroid
  • Automatic 'this' pointer capture (supported only on msvc)
  • Lazy stream evaluation
  • Unicode aware, files are stored in UTF8
  • Doesn't require C++11
  • Extendable
  • 很小(小于1000 LOC)
  • 使用方便
  • 仅限标题
  • 没有第三方依赖
  • 跨平台:Windows,Linux,Mac OS X,Android(gcc,clang,msvc)
  • 线程和类型安全
  • 格式化程序:  TXT,  CSV,  FuncMessage
  • 数据来源:  RollingFile,  Console,  Android
  • 自动'this'指针捕获  (仅在msvc上支持)
  • 懒流评估
  • 支持Unicode,文件以UTF8格式存储
  • 不需要C ++ 11
  • 可扩展

Usage用法

To start using plog you need to make 3 simple steps. 3个简单步骤

Step 1: Adding includes第1步:添加包含

At first your project needs to know about plog. For that you have to: 首先,您的项目需要了解p log。为此你必须:

  • Add plog/inlcude to the project include paths
  • 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)
  • 添加   plog/inlcude到项目包括路径
  • 添加   #include <plog/log.h>到您的cpp / h文件中(如果您有预编译的头文件,那么它是添加此文件的好地方)

Step 2: Initialization第2步:初始化

The next step is to initialize the Logger. This is done by the following plog::init function: 下一步是初始化  Logger。这是通过以下功能完成的:plog::init

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: maxSeverity是logger严重性上限。所有日志消息都有自己的严重性,如果高于限制,则丢弃这些消息。P log定义以下严重性级别:

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

The log format is determined automatically by fileName file extension: 该日志格式由fileName 文件的扩展名自动确定  :

  • .csv => CSV format
  • anyting else => TXT format

The rolling behavior is controlled by maxFileSize and maxFiles parameters: 切换行为由maxFileSize 和  maxFiles 参数控制  :

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

  • maxFileSize - 最大日志文件大小(以字节为单位)
  • maxFiles - 要保留的日志文件个数

如果其中一个为零,则禁用日志文件切换。
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. 这里初始化logger以将具有高达警告严重性的所有消息写入csv格式的文件。最大日志文件大小设置为1'000'000字节,并保留5个日志文件。

Step 3: Logging第3步:写日志

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. logging是在特殊宏的帮助下执行的。日志消息是使用流输出操作符构成 <<。因此,与格式字符串输出相比,它是类型安全的和可扩展的。

Basic logging macros基本日志 宏

This is the most used type of logging macros. They do unconditional logging. 这是最常用的日志宏类型。他们是无条件的日志
Long macros:

log_VERBOSE << "verbose";
log_DEBUG << "debug";
log_INFO << "info";
log_WARNING << "warning";
log_ERROR << "error";
log_FATAL << "fatal";

Short macros:

logV << "verbose";
logD << "debug";
logI << "info";
logW << "warning";
logE << "error";
logF << "fatal";

Function-style macros:

log(severity) << "msg";

Conditional logging macros条件日志 ging宏

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:

log_VERBOSE_IF(cond) << "verbose";
log_DEBUG_IF(cond) << "debug";
log_INFO_IF(cond) << "info";
log_WARNING_IF(cond) << "warning";
log_ERROR_IF(cond) << "error";
log_FATAL_IF(cond) << "fatal";

Short macros:

logV_IF(cond) << "verbose";
logD_IF(cond) << "debug";
logI_IF(cond) << "info";
logW_IF(cond) << "warning";
logE_IF(cond) << "error";
logF_IF(cond) << "fatal";

Function-style macros:

log_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_log(severity)

Sample:

IF_log(plog::debug) // we want to execute the following statements only at debug severity (and higher)
{
    for (int i = 0; i < vec.size(); ++i)
    {
        logD << "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: 非典型的日志案例需要使用自定义初始化。它由以下功能完成:plog::init

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!
您必须构造一个 使用Formatter参数化  的 Appender并将其传递给函数plog::init
注意:appender的生命周期应该是静态的!
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中可以有多个 Appender。在这种情况下,所有这些追加器都会写日志消息。使用以下方法来实现:

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. 这里logger以日志消息写入文件和控制台的方式初始化。

Multiple loggers多个日志目标

Multiple Loggers can be used simultaneously each with their own separate configuration. The Loggers differ by their instance number (that is implemented as a template parameter). The default instance is zero. Initialization is done by the appropriate template plog::initfunctions: 多个  Loggers  可以同时使用,每个都有自己独立的配置。日志之间区别在于它们的实例数目不同(用模板参数来实现)。默认实例为零。初始化由适当的模板函数完成:plog::init

logger<instance>& init<instance>(...);

To get a logger use plog::get function (returns NULL if the logger is not initialized): 获取日志使用plog::get函数(如果日志未初始化则返回 NULL)

logger<instance>* get<instance>();

All logging macros have their special versions that accept an instance parameter. These kind of macros have an underscore at the end: 所有日志宏都有它们接受实例参数的特殊版本。这些宏最后有一个下划线:

logD_(instance) << "debug";
logD_IF_(instance, condition) << "conditional debug";
IF_log_(instance, severity)

Sample:

enum // Define log instances. 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.
    logD << "Hello default log!";
   
    // Write some messages to the 2nd log.
    logD_(Secondlog) << "Hello second log!";
   
    return 0;
}

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. 一个日志实例可作为其它日志追加器。因此,您可以将多个日志链接在一起。这对于将日志消息从共享库流式传输到主应用程序二进制文件非常有用。
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()
{
    logI << "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.
    logD << "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;
}

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设计得小而灵活,因此它更喜欢模板来继承接口。所有主要实体都显示在以下UML图中:
Plog架构
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
  • Logger - 主要对象,实现为单例
  • 记录  - 保存日志数据:时间,消息等
  • Appender  - 表示日志数据目标:文件,控制台等
  • Formatter  - 将日志数据格式化为字符串
  • 转换器  - 将格式化程序输出转换为原始缓冲区

 

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 IAppenderinterface. Also there can be several independent loggers that are parameterized by an integer instance number. The default instance is 0. Logger 是整个日志系统的中心对象。它是一个单例,因此它形成了一个已知的单一入口点,用于配置和处理日志数据。 logger 可以作为  另一个Logger的Appender,  因为它实现了 接口。此外,可以有几个独立的日志gers,它们由整数实例编号参数化。默认实例为0。IAppender

template<int instance>
class logger : public util::Singleton<logger<instance> >, 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
  • function name
  • message

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 void* object);

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

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

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

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

    const util::Time& getTime() const;
    Severity getSeverity() const;
    unsigned int getTid() const;
    const void* getObject() const;
    size_t getLine() const;
    const util::nstring getMessage() const;
    std::string getFunc() const;
};

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 formatand header:
Formatter  负责将Record中的日志数据 格式化 为各种字符串表示形式(也可以使用二进制形式)。格式化程序没有基类,它们实现为具有静态函数的类,这些静态函数为:format和header

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

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]

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.
这是最强大的日志格式。它可以在没有任何工具的情况下轻松读取(但比TXT格式更难  ),并且如果使用支持CSV的工具(如Excel)打开它,则可以进行大量分析。可以根据单元格值突出显示一行,可以隐藏另一行,可以操作列,甚至可以对日志数据运行SQL查询!如果log很大并需要大量分析,这是推荐的格式。此外,还显示了“this”指针,因此可以将对象实例分开。

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.
FuncMessageFormatter
This format is designed to be used with appenders that provide their own timestamps (like AndroidAppender or linux syslog facility).
此格式旨在与提供自己时间戳的appender一起使用(如  AndroidAppender  或linux sys log 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:

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:
Converter  负责将Formatter  输出数据转换为 原始缓冲区(表示为  std::string)。RollingFileAppender使用它   在写入文件之前执行转换。转换器没有基类,它们被实现为具有静态函数的类,  静态函数为:convert和  header:

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

UTF8Converter
UTF8Converter is the only converter available in plog out of the box. It converts string data to UTF-8 with BOM.
UTF8Converter  是plog直接即可使用的唯一转换器。它使用BOM将字符串数据转换为UTF-8。
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 IAppenderinterface (the only interface in plog):
Appender  使用  Formatter  和  Converter  来获得所需的日志数据表示,并将其输出(附加)到文件/控制台/等。所有appender都必须实现  IAppender接口(p log唯一的接口):

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

RollingFileAppender
This appender outputs log data to a file with rolling behaviour. As template parameters it accepts both Formatter and Converter.
此appender将日志数据输出到具有切换行为的文件。作为模板参数,它接受  Formatter  和  Converter。

RollingFileAppender<Formatter, Converter>::RollingFileAppender(const char* 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 maxFileSizeor maxFilesis 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)

Note: the lowest maxFileSize is 1000 bytes.
ConsoleAppender
This appender outputs log data to stdout. As a template parameter it accepts Formatter.

ConsoleAppender<Formatter>::ConsoleAppender();

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

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

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.

logD << /* 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)

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

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 nstringand nstringstream('n' for native) that are defined as:

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

By default all log files are stored in UTF-8 with BOM thanks to UTF8Converter.
Note: on Android wide string support in plog is disabled.
Performance
Plog is not using any asynchronous techniques so it may slow down your application on large volumes of logmessages.
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.

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

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

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

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);
    };
}
友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内