A logging library for ESP32 that saves logs to LittleFS and provides console output with detailed formatting. Features non-blocking queue-based logging, configurable log levels, and callback support.
- Non-blocking queue-based logging system
- File logging to LittleFS with automatic rotation
- Console output with timestamps and core ID
- Configurable log levels for console and file
- Log counters and queue monitoring
- Callback support for custom log handling
- Conditional compilation flags for production builds
Add to your platformio.ini file:
lib_deps = jijio/AdvancedLoggerSearch for "AdvancedLogger" in the Library Manager.
Download the latest release from the releases page.
Tested on: ESP32S3, ESP-WROVER
#include <AdvancedLogger.h>
void setup() {
Serial.begin(115200);
AdvancedLogger::begin();
LOG_INFO("System started");
LOG_ERROR("Error occurred: %d", 42);
}
void loop() {
LOG_DEBUG("Loop iteration: %lu", millis());
delay(5000);
}Output format:
[2024-03-23T09:44:10.123Z] [1 450 ms] [INFO ] [Core 1] [main.cpp:setup] System started
[2024-03-23T09:44:10.456Z] [1 783 ms] [ERROR ] [Core 1] [main.cpp:setup] Error occurred: 42
Set different log levels for console output and file logging:
AdvancedLogger::setPrintLevel(LogLevel::DEBUG); // Console output
AdvancedLogger::setSaveLevel(LogLevel::WARNING); // File loggingAvailable levels: VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL
Customize the logging queue with global build flags. They are read when the library itself is compiled, so a #define in the sketch is not enough (in the Arduino IDE, put the -D flags in a build_opt.h file next to the sketch).
In platformio.ini:
build_flags =
-DADVANCED_LOGGER_ALLOCABLE_HEAP_SIZE=20480 ; Internal RAM for the queue (default 12 KB = 20 entries)
-DADVANCED_LOGGER_PSRAM_QUEUE_SIZE=262144 ; Opt-in: put the queue in PSRAM with this size (not defined by default)
-DADVANCED_LOGGER_QUEUE_FULL_WAIT_MS=100 ; Longest a caller waits for a slot when the queue is full (default 100, 0 = never block)
-DADVANCED_LOGGER_TASK_STACK_SIZE=8192 ; Log task stack (default 8 KB, a log rotation on LittleFS peaks at about 5.6 KB)
-DADVANCED_LOGGER_TASK_PRIORITY=2 ; Log task priority
-DADVANCED_LOGGER_MAX_MESSAGE_LENGTH=512 ; Max message sizeBy default the queue lives in internal RAM. On a board with PSRAM, define ADVANCED_LOGGER_PSRAM_QUEUE_SIZE to move the queue storage there: internal RAM then only holds the small queue control structure, and the queue can be hundreds of KB. If PSRAM is not found or the allocation fails, the queue falls back to internal RAM with ADVANCED_LOGGER_ALLOCABLE_HEAP_SIZE.
When the queue is full, the caller waits up to ADVANCED_LOGGER_QUEUE_FULL_WAIT_MS for a slot, then the entry is dropped and counted (getDroppedCount()), and the log task writes a WARNING with the number of dropped entries. Sinks (console, file, callback) only ever run on the log task. A log rotation keeps the log task busy for a few seconds: size the queue for what your application logs in that time.
Configure when log files are flushed to ensure data persistence (global build flags, as above):
build_flags =
-DADVANCED_LOGGER_FLUSH_INTERVAL_MS=5000 ; Flush every 5 seconds (default)
-DADVANCED_LOGGER_FLUSH_LOG_LEVEL=LogLevel::ERROR ; Log level that triggers immediate flush (default)The library automatically flushes files periodically and on the specified log level to prevent data loss during power cycles or crashes.
Register a function to handle log entries:
void logHandler(const LogEntry& entry) {
// Send to server, display on screen, etc.
Serial.printf("Callback: %s\n", entry.message);
}
void setup() {
AdvancedLogger::setCallback(logHandler);
AdvancedLogger::setCallbackLevel(LogLevel::INFO); // Optional, default VERBOSE (everything)
AdvancedLogger::begin();
}The callback runs on the log task, so keep it short and do not log from it. Entries below the callback level that are also below the print and save levels are discarded before they take a queue slot.
Check system status:
unsigned long available = AdvancedLogger::getQueueSpacesAvailable();
unsigned long waiting = AdvancedLogger::getQueueMessagesWaiting();
unsigned long dropped = AdvancedLogger::getDroppedCount();
LOG_INFO("Queue: %lu available, %lu waiting, %lu dropped", available, waiting, dropped);// Set max lines before auto-rotation
AdvancedLogger::setMaxLogLines(5000);
// Get current line count
unsigned long lines = AdvancedLogger::getLogLines();
// Clear log (keep 20% of recent entries)
AdvancedLogger::clearLogKeepLatestXPercent(20);
// Dump to Serial
AdvancedLogger::dump(Serial);Disable specific log levels to reduce binary size:
#define ADVANCED_LOGGER_DISABLE_VERBOSE
#define ADVANCED_LOGGER_DISABLE_DEBUG
#define ADVANCED_LOGGER_DISABLE_CONSOLE_LOGGING // Disable all console output
#define ADVANCED_LOGGER_DISABLE_FILE_LOGGING // Disable all file logging
#include "AdvancedLogger.h"LOG_VERBOSE(format, ...)- Most detailed loggingLOG_DEBUG(format, ...)- Debug informationLOG_INFO(format, ...)- General informationLOG_WARNING(format, ...)- Warning messagesLOG_ERROR(format, ...)- Error conditionsLOG_FATAL(format, ...)- Fatal errors
AdvancedLogger::begin(path)- Initialize loggerAdvancedLogger::end()- Save what is still queued, stop the log task and clean up resourcesAdvancedLogger::setPrintLevel(level)- Set console log levelAdvancedLogger::setSaveLevel(level)- Set file log levelAdvancedLogger::setCallback(callback)- Register log handlerAdvancedLogger::setCallbackLevel(level)/getCallbackLevel()- Lowest level the callback receives (defaultVERBOSE)
getVerboseCount(),getDebugCount(),getInfoCount()getWarningCount(),getErrorCount(),getFatalCount()getTotalLogCount(),resetLogCounters()
setMaxLogLines(count)- Set rotation thresholdgetLogLines()- Get current line countclearLog()- Delete all logsclearLogKeepLatestXPercent(percent)- Rotate logsdump(stream)- Output logs to stream
See the examples folder for complete usage examples.
Fork the repository, create a feature branch, and submit a pull request. All contributions are welcome.
This project is licensed under the MIT License - see the LICENSE file for details.