Skip to content

Instantly share code, notes, and snippets.

@sidwarkd
Created August 7, 2025 20:40
Show Gist options
  • Save sidwarkd/dc970a96ae7795eb22669e042859d618 to your computer and use it in GitHub Desktop.
Save sidwarkd/dc970a96ae7795eb22669e042859d618 to your computer and use it in GitHub Desktop.
Abstracted Logger PoC
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp32_serial_logger.h"
#define RED_COLOR_CODE 31
#define GREEN_COLOR_CODE 32
#define YELLOW_COLOR_CODE 33
#define MAGENTA_COLOR_CODE 35
#define CYAN_COLOR_CODE 36
static SemaphoreHandle_t xSemaphore = NULL;
char get_error_char(const LogLevel level)
{
switch(level)
{
case LogLevel::ERROR:
return 'E';
case LogLevel::WARN:
return 'W';
case LogLevel::INFO:
return 'I';
case LogLevel::DEBUG:
return 'D';
case LogLevel::VERBOSE:
return 'V';
default:
return 'X';
}
}
int get_console_color_code(const LogLevel level)
{
switch(level)
{
case LogLevel::ERROR:
return RED_COLOR_CODE;
case LogLevel::WARN:
return YELLOW_COLOR_CODE;
case LogLevel::INFO:
return GREEN_COLOR_CODE;
case LogLevel::DEBUG:
return CYAN_COLOR_CODE;
case LogLevel::VERBOSE:
return MAGENTA_COLOR_CODE;
default:
return GREEN_COLOR_CODE;
}
}
int map_log_level(const LogLevel level)
{
switch(level)
{
case LogLevel::NONE:
return ESP_LOG_NONE;
case LogLevel::ERROR:
return ESP_LOG_ERROR;
case LogLevel::WARN:
return ESP_LOG_WARN;
case LogLevel::INFO:
return ESP_LOG_INFO;
case LogLevel::DEBUG:
return ESP_LOG_DEBUG;
case LogLevel::VERBOSE:
return ESP_LOG_VERBOSE;
default:
return ESP_LOG_INFO;
}
}
void ESP32SerialLogger::log_message(const char *tag, LogLevel level, const char *fmt, va_list args)
{
if(xSemaphore == NULL)
{
xSemaphore = xSemaphoreCreateMutex();
}
if(xSemaphore != NULL && xSemaphoreTake(xSemaphore, (TickType_t) 20))
{
esp_log_level_t esp_log_level = (esp_log_level_t)map_log_level(level);
esp_log_write(esp_log_level, tag, "\033[0;%dm%c (%ld) %s: ", get_console_color_code(level), get_error_char(level), esp_log_timestamp(), tag);
esp_log_writev(esp_log_level, tag, fmt, args);
esp_log_write(esp_log_level, tag, "\033[0m\n");
xSemaphoreGive(xSemaphore);
}
else{
printf("could not get semaphore\n");
}
}
#ifndef ESP_SERIAL_LOGGER_H
#define ESP_SERIAL_LOGGER_H
#include <logging.h>
#include <stdarg.h>
class ESP32SerialLogger : public ILogHandler
{
public:
void log_message(const char *tag, const LogLevel level, const char *fmt, va_list args) override;
};
#endif // ESP_SERIAL_LOGGER_H
#include "logging.h"
LogManager *LogManager::_log_manager = nullptr;
LogManager *LogManager::GetInstance()
{
if(_log_manager == nullptr)
{
_log_manager = new LogManager();
}
return _log_manager;
}
void LogManager::dispatch_message(const char *tag, const LogLevel level, const char *fmt, va_list args)
{
if (_log_level >= level)
{
for(auto& log_handler: _log_handlers)
{
log_handler->log_message(tag, level, fmt, args);
}
}
}
void LogManager::add_logger(ILogHandler *log_handler)
{
_log_handlers.push_back(log_handler);
}
void LogManager::remove_logger(ILogHandler *log_handler)
{
_log_handlers.remove(log_handler);
}
void LogManager::verbose(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dispatch_message(tag, LogLevel::VERBOSE, fmt, args);
va_end(args);
}
void LogManager::debug(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dispatch_message(tag, LogLevel::DEBUG, fmt, args);
va_end(args);
}
void LogManager::info(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dispatch_message(tag, LogLevel::INFO, fmt, args);
va_end(args);
}
void LogManager::warn(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dispatch_message(tag, LogLevel::WARN, fmt, args);
va_end(args);
}
void LogManager::error(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dispatch_message(tag, LogLevel::ERROR, fmt, args);
va_end(args);
}
void LogManager::set_log_level(LogLevel level)
{
_log_level = level;
}
LogLevel LogManager::get_log_level()
{
return _log_level;
}
#ifndef LOGGER_H
#define LOGGER_H
#include <stdarg.h>
#include <list>
enum class LogLevel
{
NONE = 0,
ERROR,
WARN,
INFO,
DEBUG,
VERBOSE
};
class ILogHandler
{
public:
virtual void log_message(const char *tag, const LogLevel level, const char *fmt, va_list args) = 0;
};
class LogManager
{
private:
void dispatch_message(const char *tag, const LogLevel level, const char *fmt, va_list args);
LogManager() : _log_level(LogLevel::ERROR){}
std::list<ILogHandler*> _log_handlers;
static LogManager *_log_manager;
LogLevel _log_level;
public:
LogManager(LogManager &other) = delete;
void operator=(const LogManager &) = delete;
static LogManager *GetInstance();
void add_logger(ILogHandler *log_handler);
void remove_logger(ILogHandler *log_handler);
void verbose(const char *tag, const char *fmt, ...);
void debug(const char *tag, const char *fmt, ...);
void info(const char *tag, const char *fmt, ...);
void warn(const char *tag, const char *fmt, ...);
void error(const char *tag, const char *fmt, ...);
void set_log_level(LogLevel level);
LogLevel get_log_level();
};
#endif //LOGGER_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment