MARIE Logger

From MARIEWiki

Jump to: navigation, search

Contents

Description

Introduction

The MARIE Logger provides a simple way to journalize informations. You get the following benefits:

  • Insert easily log in your code.
  • Choose the destination of the informations (file or console).
  • Select the type of informations desire.
  • Put in form your information.

Why a Logger?

  • The goal of the logger is to journalize the informations in a structured and flexible manner :
    • All the pertinent information is journalize in real time to check the decision-making architecture
    • The structure of the log facilitate the analyse of the informations.

Design

Log

With the MARIE logger, you could insert some log in your code with the class marie::Logger::log methods (See also the inline function).

/** Log interface function with a message*/
void log(const std::string &tag, int level, const std::string &message);
     
/** Log interface function with a dataAbstract*/
void log(const std::string &tag, int level, const DataAbstract &data);

You give to each log many attributes which are detail below.

Message

For each log, a message is associate. It could contains :

  • An information in text with a std::string (ex: "Error in the initialization").
  • A data derived of marie::DataAbastract. It uses a marie::DataFactory to serialize data : MARIETAB, MARIEXML, MARRIEPRETTY.

Level

The log are class in different level which depend of the importance of the information. The different level available are : DEBUG, INFO, WARN, ERROR and FATAL. In log4cxx, this level is represented by an integer defined in the class marie::LogEntityIF :

     enum {
        LOGLEVEL_ALL = 00000,
        LOGLEVEL_DEBUG = 10000,
        LOGLEVEL_INFO = 20000,
        LOGLEVEL_WARN = 30000,
        LOGLEVEL_ERROR = 40000,
        LOGLEVEL_FATAL = 50000 
     };

Tag

  • It identify the location of the log in the code: it indicates where the message come from.
  • There is a hierarchy between this tag symbolize by a point : '.' (For exemple : AAComponent.Initialization.Input). Thus, you could regroup log which have same type of information.
  • With this tag, at the configuration, you could select the type of information you need.
    • For example if you select to journalise the tag : AAComponent.Initialization then, all the tag like AAComponent.Initialization.'something' will be journalize.

Example of a log

You could see an example of the log you could insert in your code :

marie::Logger::getInstance().log("AAComponent.Initialization", marie::LogEntityIF::LOGLEVEL_ERROR, "Error in the initialization of the component");

marie::MARIE_LOG_ERROR("AAComponent.Initialization", "Error in the initialization of the component"); //Same thing with the inline command

LogEntity

  • A LogEntity make an interface to create and configure a log4cxx logger. Each LogEntity uses only one log4cxx logger.
  • A LogEntity permit to specialize a log4cxx logger. Furthermore, it permit to configure a log4cxx logger with a configuration which could be extract from a XML file.
  • The pure virtual class marie::LogEntityIF describe the headed of the essential functions to use a log4cxx logger. All the LogEntity must derived of this class :
    • marie::LogEntityIF::getType : return the type of the LogEntity (ex ; LogEntityDefaultFile, LogEntityDefaulConsole...).
    • marie::LogEntityIF::log : create a log with its tag, level, and message or marie::DataAbstract.
    • marie::LogEntityIF::pushText : log a message with an indentation before.
    • marie::LogEntityIF::configure : configure log4cxx logger with the special configuration need by the LogEntity.
  • The most of LogEntity definied in MARIE is derived from marie::Logger::LogEntityIndentAbstract. This logEntity integrate the tag in the message like : tag -> message. It also make a correct indentation of the message notably when some pushText are made.
  • You could find all the LogEntity propose by marie here: LogEntity . You could easily create your own LogEntity based on the same model.
  • Each specific logEntity must configure many attributes for the log4cxx logger :

minLevel

Specify the minimum level of the log4cxx logger. All the log which have a level superior will be journalize

Appender

Specify the output destination of the log. In log4cxx, it exits many appenders to write log in different location : Telnet, socket, file, console... In MARIE logger, we only use log4cxx::WriteAppender which permit to write the log in a file (log4cxx::FileAppender) or at the console (log4cxx::ConsoleAppender).

Layout

Specify the output format of the log. In log4cxx, different formats are available: HTML, XML, Pattern. In MARIE, 2 layout are available :

  • pattern : Use the pattern layout of log4cxx. It permit to write in text all the information desired. You could select the different informations need (Date, message, level..) with special characters ( refer to log4cxx documentation : pattern).
  • mariePattern : is based on pattern layout. It have the same functionality as pattern but it separate the message and the tag which has been fuse in marie::Logger::LogEntityIndentAbstract. A new conversion character is also integrate (%T):
- %T: With this character, you display only the tag.
- %m: With this character, you display only the message.

So, the mariePattern offers more flexibility. It's the one you must choice if you haven't any restriction.</li>

LogEntityFactory

  • It is defined by the singleton class marie::LogEntityFactory. Invoking the class static marie::LogEntityFactory::getInstance method retrieves it. It produces LogEntityIF.
  • The class marie::LogEntityFactory::loadLogEntities method permit to load all the LogEntity know. It look for the library which begin by "libmarielogentity_" and save it in the memory.
  • A map is create which for each Type of LogEntity indicate the location of the function to create the specific LogEntity.

Logger

  • It's the main class of the logger. Only one MARIE Logger exist in a process. It is defined by the singleton class marie::Logger. Invoking the class static marie::Logger::getInstance method retrieves it.
  • The main role of the the class marie::Logger is to manage the LogEntity. For each tag, a LogEntity is associate. It's the operator, in the configuration, who make this association between the tag and the specific Log Entity (see usage). If no log entity is associate to a tag, the logger will associate the one of its parent or its ancestor if they have one. Otherwise it use a logEntity by default(see default).
  • The class marie::Logger::VisitorLogger permit to read the configuration give to the logger and validate it.
  • the class marie::Logger::configure method is in charge to read the configuration give and make to each tag the logEntity associate. It create a multimap (std::multimap<std::string, std::string>) : marie::Logger::m_tagToLogEntityMap for this association.
    • In the MARIE component, the configuration of the logger is made automatically by the class marie::ComponentMain::initializeLogger method.
  • the class marie::Logger::log method is in charge to log the message with the logEntity associate to the tag. It use the map create by the class marie::logEntityFactory to create the specific logEntity

inline functions

In the file MARIE.h, you could find many inline function to facilitate the usage of the logger. You could used the MARIE logger only with this function. The configuration is made with the configuration file (see below). Then, in your code, you could make some log with all this command :

//Configure the logger
inline bool MARIE_LOG_CONFIGURE(Configuration& config, bool verbose=false)

//Log your message
inline void MARIE_LOG_LEVEL(const std::string &tag, const std::string &message)
inline void MARIE_LOG_LEVEL(const std::string &tag, const DataAbstract &data)

//Make 4 spaces before the message. If doing many time the spaces are adding
inline void MARIE_LOG_LEVEL_TRY(const std::string &tag, const std::string &text)

//Make a return to the line of 4 spaces. A try must be done before.
inline void MARIE_LOG_LEVEL_RESULT(const std::string &tag, const std::string &text)
inline void MARIE_LOG_LEVEL_FAILED(const std::string &tag)
inline void MARIE_LOG_LEVEL_SUCCEEDED(const std::string &tag)

Where LEVEL correspond to the level of your log : DEBUG, INFO, WARN, ERROR and FATAL.

Usage

Configuration

In configuration file of your component, you could configure the logger at the same time.

  • In a first time, You must configure all the LogEntity need.
  • Then, you must associate to each tag used the LogEntity wanted.

Defining LogEntity

Here, you configure all the LogEntity need.

o C logger
   # KV forwardtoDefault
   # Q loggingEntities
  • forwardtoDefault : if true, all the log whose haven't have a log entity associate to its tag, will be journalize with the log entity by default (LogEntityDefaultFile). You could modified the default configuration by create a log entity with the name : default
  • loggingEntities : regroups all the logEntity desired.

Mapping semantic tag with LogEntity

Here, you must associate to each tag used a logEntity defined before.

o C logger
   ! Q mapping
      * T tag
         # KV tagName
         # KV logEntityName
  • mapping: regroups all the tag desired
    • tagName: specify the name of the tag
    • logEntityName: specify the name of the logEntity used. For a same logEntity, you could use many tags.

Example

  <logger elem="conf">
     <forwardToDefault elem="kv">false</forwardToDefault> 
     <loggingEntities elem="q">
        <logEntity elem="type">
           <name elem="kv">InitialisationInfo</name>
           <type elem="kv">LogEntityDefaultFile</type>
           <protocolID elem="kv">MARIEPRETTY</protocolID>
           <minLevel elem="kv">info</minLevel>
           <filename elem="kv">./log/InitialisationInfo.txt</filename>
           <conversionPattern elem="kv">[%20T] [%T] [%m] [%m]%n</conversionPattern>
           <createDirectory elem="kv">true</createDirectory>
           <preserveExistingFile elem="kv">false</preserveExistingFile>
        </logEntity>
     </loggingEntities>
     <mapping elem="q">     
        <tag elem="type">     
           <tagName elem="kv">AAComponent.Initialisation</tagName>
           <logEntityName elem="kv">InitialisationInfo</logEntityName>
        </tag>
     </mapping>      
  </logger>

In this exemple, a file "info.txt" will be create in the repertory "./log/". All the log with a minimum level "info" and with their tag begin by 'AAComponent.Initialisation' will be journalize.

Default configuration

  • If no LogEntity is associated to a tag, then the logger will use a marie::LogEntityDefaultFile with this configuration:
    • The minimum level is : INFO
    • The logEntity name : Default
    • The filename : "./log/MARIE_LOG.txt"
    • createDirectory : true
    • preserveExistingFile : false
  • For the MARIE component, the filename is the name of the application or by default the name of its executable.
  • Before the configuration of the MARIE logger, it is possible to change the value by default of minLevel and filename with this inline funtions of MARIE.h:
inline void MARIE_LOG_SET_DEFAULT_FILENAME(std::string filename)
inline void MARIE_LOG_SET_DEFAULT_LEVEL(std::string level)
  • You could change also this comportment by default in your configuration file with a logEntity called "default". Example to send the log at the console by default :
<logEntity elem="type">
   <name elem="kv">Default</name>
   <type elem="kv">LogEntityDefaultConsole</type>
   <minLevel elem="kv">info</minLevel>
</logEntity>
  • Finally, to fix your comportment by default of the logger in MARIE, you could change this line in the class marie::Logger :
const std::string Logger::DEFAULT_NAME = "Default";
const std::string Logger::DEFAULT_TYPE = "LogEntityDefaultFile";
const std::string Logger::DEFAULT_MINLEVEL = "info";  
const std::string Logger::DEFAULT_FILENAME = "./log/MARIE_LOG.txt";

Personal tools