How to properly change log level at runtime?

Hi,

I'd like to change the log level at runtime.
I implemented the code mentioned here:

However, every time I call that function, I believe a new handler is registered and then I get double, then triple, then quad, and so on, logs.

How can I kill previous handlers so when a new one is created, I do not get more than one log?

double logs example:

0000052496 [app] INFO: =====================================
0000052496 [app] INFO: =====================================
0000052497 [app] INFO: Execution Time: 8
0000052497 [app] INFO: Execution Time: 8
0000052524 [app] INFO: Start XYZ
0000052524 [app] INFO: Start ZYX
0000052525 [app] INFO: End XYZ
0000052525 [app] INFO: End XYZ

thank you

Make sure you are saving the logManager pointer globally, as you need to remove the last used log handler using removeHandler. If you have the wrong pointer, it won't be removed and you'll end up with repeated output.

1 Like

I just implemented something similar a few weeks ago that seems to work well, if it's useful for you.
I was using it so I could turn off logging at runtime so that I could leave Log() calls in when serial wasn't connected and I wouldn't take a performance hit.

// log handler instance
StreamLogHandler* logHandler;
// store the previous one in case we want to go back to it
StreamLogHandler* previousLogHandler;

// Set logging to level, with filters for other categories
void setLogging(LogLevel level, LogCategoryFilters filters) {
  auto logManager = LogManager::instance();
  pushLogHandler(logHandler);
  logManager->removeHandler(logHandler);
  logHandler = new StreamLogHandler(Serial, level, filters);
  logManager->addHandler(logHandler);
}

// Set logging to level with default filters
void setLogging(LogLevel level) {
  LogCategoryFilters filters = {
    { "app", level }, // Logging level for application messages
    // comm.coap logs are obnoxious and you don't want them (probably)
    { "comm.coap", (level==LOG_LEVEL_NONE?LOG_LEVEL_NONE:LOG_LEVEL_INFO) },
  };

  setLogging(level, filters);
}

// Save the current log handler
static void pushLogHandler(StreamLogHandler* handler) {
  previousLogHandler = handler;
}

// Return the previous log handler
static StreamLogHandler* popLogHandler(void) {
  return previousLogHandler;
}

// Restore the previously set log handler
void resetLoggingLevel(void) {
  auto logManager = LogManager::instance();
  logManager->removeHandler(logHandler);
  logHandler = popLogHandler();
  logManager->addHandler(logHandler);
}

In my application I can hop between logging levels by simply calling setLogging(LogLevel) or I could add more explicit filters with setLogging(LogLevel, LogCategoryFilters)

4 Likes

This looks great, thank you!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.