Table of Contents
The client library log4j
from the
Apache Logging Framework
contains a quite large number of features. log4sendpp adopts the basic
working methods and implements the most important features. For that reason it should
not be too difficult to switch to a more feature rich logging libary
like log4cxx
if you need to.
All features are basically grouped into for categories:
Diagnostic data encompass basic data like a user defined message and the according sourcefile and line number. But there is also extended data to describe the current context of the running process and even thread.
A formatter converts the diagnostic data into a representation that can be sent to some consumer. A consumer may be a remote host or a simple data storage like a regular file.
An appender sends the converted diagnostic data to the according consumer. An appender can write into a regular file or send over a network.
A logger finally ties everything together and provides simple means to send logging data.
There are several ways to handle diagnostic data which are grouped into the following two types:
Local information about a few of the current statements. This
information is encapsulated in class LocationInformation
.
The general context which can describe more of the current
programm flow. This extended information is handled with the classes
MDC
, NDC
,
Property
and ThreadDictionary
which are explained below.
LocationInformation
This class contains information about the location from where the log messsage came.
NDC
Stands for Nested Diagnostic Context. Here you can append descriptions about the course of your programm flow. Every time you send a log message the whole content of the NDC is sent. An NDC is organized like a stack. So it is possbile to remove descriptions one after the other when the program leaves a context.
Property
A property is a simple pair of a name and a value. You can used whatever name you wish to, but some properties are already in use. application and hostname contain the values you passed to initialize log4sendpp. Similar to the former NDC all properties are included when you send a log message.
MDC
MDC stand for Mapped Diagnostic Context.
It works similar to Property
but is intended
for example to help distinguish the flow of threads.
All MDC values are included when you send a log message.
ThreadDictionary
This dictionary helps to distinguish all the running threads
by assigning a nickname to a platform dependent thread identifier.
This nickname is then used in a LocationInformation
.
log4sendpp offers two formatters to cover the common use cases.
Mainly intended
for logging to files in a format used by syslog is
SimpleFormatter
[ 18:05:37,400ERROR ] first message [ 18:05:37,400 ERROR . second message . 18:05:37,400 ERROR .second line . 18:05:37,400 ERROR . third line . 18:05:37,400 ERROR ] forth line
The second format is mainly used when messages are sent to logging applications like Chainsaw which can receive messages in XML format over a network or read regular files.
An example created by XmlFormatter
could look like this:
<log4j:event logger="category2" timestamp="1529829438" sequenceNumber="3" level="INFO" thread="threadname"> <log4j:message>second message</log4j:message> <log4j:throwable>throwablename</log4j:throwable> <log4j:NDC>my-ndc</log4j:NDC> <log4j:MDC> <log4j:data name="mdc1" value="val1" /> <log4j:data name="mdc2" value="val2" /> </log4j:MDC> <log4j:locationInfo file="filename" line="1234" class="" method="methodname" /> <log4j:properties> <log4j:data name="application" value="test" /> <log4j:data name="hostname" value="hostname" /> <log4j:data name="prop1" value="val1" /> </log4j:properties> </log4j:event>
Appenders are used to forward the log messages to their destination. log4sendpp contains two of the most important classes:
A FileAppender
appends the log messages
at the end of a local regular file
A TcpIpAppender
sends the messages
over a TCP/IP network to a local or remote log host.
An ostream_Appender
redirects messages to a standard std::stream
.
This class may be useful to bridge a gap to other frameworks like
Boost.Test.
For covenient access all the logger helper classes are tied together
by a Logger
. You can either use a predefined default
object with a TcpIpAppender
and a
FileAppender
:
Logger &logger = Logger::logger(); logger.ndc().push("trivial context"); logger.info("info message"); logger.warn("warn message");
or you can create your own setting:
Logger mylogger; mylogger.setPrimaryAppender(new TcpIpAppender( new XmlFormatter("appname", "localhost"), "localhost")); mylogger.setSecondaryAppender(FileAppender app ( new SimpleFormatter("appname"), "testfile.txt"));
By default two appenders are used. The second is only used if the first fails for some reason. This way you can preferably log over a network and still store everything to a file when there is not network available or the remote log host is not running.
If you want to add location information to trace the file and line it is more convenient to use the logging macros instead of the plain method calls. These macros already contain this information and also request the current nickname from the thread dictionary:
LOG4SENDPP_TRACE("trace by macro\nline2"); LOG4SENDPP_DEBUG("debug by macro\nline2\nline3");
There are some more lower level macros which might become interesting if you wish to build your own macro for logging information.
LOG4SENDPP_MACRO_TI("message throwinfo", "exception name", Logger::Info); LOG4SENDPP_MACRO_LI("message location", "category", Logger::Error); LOG4SENDPP_MACRO_LTI("message", "category", "exception name", Logger::Error);
An possible application is to create a macro which throws an exception. Before actually throwing the exception you could send the log message to be informed about every thrown exception and the according location.
#define THROW_ASSERTION(txt) \ { \ LOG4SENDPP_MACRO_TI(txt, L"Assertion", Logger::LogError); \ throw Assertion(txt, __FILE__, __LINE__) ; \ }
Error messages might be confusing | |
---|---|
All these macros surround the according parameters with a do { ... } while(false) sequence. This is neccessary to be able to use the macros like normal function calls. Otherwise there might be situations in if - statements leading to forbidden code. Unfortunately your compiler may issue confusing error messages regarding this do .. while statement if you place incorrect code into the macro. |