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).
PlainLoggerService
In scenarios where the advantages of LoggerService cannot be used (e.g. BareMetal, single core/thread applications), the PlainLoggerService is offered. Conversely to its multi-thread based counterpart, the PlainLoggerService directly intercepts the callback function, handling all the logging function in the same thread execution unit. This approach gives a consistent logging facility also for scenarios where no threading is possible or available, like the BareMetal porting of MARTe2.
LogView utility
When using UDPLogger consumer, a viewer counterpart may be needed. A companion tool: MARTe2-LogView offers a convenient way to render the message flow onto a webpage or curses terminal.
MARTe2-LogView is a standalone Python3 toolset which can be found at <https://vcis-gitlab.f4e.europa.eu/common/marte2-logview> with a comprehensive quick-start guide and an in-depth manual.
Tip
A configuration file example is provided (RTApp-11-Logger.cfg) to allow a quick bootstrap with all-default parameters.
Examples
The following is an example of a LoggerService instance which prints the logging messages in the console.
1/**
2 * @file LoggerServiceExample1.cpp
3 * @brief Source file for class LoggerServiceExample1
4 * @date 04/04/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class LoggerServiceExample1 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ClassRegistryDatabase.h"
35#include "ConfigurationDatabase.h"
36#include "ErrorLoggerExample.h"
37#include "JsonParser.h"
38#include "Matrix.h"
39#include "Object.h"
40#include "ObjectRegistryDatabase.h"
41#include "Reference.h"
42#include "ReferenceT.h"
43#include "StandardParser.h"
44#include "StreamString.h"
45#include "Vector.h"
46
47/*---------------------------------------------------------------------------*/
48/* Static definitions */
49/*---------------------------------------------------------------------------*/
50
51/*---------------------------------------------------------------------------*/
52/* Method definitions */
53/*---------------------------------------------------------------------------*/
54namespace MARTe2Tutorial {
55
56/**
57 * @brief A MARTe::Object that will print some logging information.
58 */
59class LoggerEx1: public MARTe::Object {
60public:
61 CLASS_REGISTER_DECLARATION()
62
63LoggerEx1 () {
64 using namespace MARTe;
65 REPORT_ERROR_STATIC(ErrorManagement::Debug, "Constructing an instance of LoggerEx1");
66 }
67
68 virtual ~LoggerEx1 () {
69 if (GetName() != NULL) {
70 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Debug, "Destroying an instance of LoggerEx1");
71 }
72 }
73
74 virtual bool Initialise(MARTe::StructuredDataI &data) {
75 using namespace MARTe;
76 bool ok = Object::Initialise(data);
77
78 REPORT_ERROR(MARTe::ErrorManagement::Information, "Initialised called");
79
80 float32 a;
81 if (ok) {
82 ok = data.Read("a", a);
83 }
84 if (ok) {
85 REPORT_ERROR(MARTe::ErrorManagement::Information, "a = %f", a);
86 }
87 else {
88 REPORT_ERROR(MARTe::ErrorManagement::ParametersError, "Could not read the value of a");
89 }
90
91 return ok;
92 }
93
94};
95CLASS_REGISTER(LoggerEx1, "")
96}
97
98int main(int argc, char **argv) {
99 using namespace MARTe;
100 using namespace MARTe2Tutorial;
101 //This will be later overridden by the LoggerService
102 SetErrorProcessFunction(&ErrorProcessExampleFunction);
103
104 StreamString configurationCfg = ""
105 "+LoggerService = {\n"
106 " Class = LoggerService\n"
107 " CPUs = 0x1\n"
108 " StackSize = 32768\n"
109 " NumberOfLogPages = 128\n"
110 " +ConsoleLogger1 = {\n"
111 " Class = ConsoleLogger\n"
112 " Format = \"EtOoFmC\"\n"
113 " PrintKeys = 1\n"
114 " }\n"
115 "}"
116 "+LEx1 = {\n"
117 " Class = LoggerEx1\n"
118 " a=5.3\n"
119 "}\n"
120 "+LEx2 = {\n"
121 " Class = LoggerEx1\n"
122 " a = 2"
123 "}\n";
124
125 REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s",
126 configurationCfg.Buffer());
127 ConfigurationDatabase cdb;
128 StreamString err;
129 //Force the string to be seeked to the beginning.
130 configurationCfg.Seek(0LLU);
131 StandardParser parser(configurationCfg, cdb, &err);
132 bool ok = parser.Parse();
133 if (ok) {
134 //After parsing the tree is pointing at the last leaf
135 cdb.MoveToRoot();
136 ok = ObjectRegistryDatabase::Instance()->Initialise(cdb);
137 }
138 else {
139 StreamString errPrint;
140 errPrint.Printf("Failed to parse %s", err.Buffer());
141 REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
142 errPrint.Buffer());
143 }
144
145 if (ok) {
146 REPORT_ERROR_STATIC(ErrorManagement::Information,
147 "Successfully loaded the configuration file");
148 }
149
150 //Purge all the Objects!
151 MARTe::ObjectRegistryDatabase::Instance()->Purge();
152 return 0;
153}
Instructions on how to compile and execute the example can be found here.