Logging

MARTe offers a logging mechanism that is both thread and interrupt safe.

Note

The number of logging messages is expected to be maximised in any MARTe component.

ErrorType

The framework offers the following ErrorTypes (i.e. severities, see ErrorType).

Type

Meaning

FatalError

An error which is not recoverable.

RecoverableError

The component can recover from this error.

InitialisationError

Error which occurred during the initialisation of the component.

OSError

Operating system error (typically used when developing interfaces to hardware).

ParametersError

Initialisation error due to misconfiguration of parameters.

IllegalOperation

Operation not possible in a given state.

ErrorSharing

Given resource cannot be shared.

ErrorAccessDenied

Access denied to a given resource.

Exception

Runtime exception triggered.

Timeout

Timeout waiting for a given resource.

CommunicationError

Communication error (sockets, files, …).

SyntaxError

Invalid syntax.

UnsupportedFeature

Request for a feature that is not available (possibly available on other states).

InternalSetupError

Error due

Debug

Debug messages.

Information

Information messages.

Warning

Warning messages.

Completed

ErrorType to be used when a given operation has completed.

NotCompleted

ErrorType to be used when a given operation has not yet completed. Usually a retry is expected.

Log macros

The AdvancedErrorManagement defines two main error logging macros.

The REPORT_ERROR_STATIC is to be called by classes that do not inherit from Object while the REPORT_ERROR should be called by classes that inherit from Object, since this will automatically add the object name, class name and object pointer to the log message.

Both macros expect a compulsory ErrorType, followed by a compulsory error/information string and a list of optional parameters that will be Printf in the String using the rules described in the Streams section.

...
REPORT_ERROR(ErrorManagement::Information, "Array set to %f", readVector);
...

Callback

The messages are processed by a user registered callback function.

This is set by calling the global function SetErrorProcessFunction with a pointer to user error handling function.

typedef void (*ErrorProcessFunctionType)(const ErrorInformation &errorInfo, const char8 * const errorDescription);

The errorDescription already contains the printfed message while the ErrorInformation provides a list of properties related to the conditions at the time of the logging (e.g. time, line number, …).

void ErrorProcessExampleFunction(const MARTe::ErrorManagement::ErrorInformation &errorInfo, const char * const errorDescription) {
   ...
   printf("[%s - %s:%d]: %s\n", errorCodeStr.Buffer(), errorInfo.fileName, errorInfo.header.lineNumber, errorDescription);
   printf(RST);
   ...

LoggerService

The framework also offers a data-driven LoggerService which decouples the log production from the log consumption using a decoupling queue.

The LoggerService allows to register one or more LoggerConsumerI components, which will consume the logging message accordingly. Note that the LoggerService will override any callback function previously set by the user.

The framework currently offers the following consumers: ConsoleLogger, UDPLogger and SysLogger (from the MARTe2-components).

Examples

The following is an example of a LoggerService instance which prints the logging messages in the console.

LoggerService example (LoggerServiceExample1)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
 * @file LoggerServiceExample1.cpp
 * @brief Source file for class LoggerServiceExample1
 * @date 04/04/2018
 * @author Andre' Neto
 *
 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
 * the Development of Fusion Energy ('Fusion for Energy').
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 *
 * @warning Unless required by applicable law or agreed to in writing, 
 * software distributed under the Licence is distributed on an "AS IS"
 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the Licence permissions and limitations under the Licence.

 * @details This source file contains the definition of all the methods for
 * the class LoggerServiceExample1 (public, protected, and private). Be aware that some
 * methods, such as those inline could be defined on the header file, instead.
 */

#define DLL_API

/*---------------------------------------------------------------------------*/
/*                         Standard header includes                          */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/*                         Project header includes                           */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "ClassRegistryDatabase.h"
#include "ConfigurationDatabase.h"
#include "ErrorLoggerExample.h"
#include "JsonParser.h"
#include "Matrix.h"
#include "Object.h"
#include "ObjectRegistryDatabase.h"
#include "Reference.h"
#include "ReferenceT.h"
#include "StandardParser.h"
#include "StreamString.h"
#include "Vector.h"

/*---------------------------------------------------------------------------*/
/*                           Static definitions                              */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/*                           Method definitions                              */
/*---------------------------------------------------------------------------*/
namespace MARTe2Tutorial {

/**
 * @brief A MARTe::Object that will print some logging information.
 */
class LoggerEx1: public MARTe::Object {
public:
    CLASS_REGISTER_DECLARATION()

LoggerEx1    () {
        using namespace MARTe;
        REPORT_ERROR_STATIC(ErrorManagement::Debug, "Constructing an instance of LoggerEx1");
    }

    virtual ~LoggerEx1 () {
        if (GetName() != NULL) {
            REPORT_ERROR_STATIC(MARTe::ErrorManagement::Debug, "Destroying an instance of LoggerEx1");
        }
    }

    virtual bool Initialise(MARTe::StructuredDataI &data) {
        using namespace MARTe;
        bool ok = Object::Initialise(data);

        REPORT_ERROR(MARTe::ErrorManagement::Information, "Initialised called");

        float32 a;
        if (ok) {
            ok = data.Read("a", a);
        }
        if (ok) {
            REPORT_ERROR(MARTe::ErrorManagement::Information, "a = %f", a);
        }
        else {
            REPORT_ERROR(MARTe::ErrorManagement::ParametersError, "Could not read the value of a");
        }

        return ok;
    }

};
CLASS_REGISTER(LoggerEx1, "")
}

int main(int argc, char **argv) {
    using namespace MARTe;
    using namespace MARTe2Tutorial;
    //This will be later overridden by the LoggerService
    SetErrorProcessFunction(&ErrorProcessExampleFunction);

    StreamString configurationCfg = ""
            "+LoggerService = {\n"
            "    Class = LoggerService\n"
            "    CPUs = 0x1\n"
            "    StackSize = 32768\n"
            "    NumberOfLogPages = 128\n"
            "    +ConsoleLogger1 = {\n"
            "        Class = ConsoleLogger\n"
            "        Format = \"EtOoFmC\"\n"
            "        PrintKeys = 1\n"
            "    }\n"
            "}"
            "+LEx1 = {\n"
            "    Class = LoggerEx1\n"
            "    a=5.3\n"
            "}\n"
            "+LEx2 = {\n"
            "   Class = LoggerEx1\n"
            "   a = 2"
            "}\n";

    REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s",
                        configurationCfg.Buffer());
    ConfigurationDatabase cdb;
    StreamString err;
    //Force the string to be seeked to the beginning.
    configurationCfg.Seek(0LLU);
    StandardParser parser(configurationCfg, cdb, &err);
    bool ok = parser.Parse();
    if (ok) {
        //After parsing the tree is pointing at the last leaf
        cdb.MoveToRoot();
        ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
    }
    else {
        StreamString errPrint;
        errPrint.Printf("Failed to parse %s", err.Buffer());
        REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
                            errPrint.Buffer());
    }

    if (ok) {
        REPORT_ERROR_STATIC(ErrorManagement::Information,
                            "Successfully loaded the configuration file");
    }

    //Purge all the Objects!
    MARTe::ObjectRegistryDatabase::Instance()->Purge();
    return 0;
}

Instructions on how to compile and execute the example can be found here.