Logging framwork with multiple modules (cellular interface and MQTT)

hello,
i experimented with the cellular interface demo (FreeRTOS-Plus/Demo/FreeRTOS_Cellular_Interface_Windows_Simulator) and i have a problem with the logging functionality.

i followed the template code for the logging functionality:

/**************************************************/
/******* DO NOT CHANGE the following order ********/
/**************************************************/

/* Include logging header files and define logging configurations in the
 * following order:
 * 1. Include the header file "logging_levels.h".
 * 2. Define the logging configurations for your application. It is required
 * to define LIBRARY_LOG_NAME, LIBRARY_LOG_LEVEL and SdkLog macros.
 * 3. Include the header file "logging_stack.h".
 */

#include "logging_levels.h"

/* Logging configurations for the application. */


/* Set the application log name. */
#ifndef LIBRARY_LOG_NAME
    LIBRARY_LOG_NAME    "MyApplication"
#endif


/* Set the logging verbosity level. */
#ifndef LIBRARY\_LOG\_LEVEL
 LIBRARY\_LOG\_LEVEL LOG\_INFO
#endif

/* Define the metadata information to add in each log.
 * The example here sets the metadata to [:]. */
#if !defined( LOG_METADATA_FORMAT ) && !defined( LOG_METADATA_ARGS )
   #define LOG_METADATA_FORMAT "[%s:%d]"
   #define LOG_METADATA_ARGS __FILE__, __LINE__
#endif


/* Define the platform-specific logging function to call from
 * enabled logging macros. */
#ifndef SdkLog
    #define SdkLog( message )   MyLogger message
#endif


/************ End of logging configuration ****************/

but because LIBRARY_LOG_NAME was already defined in the demo_config.h i see that LIBRARY_LOG_NAME that is defined in cellular_config.h is grayed out by my ide (vscode) and when logs print they all print the LIBRARY_LOG_NAME defined in demo_config.h (even thogh thay belong to other modules like cellularLib and MQTT.

the solution i found is to remove the #ifndef’s. this way the compiler will re-define LIBRARY_LOG_NAME every time a new module is included in the project (im not a seasoned C developer and dont really know all the inner-workings of the preprocessor ).

my question is what am i doing wrong? why the template code will not work ?
thank you!

Hi @roni1234321,
Welcome to FreeRTOS community!

C doesn’t allow MACRO re-definition. And the mechanism here is to define LIBRARY_LOG_NAME when it’s not pre-defined. If you remove the #ifndef and it already defines that MACRO, the re-define error message happens. And LIBRARY_LOG_NAME might be defined in several places. So that logging functionality can show different library name for different modules. Refer to Logging Functionality - FreeRTOS™ for more detail. The solution I’d suggest is to define the LIBRARY_LOG_NAME before including demo_config.h if you want to use different library name. Then the compiler ignores the define in the template by #ifndef.

BTW, there is a mistake in the template, we’ll update it soon. It should be:

/* Set the application log name. */
#ifndef LIBRARY_LOG_NAME
-    LIBRARY_LOG_NAME    "MyApplication"
+    #define LIBRARY_LOG_NAME    "MyApplication"
#endif

Thank you.

thank you! its working as intended now.
i have another question. it is required to write the SdkLog() function as thread safe in order to handle logs coming from different tasks at the “same time”, so i used a mutex to handle my uart logging. the problem is that the SdkLog function is used 3 times for each log:

#define LogAlways( message )    SdkLog( ( "[ALWAYS] [%s] "LOG_METADATA_FORMAT, LIBRARY_LOG_NAME, LOG_METADATA_ARGS ) ); SdkLog( message ); SdkLog( ( "\r\n" ) )

this causes the log to sometimes be “cut up” between the log header and the log message (and the “\r\n” also), as another task has took the semaphore between SdkLog() calls.

is there a solution for this? am i doing something wrong? thank you.

If your compiler supports variadic macros, you can use them. Here is an example:

#include <stdio.h>
#include <stdarg.h>

#define LIB_NAME "App"

void MyLogger( const char * pLevel,
               const char * pLibraryName,
               const char * pFile,
               int lineNumber,
               const char * pFormat,
               ... );

#define LogInfo_( format, ... )  \
    MyLogger( "INFO", LIB_NAME, __FILE__, __LINE__, format, ##__VA_ARGS__ )

#define LogDebug_( format, ... )  \
    MyLogger( "DEBUG", LIB_NAME, __FILE__, __LINE__, format, ##__VA_ARGS__ )

#define LogInfo( msg ) LogInfo_ msg
#define LogDebug( msg ) LogDebug_ msg

void MyLogger( const char * pLevel,
               const char * pLibraryName,
               const char * pFile,
               int lineNumber,
               const char * pFormat,
               ... )
{
    va_list args;

    /* Acquire mutex. */

    printf( "[%s] [%s] [%s:%d] ",
            pLevel,
            pLibraryName,
            pFile,
            lineNumber );

    va_start( args, pFormat );
    vprintf( pFormat, args );
    va_end( args );

    printf( "\r\n" );

    /* Release mutex. */
}

int main( void )
{
    unsigned long ts = 10;
    unsigned long msgs = 20;

    LogInfo( ( "Timestamp: %lu, Messages: %lu", ts, msgs ) );
    LogDebug( ( "Timestamp: %lu, Messages: %lu", ts, msgs ) );

    return 0;
}