Home > Software engineering >  Inject string to const char* message in custom logger printf-style function
Inject string to const char* message in custom logger printf-style function

Time:09-30

I have a debugger class which implements a printf() c style method. It looks like this:

#define NO_DEBUG 0
#define NO_PREFIX 1
#define DEBUG_INFO 2
#define DEBUG_SUCCESS 3
#define DEBUG_WARN 4
#define DEBUG_ERROR 5
#define MAX_DEBUG_LEVEL 5


#define DEBUG_INFO_PREFIX "[INFO] "
#define DEBUG_SUCCESS_PREFIX "[SUCCESS] "
#define DEBUG_WARN_PREFIX "[WARN] "
#define DEBUG_ERROR_PREFIX "[ERROR] "

/*
*   Printing debug information to Serial in c printf style
*   If the level is higher then the global debug level or
*   the level is NO_DEBUG ( see debug.h ) then the message is not printed.
*/
void DebugSystem::print(byte level, const char *message, ...){
    if( level > debugLevel || level == NO_DEBUG ){ return; }
    char buffer[PRINT_BUFFER_SIZE];
    printPrefix(level);
    va_list  args;
    va_start (args, message);
        vsprintf (buffer, message, args);
        Serial.print(buffer);
    va_end (args);
}

It is used like this:

int count = 0;
debug.print(DEBUG_INFO,"Test message: %s,%d\n","testMSG",count);
debug.print(DEBUG_SUCCESS,"Test message: %s,%d\n","testMSG",count);
debug.print(DEBUG_WARN,"Test message: %s,%d\n","testMSG",count);
debug.print(DEBUG_ERROR,"Test message: %s,%d\n","testMSG",count);

It is working very well. Now i want to add a prefix before the message which i have implemented like this:

/*
*   Printing a prefix before the message based on it's level.
*   Levels:
*    - INFO prefix --> [INFO] 
*    - WARN prefix --> [WARN] 
*    - ERROR prefix --> [ERROR] 
*    - SUCCESS prefix --> [SUCCESS] 
*/ 
void DebugSystem::printPrefix(byte level){
    if( !levelPrefix || level == NO_PREFIX ){ return; }
    const char* prefix = level == DEBUG_ERROR ? DEBUG_ERROR_PREFIX
        : level == DEBUG_WARN    ? DEBUG_WARN_PREFIX
        : level == DEBUG_SUCCESS ? DEBUG_SUCCESS_PREFIX
        : DEBUG_INFO_PREFIX;
    Serial.print(prefix);
}

But i have a small problem. If the user want's to print \n at the beginning of the message, the output will be ill formatted.

Here is an example:

debug.print(DEBUG_INFO,"Test message: %s\n","TEST");
debug.print(DEBUG_INFO,"\nTest message: %s\n","TEST");

Output:

[INFO] Test message: TEST
[INFO]
      Test message: TEST

For this to work properly i have two solutions in mind Either check the first param ( i don't know how ) and if it is a new line '\n' character i remove it and print it before the prefix or i have to inject my prefix after the first \n character into the message.

I'm using Arduino framework to do all of this but i can't think of an elegant solution.

Expected output of this test message would be:

[INFO] Test message: TEST

[INFO] Test message: TEST

Ofc the problem is not just with the \n but any format character in the string. I need a robust solution, some regex or something to detect if there is a formatter character in the beginning of the arguments, remove and print it before the prefix.

CodePudding user response:

And there might be comments with several \n somewhere in the text.

You might repeat the prefix after every \n except for the trailing one at the end. And if there no ending \n add a \n.

Of course there often is a misconception that lines start with \n; one idea that should not be "repaired" - unnecessarily accepting that.

There might be more that one debug printf, meant to be printed as one text block. That you cannot determine:

if (i   % 10 == 0) printf("\n...
printf

CodePudding user response:

This not directly answer your question. But why reinvent the wheel when you could enable the ESP32 logging system from Arduino IDE Tools -> Core Debug Level?

enter image description here

And then you could use the ESP logging system as

log_i( "I'm using the ESP logging system");

I would suggest you take a look at the esp32-hal-log.h of the ESP32-Arduino Core and read more about esp-idf logging system.

  • Related