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.
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)