[C++] POCO learning summary (17): Log system (level, channel, formatting, record flow)

[C++] Guo Laoer’s blog post: C++ directory

1. Poco::Message log message

1.1 Description

All log messages are stored and transmitted in Poco::Message objects.
Header file: #include "Poco/Message.h"
A message contains the following content: priority, source, a text, a timestamp, process and Thread identifier, optional parameters (name-value pairs)

1.2 Message priority

POCO defines 8 message priorities:

  • PRIO_FATAL (highest priority)
  • PRIO_CRITICAL
  • PRIO_ERROR
  • PRIO_WARNING
  • PRIO_NOTICE
  • PRIO_INFORMATION
  • PRIO_DEBUG
  • PRIO_TRACE (lowest priority)

Set and get priority

  • void setPriority(Priority prio)
  • Priority getPriority() const

1.3 Sources

Message source: generally the name of the class that generates the message, or the name of the subsystem that generates the message

  • void setSource(const std::string& source)
  • const std::string& getSource() const

1.4 Message content

The actual message to log. There are no requirements on format, length, etc. Can be modified by the formatter before appearing at the log destination

  • void setText(const std::string& text)
  • const std::string& getText() const

1.5 Timestamp

The date and time when the message was created, with microsecond accuracy.
is automatically initialized to the current date and time by the constructor of Poco::Message.

  • void setTime(const Timestamp& time)
  • const Timestamp& getTime() const

1.6 Process and thread identifiers

The process identifier (PID) is a long integer value used to store the process ID of the system.
The thread identifier (TID) is also a long integer value that stores the sequence number of the current thread.
The process identifier, thread identifier and thread name are initialized in the constructor of Poco::Message.

  • void setThread(const std::string& threadName)
  • const std::string& getThread() const
  • void setTime(long time)
  • long getTid() const
  • void setPid(long pid)
  • long getPid() const

1.7 Message parameters

Messages can store any number of key-value pairs. Keys and values ​​can be arbitrary strings. Message parameters can be referenced in formatters. Use the index operator to access message parameters.

2. Poco::Logger logging

2.1 Create

Poco::Logger is the main entry point of the logging framework.
Header file #include “Poco/Logger.h”
The application uses an instance of the Poco::Logger class to generate log messages.
Each logger has an attached channel that delivers messages to their destination (possibly via other channels).
Each logger has a name, which becomes the source of all messages generated by that logger. This name is set at creation time and cannot be changed later

2.2 Priority

The logger filters messages based on their priority.
Only messages with a priority equal to or higher than the logger's log level will be propagated.
For example:
A logger with the log level set to PRIO_ERROR will only propagate messages with priorities PRIO_ERROR, PRIO_CRITICAL or PRIO_FATAL.
PRIO_WARNING or lower values ​​will be discarded.

2.3 Logger hierarchy

According to their names, loggers form a tree-like hierarchy.
The name of a logger consists of one or more components, separated by periods. Each component corresponds to a name in the namespace of the previous component.
A special logger, the root logger, is a logger with an empty string as its name. It forms the root of the logger hierarchy.
There is no limit on the maximum depth of the logger hierarchy.

Insert image description here

2.4 Inheritance hierarchy

A newly created logger inherits its log level and attached channels from its ancestors in the logger hierarchy.
For example: When created, the logger "HTTPServer.RequestHandler.cgi" will inherit its log level and attached channels from the logger named "HTTPServer.RequestHandler".
Once a logger is fully created, it is no longer related to its ancestor. In other words, changes to a logger's log level or channel have no effect on its already existing descendants.

2.5 Recording logs

  • void log(const Message&msg): If the priority of the message is greater than or equal to the logger's log level, the message is propagated to the attached channel. The information remains the same.

  • void log(const Exception& exc): Create and record a message with priority PRIO_ERROR and the display text of the exception

Create and log messages with respective priorities and given text:

  • void fatal(const std::string& text)
  • void critical(const std::string& text)
  • void error(const std::string& text)
  • void warning(const std::string& text)
  • void notice(const std::string& text)
  • void information(const std::string& text)
  • void debug(const std::string& text)
  • void trace(const std::string& text)

void dump(const std::string& text,const void* buffer, int length,Message::Priority prio = Message::PRIO_DEBUG)
Use the given priority Log the given message. The text is followed by a hex dump of the given buffer.

2.6 Log level

  • bool is(int level) const: Returns true if the logger's log level is at least level. - bool fatal() const

Returns true if the logger's log level is at least the corresponding level:

  • bool critical() const
  • bool error() const
  • bool warning() const
  • bool notice() const
  • bool information() const
  • bool debug() const
  • bool trace() const

2.7 Logger

POCO manages a global logger mapping.
Do not create your own logger. To use POCO provide a reference to the logger. POCO will dynamically create new loggers as needed.

static Logger& get(const std::string& name)

Returns a reference to the logger with the given name. A logger will be created automatically if there is none. This is thread safe.

2.8 Example

#include "Poco/Logger.h"
using Poco::Logger;
int main(int argc, char** argv)
{
    
    
	Logger& logger = Logger::get("TestLogger");
	logger.information("This is an informational message");
	logger.warning("This is a warning message");
	return 0;
}

3. Poco::Channel channel

3.1 Description

Subclasses of Poco::Channel are responsible for delivering messages (Poco::Message) to their destination (for example, the console or log file).
Each Poco::Logger (itself a subclass of Poco::Channel) is connected to Poco::Channel. POCO provides various subclasses of POCO::Channel that pass messages to the console, log files, or the system's logging facilities.
You can define your own channel class.
Channels use reference counting for memory management.

3.2 Channel characteristics

Channels can support any number of properties (key-value pairs), which are used to configure the channel.
The property is set through the setProperty() member function:
The value of the property can be obtained through getProperty():
These two This function is defined in the Poco::Configurable class, which is the superclass of Poco::Channel.

  • void setProperty(const std::string& name, const std::string& value)
  • std::string getProperty(const sdt::string& name)

3.3 Poco::ConsoleChannel console channel

Poco::ConsoleChannel is the most basic channel implementation.
Header file: #include "Poco/ConsoleChannel.h"
Poco::ConsoleChannel simply writes the text of any message received to standard output (std: :clog).
Poco::ConsoleChannel has no configurable properties.
Poco::ConsoleChannel is the default channel for the root logger.

3.4 Poco::WindowsConsoleChannel Windows console

Poco::WindowsConsoleChannel is similar to ConsoleChannel, but writes directly to the Windows console instead of std::clog.
Header file: #include "Poco/WindowsConsoleChannel.h"
Poco::WindowsConsoleChannel simply writes the text of any message received to the Windows console.
Poco::WindowsConsoleChannel has no configurable properties.
Poco::WindowsConsoleChannel supports > UTF-8 encoded text.

3.5 Poco::NullChannel empty channel

Poco::NullChannel discards all messages sent to it.
Header file: #include "Poco/NullChannel.h"

3.6 Poco::SimpleFileChannel simplest log file

3.6.1 Description

Poco::SimpleFileChannel is the simplest way to write log files.
The text of the message is appended to a file, followed by a newline character.
Supports optional simple log file rotation: between primary and standby log filesTake turns writing, when the primary log file exceeds a certain size, a backup log file will be created (if it already exists, it will be emptied). If the standby log file exceeds the maximum size, the primary log file is cleared and recording continues to the primary log file, and so on.

3.6.2 Properties

1) path: main log file path.
2) secondaryPath: backup log file path. The default is path.1
3) rotation: log file size

  • never: Default, always recorded in the main log file
  • n: rotate when file size exceeds n bytes
  • n K: Rotate when file size exceeds n Kb
  • n M: Rotate when file size exceeds n Mb

3.6.3 Example

#include "Poco/Logger.h"
#include "Poco/SimpleFileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::SimpleFileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
    
    
	AutoPtr<SimpleFileChannel> pChannel(new SimpleFileChannel);
	pChannel->setProperty("path", "sample.log");
	pChannel->setProperty("rotation", "2 K");
	Logger::root().setChannel(pChannel);
	Logger& logger = Logger::get("TestLogger"); // 继承根通道
	for (int i = 0; i < 100; ++i)
		logger.information("Testing SimpleFileChannel");
	return 0;
}

3.7 Poco::FileChannel file channel

3.7.1 Description

Poco::FileChannel provides comprehensive log file support.
Header file: #include "Poco/FileChannel.h"
The text of the message is appended to a file, followed by a newline character.
Poco::FileChannel supports rotating log files based on file size or time interval.
Poco::FileChannel supports automatic archiving (different file naming strategies), compression (gzip) and purging (based on the time of archived files or the number of archived files) of archived log files.

3.7.2 Properties

1) path: log file path
2) rotation: log file rotation method

  • never does not rotate
    • n: rotate when file size exceeds n bytes
  • n K: Rotate when file size exceeds n Kb
  • n M: Rotate when file size exceeds n Mb
  • [day,][hh:][mm]: rotate at the specified week/time
  • daily/weekly/monthly:daily/weekly/monthly
  • n hours/weeks/months: every n hours/weeks/months

3) archive: naming of archived log files

  • number: An automatically incrementing number, starting from 0, appended to the log file name. The latest archived file is always 0.
  • timestamp: A timestamp in YYYYMMDDHHMMSS format is appended to the log file.

4) times: Specify whether the rotation time is treated as local time or UTC time. Valid values ​​are local and utc.
5) compress: Automatically compress archive files. Specify true or false.
6) purgeAge: Specify the maximum storage time of archived log files. Files older than this time will be cleared.
7) purgeCount: Specify the maximum number of archived log files. If this number is reached, the oldest archived log files will be purged.

3.7.3 Example

#include "Poco/Logger.h"
#include "Poco/FileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::FileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
    
    
	AutoPtr<FileChannel> pChannel(new FileChannel);
	pChannel->setProperty("path", "sample.log");
	pChannel->setProperty("rotation", "2 K");
	pChannel->setProperty("archive", "timestamp");
	Logger::root().setChannel(pChannel);
	Logger& logger = Logger::get("TestLogger"); // 继承根通道
	for (int i = 0; i < 100; ++i)
		logger.information("Testing FileChannel");
	return 0;
}

3.8 Poco::EventLogChannel Windows only

Poco::EventLogChannel: Only used on Windows NT platform to record Windows event logs.
Poco::EventLogChannel registers PocoFoundation.dll as a message definition resource DLL in the Windows event log.
When viewing the Windows event log, the event viewer application must be able to find PocoFoundation.dll, otherwise the log messages will not appear as expected.

3.9 Poco::SyslogChannel Linux-specific

Poco::SyslogChannel, available only on Unix platforms, logs to the local Syslog daemon.
The Net library contains a RemoteSyslogChannel class that uses the UDP-based Syslog protocol to work with remote Syslog daemons.

3.10 Poco::AsyncChannel asynchronous channel

Poco::AsyncChannel allows running channels in separate threads.
Decouple the thread that generates the log message from the thread that delivers the log message.
All log messages are stored in the FIFO queue.
A separate thread extracts messages from the queue and sends them to another channel.

#include "Poco/Logger.h"
#include "Poco/AsyncChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::AsyncChannel;
using Poco::ConsoleChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
    
    
	AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
	AutoPtr<AsyncChannel> pAsync(new AsyncChannel(pCons));
	Logger::root().setChannel(pAsync);
	Logger& logger = Logger::get("TestLogger");
	for (int i = 0; i < 10; ++i)
		logger.information("This is a test");
	return 0;
}

3.11 Poco::SplitterChannel distribution channel

Poco::SplitterChannel forwards messages to one or more other channels.
void addChannel(Channel* pChannel) adds a new channel to Poco::SplitterChannel

#include "Poco/Logger.h"
#include "Poco/SplitterChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/SimpleFileChannel.h"
#include "Poco/AutoPtr.h"
using Poco::Logger;
using Poco::SplitterChannel;
using Poco::ConsoleChannel;
using Poco::SimpleFileChannel;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
    
    
	AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
	AutoPtr<SimpleFileChannel> pFile(new SimpleFileChannel("test.log"));
	AutoPtr<SplitterChannel> pSplitter(new SplitterChannel);
	pSplitter->addChannel(pCons);
	pSplitter->addChannel(pFile);
	Logger::root().setChannel(pSplitter);
	Logger::root().information("This is a test");
	return 0;
}

4. Poco::LogStream log stream

Poco::LogStream provides the ostream interface for Logger.
All features of the stream can be used to format log messages.
Log messages must end with std::endl (or CR or LF characters).

Message priority can be set

  • LogStream& priority(Message::Priority prio)
  • LogStream& fatal()
  • LogStream& critical()
  • LogStream& error()
  • LogStream& warning()
  • LogStream& notice()
  • LogStream& information()
  • LogStream& debug()
  • LogStream& trace
#include "Poco/LogStream.h"
#include "Poco/Logger.h"
using Poco::Logger;
using Poco::LogStream;
int main(int argc, char** argv)
{
    
    
	Logger& logger = Logger::get("TestLogger");
	LogStream lstr(logger);
	lstr << "This is a test" << std::endl;
	return 0;
}

5. Log formatting

5.1 Description

Poco::FormattingChannel and Poco::Formatter are responsible for formatting log messages.
Poco::FormattingChannel passes each message it receives to Poco::Formatter before propagating the message to the next channel.
Formatter is the base class for all formatter classes.
Like channels, formatters can be configured using properties.

5.2 PatternFormatter

PatternFormatter formats messages according to printstyle printing pattern

#include "Poco/ConsoleChannel.h"
#include "Poco/FormattingChannel.h"
#include "Poco/PatternFormatter.h"
#include "Poco/Logger.h"
#include "Poco/AutoPtr.h"
using Poco::ConsoleChannel;
using Poco::FormattingChannel;
using Poco::PatternFormatter;
using Poco::Logger;
using Poco::AutoPtr;
int main(int argc, char** argv)
{
    
    
	AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
	AutoPtr<PatternFormatter> pPF(new PatternFormatter);
	pPF->setProperty("pattern", "%Y-%m-%d %H:%M:%S %s: %t");
	AutoPtr<FormattingChannel> pFC(new FormattingChannel(pPF, pCons));
	Logger::root().setChannel(pFC);
	Logger::get("TestChannel").information("This is a test");
	return 0;
}

6. Performance

Creating the message takes some time (the current time, current process ID and current thread ID must be determined).
Creating a meaningful message may take more time because string concatenation and number formatting etc. are necessary.
Messages are usually passed in a channel chain by reference.
Special: formattingchannel and AsyncChannel create a copy of the message.

For each logger, logging is always enabled or disabled (or more precisely, the log level is set) individually, so once you have a reference to the logger, determining which log level to set for a specific logger is A constant time operation (simple inline integer comparison).

Getting a reference to the logger is an operation with logarithmic complexity (basically a std::map lookup). The name of the logger is used as the key in the lookup, so the length of the logger name affects lookup time linearly (string comparison). However, this is probably negligible.

Normally, a reference to the logger (logger::get()) is obtained only once in the application. For example, in a class, you can get a reference to its logger in the class's constructor and then only use that reference from then on.
Frequent calls to Logger::get() should be avoided. It's better to call it once for each logger you will use, and then store the reference to the logger for later use.
Logging performance depends on the channel you want to use. Actual channel performance is highly system dependent.

Constructing log messages is usually a time-consuming operation, including string creation, string concatenation, number formatting, etc.
In this case, it is a good idea to check whether the message will be logged before constructing it, using methods such as is(), fatal(), critical(), etc.
There are also some macros that check before constructing the message: poco_fatal(msg), poco_critical(msg), poco_error(msg)

if (logger.warning())
{
    
    
	std::string msg("This is a warning");
	logger.warning(msg);
}

Equivalent to: poco_warning(logger, “This is a warning”);

Guess you like

Origin blog.csdn.net/u010168781/article/details/135025308