3.7. Logging¶
In order to efficiently debug and diagnose the Plug & Trust Middleware and its
supported use-cases and examples, it supports logging. The logging Framework
is written in such a way that embedded platforms are kept in mind and at
priority. The choice of logging is done at compile time and not at run time
like other high-level languages. Logging library mwlog
is compiled and
linked to all projects.
3.7.1. Logging level¶
The logging is divided into following levels:
- Error
Some kind of unrecoverable or unexpected error has happened and the behaviour from this point on is most likely to be out of specifications/expectations. The suffix for this in Logging APIs is E.
- Warn
Whatever happened is unexpected but not fatal, the severity of the warning requires the judgement of the user. The suffix for this in Logging APIs is W.
- Info
This is information for the user. The suffix for this in Logging APIs is I.
- Debug
These are verbose low level diagnostic debug messages and not to be used/enabled in normal circumstances. The suffix for this in Logging APIs is D.
3.7.2. Adding log messages into the source code¶
Add one of Logging Header Files to the
C
source code.Warning
Only for
C
source code. Never add the logging files to header files, only add them toC
source code.Call applicable Logging APIs at respective Logging level
Re-compile and re-run the software.
3.7.3. Logging APIs¶
The following are the loggings APIs to be called from the source code.
- LOG_I(…)
Log any value. C language format specifiers and values can be used if needed.
- LOG_X8_I(VALUE)
Log a HEX number 8 bits wide
- LOG_U8_I(VALUE)
Log an unsigned decimal number 8 bits wide
- LOG_X16_I(VALUE)
Log a HEX number 16 bits wide
- LOG_U16_I(VALUE)
Log a unsigned decimal number 16 bits wide
- LOG_X32_I(VALUE)
Log a HEX number 32 bits wide
- LOG_U32_I(VALUE)
Log an unsigned number 32 bits wide
- LOG_AU8_I(ARRAY, LEN)
Log an array of 8bits of length LEN
- LOG_MAU8_I(MESSAGE, ARRAY, LEN)
Same as
LOG_AU8_I
, but use MESSAGE.
The logging APIs effectively use preprocessor directives like
#
and##
and therefore, if the variable names are verbose enough, API calls likeLOG_X16_I(statusOfDeleteKey)
are enough to log response with relevent information, and efficient for the developer to add a logging instruction.The suffix
_I
can be replaced with_E
,_W
or_D
based on Logging level. The convention of logging remains the same.Use HEX Values to log enums and other hexadecimal numbers. For items that are not treated as HEX (e.g. length), use the decimal logging APIs.
For example, the APIs can be called as below.
retStatus = DoAPDUTxRx_Case3( /* ..., */
rspbuf,
&rspbufLen);
LOG_X16_D(retStatus);
LOG_AU8_D(rspbuf, rspbufLen);
If needed, the same can be made more verbose as below.
LOG_D("Sending FOO Command");
retStatus = DoAPDUTxRx_Case3( /* ..., */
rspbuf,
&rspbufLen);
LOG_D("FOO retStatus=0x04X", rtStatus);
LOG_MAU8_D("FOO Command", rspbuf, rspbufLen);
3.7.3.1. Logging - Information¶
Code:
uint32_t xu32val=0x12341234u;
uint8_t xu8val=0x44;
LOG_I("Values are xu32val=0x%08X xu8val=0x%02X", xu32val, xu8val);
Output:
App:INFO :Values are xu32val=0x12341234 xu8val=0x44
3.7.3.2. Logging - Variable Names¶
Code:
uint32_t xu32val=0x12341234u;
uint8_t xu8val=0x44;
unsigned int some_int_value = 783;
unsigned char some_byte_value = 96;
LOG_I("Values are:");
LOG_X8_I(xu8val);
LOG_U8_I(some_byte_value);
LOG_X16_I(xu8val);
LOG_U16_I(some_byte_value);
LOG_X32_I(xu32val);
LOG_U32_I(some_int_value);
/* Logging that will be mis-intepreted */
LOG_X16_I(some_byte_value);
Output:
App:INFO :Values are:
App:INFO :xu8val=0x44
App:INFO :some_byte_value=96
App:INFO :xu8val=0x0044
App:INFO :some_byte_value=96
App:INFO :xu32val=0x12341234
App:INFO :some_int_value=783
App:INFO :some_byte_value=0x0060
3.7.3.3. Logging - Arrays¶
Code:
const uint8_t some_array[] = {
0x5A, 0x5B, 0x5C, 0x5D,
0x5E, 0x5F, 0x60, 0x61,
0x62, 0x63, 0x64, 0x65,
0x66, 0x67, 0x68, 0x69,
0x6A, 0x6B, 0x6C, 0x6D};
const uint8_t buffer[] = {
0x2A, 0x2B, 0x2C, 0x2D,
0x2E, 0x2F, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39,
0x3A, 0x3B, 0x3C, 0x3D,
0x3E, 0x3F, 0x40, 0x41,
0x42, 0x43, 0x44, 0x45};
LOG_AU8_I(some_array, ARRAY_SIZE(some_array));
LOG_MAU8_I("meaningful name", buffer, ARRAY_SIZE(buffer));
Output:
App:INFO :some_array (Len=20)
5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69
6A 6B 6C 6D
App:INFO :meaningful name (Len=28)
2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39
3A 3B 3C 3D 3E 3F 40 41 42 43 44 45
3.7.3.4. Logging - Levels¶
Code:
uint32_t xu32val=0x12341234u;
LOG_X32_D(xu32val);
LOG_X32_I(xu32val);
LOG_X32_W(xu32val);
LOG_X32_E(xu32val);
Output:
App:INFO :xu32val=0x12341234
App:WARN :xu32val=0x12341234
App:ERROR:xu32val=0x12341234
3.7.4. Logging Header Files¶
Some of the header files for logging are as under.
- nxLog_UseCases.h
High level use cases.
- nxLog_App.h
Applications and tools.
- nxLog_VCOM.h
Logging specifically for VCOM Layer.
- nxLog_sss.h
Logging specifically for SSS Layer.
- nxLog_hostLib.h
Logging specifically for Host Library Layer.
- nxLog_smCom.h
Communication and common layer.
They can be found at hostlib/hostLib/libCommon/log
. These files are machine generated and hence is is not recommended to hand edit them.
3.7.5. Changing logging level¶
To change the level of logging, the following approaches are valid and based on the need of the problem, they can and should be used.
3.7.5.1. Full source-code¶
hostlib/hostLib/libCommon/log/nxLog_DefaultConfig.h
can be modified
to change logging level. nxLog_DefaultConfig.h
is self documented.
/* See Plug & Trust Middleware Docuemntation --> stack --> Logging
for more information */
/*
* - 1 => Enable Debug level logging - for all.
* - 0 => Disable Debug level logging. This has to be
* enabled individually by other logging
* header/source files */
#define NX_LOG_ENABLE_DEFAULT_DEBUG 0
/* Same as NX_LOG_ENABLE_DEFAULT_DEBUG but for Info Level */
#define NX_LOG_ENABLE_DEFAULT_INFO 1
/* Same as NX_LOG_ENABLE_DEFAULT_DEBUG but for Warn Level */
#define NX_LOG_ENABLE_DEFAULT_WARN 1
/* Same as NX_LOG_ENABLE_DEFAULT_DEBUG but for Error Level.
* Ideally, this shoudl alwasy be kept enabled */
#define NX_LOG_ENABLE_DEFAULT_ERROR 1
/* Release - retail build */
#ifdef FLOW_SILENT
#undef NX_LOG_ENABLE_DEFAULT_DEBUG
#undef NX_LOG_ENABLE_DEFAULT_INFO
#undef NX_LOG_ENABLE_DEFAULT_WARN
#undef NX_LOG_ENABLE_DEFAULT_ERROR
#define NX_LOG_ENABLE_DEFAULT_DEBUG 0
#define NX_LOG_ENABLE_DEFAULT_INFO 0
#define NX_LOG_ENABLE_DEFAULT_WARN 0
#define NX_LOG_ENABLE_DEFAULT_ERROR 0
#endif
3.7.5.2. Logging at component level¶
For example, changing logging level of App
,
hostlib/hostLib/libCommon/log/nxLog_App.h
can be updated. As shown
below, in nxLog_App.h
, the values of
NX_LOG_ENABLE_APP_INFO
, etc. can be updated.
/* If source file, or nxLog_Config.h has not set it, set these defines
*
* Do not #undef these values, rather set to 0/1. This way we can
* jump to definition and avoid plain-old-text-search to jump to
* undef. */
#ifndef NX_LOG_ENABLE_APP_DEBUG
# define NX_LOG_ENABLE_APP_DEBUG (NX_LOG_ENABLE_DEFAULT_DEBUG)
#endif
#ifndef NX_LOG_ENABLE_APP_INFO
# define NX_LOG_ENABLE_APP_INFO (NX_LOG_ENABLE_APP_DEBUG + NX_LOG_ENABLE_DEFAULT_INFO)
#endif
#ifndef NX_LOG_ENABLE_APP_WARN
# define NX_LOG_ENABLE_APP_WARN (NX_LOG_ENABLE_APP_INFO + NX_LOG_ENABLE_DEFAULT_WARN)
#endif
#ifndef NX_LOG_ENABLE_APP_ERROR
# define NX_LOG_ENABLE_APP_ERROR (NX_LOG_ENABLE_APP_WARN + NX_LOG_ENABLE_DEFAULT_ERROR)
#endif
3.7.5.3. Individual files¶
Rather than applying logging levels to full stack, if the need is to set the logging level in individual files, the individual source file can set required defined before including the respective log file.
e.g. The below lines will set log level to maximum:
#define NX_LOG_ENABLE_APP_DEBUG 1
#include <nxLog_App.h>
e.g. The below lines will set log level to just error:
#define NX_LOG_ENABLE_APP_DEBUG 0
#define NX_LOG_ENABLE_APP_INFO 0
#define NX_LOG_ENABLE_APP_WARN 0
#define NX_LOG_ENABLE_APP_ERROR 1
#include <nxLog_App.h>
nxLog_App.h
and _APP_
needs to be replaced with
respective names as per the list in Logging Header Files.