Here we will show how to use the Logging framework. If you just want to use the logger, the next two sections (Error levels and Quick HOWTO) should explain it to you in no time. If you want to know more about the logger, read the Logger manual further below.
for
cycle, you can put a SEPARATOR inside the for
to separate every iteration.This section is intended to be a simple explanation on how to use the logger, for more detailed information see below.
The main class is called Logger
, and you can create a logger of the type FastLogger
with something like:
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<Logger> logger = FastLogger::build();
The FastLogger
is thread unsafe, if you need thread safety use the ThreadSafeLogger
. The header name changes accordingly.
Then, tell it where to send the output:
logger->enableAllLogLevels(TerminalOutput::build());
Besides the TerminalOutput
there is a FileOutput
and a DataFeedOutput
. The header names change accordingly.
Using the logger is also very simple. To log a simple std::sting
:
logger->step("The string to log. You can use the other levels, also in lowercase.");
To log anything that is not a string, like numbers:
LSTEP(logger, "(4.0/6)=" << (4.0/6));
The <<
operator works just like the stringstream's because it is the stringstream's. In fact, LSTEP
is a macro that uses a ostringstream to create a string for the method described above, but this implementation might change in the future.
To log in any other level, just replace step by the name of the level, as listed above.
The output of the above would be:
17:18:56 The string to log. You can use the other levels, also in lowercase.
17:18:56 (4.0/6)=0.666667
The logger is intended to be used for three main purposes:
Loggers are always objects of type CountedPtr<Logger>
. However, Logger
is the abstract base class of the logger, and you have instatiate a concrete logger. You can choose from a fast logger type, or a slightly slower but thread safe one. Create the fast one using:
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<Logger> logger = FastLogger::build();
And the thread safe one:
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<Logger> logger = ThreadSafeLogger::build();
You can think of the logger as having two parts. The logger itself is no more than a router that sends the messages you give it to the right outputs. The outputs themselves are the ones responsible to put the messages in the right place. You can associate a LogOutput with a logger for a specific set of LogLevels. You have several types of outputs.
To output to a terminal use a TerminalOutput
. The TerminalOutput
is a singleton and already comes with thread safety.
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<LogOutput> output = TerminalOutput::build();
To output to a file use a FileOutput
. It is your responsability to make sure that at any given moment there is only one FileOutput
for each file. If you create two or more, the results are undefined.
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<LogOutput> output = FileOutput::build("file_output.txt");
If you need to output to this file from several threads, decorate it with a ThreadSafeOutput
. Do this whether your loggers are thread safe or not.
#include <Logger.hpp> using namespace mermaid::support::logging; ... CountedPtr<LogOutput> output2 = ThreadSafeOutput::build(output);
You can use the ThreadSafeOutput
for anything that inherits from LogOutput
. These scenarios are possible:
FastLogger
and don't decorate your outputs with the ThreadSafeOutput
.ThreadSafeLogger
and decorate all the outputs with a ThreadSafeOutput
.FastLogger
for the loggers but you need to decorate the output with ThreadSafeOutput
.The DataFeedOutput
is not yet implemented.
Now you need to associate the logger with the output. You usually do this for all log levels:
logger->enableAllLogLevels(output);
You can also do this only for error or reporting levels:
logger->enableErrorLogLevels(output); logger->enableReportingLogLevels(output);
Alternatively, you can enable it just for some specific level:
logger->enableLogLevel(LOG_ERROR, output);
For the inverse operation, you also have several options. You can disable all log levels. This is the only way to explicitly halt the logger.
logger->disableAllLogLevels();
You can also completely disable a specific output, all outputs for a level or a specific output just for a specifil level.
logger->disableAllLogLevels(output); logger->disableAllLogLevel(LOG_ERROR); logger->disableAllLogLevel(LOG_ERROR, output);
The Logger Framework is divided in three parts:
Logger
: The abstract base class.FastLogger
: Fast but thread unsafe implementation of the logger.ThreadSafeLogger
: Thread safe implementation of the logger.LogOutput
: The abstract base class.TerminalOutput
: This is always a thread safe singleton that outputs to the terminal.FileOutput
: This outputs to a file. It is your responsability to have only one of these at any moment to a given file.DataFeedOutput
: This is not yet implemented.ThreadSafeOutput
: This is just a decorator to any other LogOutput that adds thread safety to it.LogLevel
: This is an enum containing all the log levels.LogMessage
: This is how the logger comunicates with the output, used only internally.LogScope
: This is a helper class to automatically add an END level message at the end of the scope.LoggerMacros
: This is just an header file with preprocessor macros to help using the logger.