OXRecorder::OXLog
Centralized, level-based logging facility
Overview
OXLog is the single output channel for the firmware. Instead of
calling Serial.print* directly, every part of the codebase
routes messages through OXLog. This keeps the output logic in
one place so behavior — log levels, timestamps, tags, and later alternate
sinks such as a file or network target — can evolve without touching call
sites.
- All methods are static; there is no instance to create.
- Messages below the configured level are dropped.
- Formatting is
printf-style; a trailing newline is added automatically. - Every line is prefixed with
[millis][LEVEL]for easy filtering.
Defined in include/OXLog.h, implemented in src/OXLog.cpp.
OXLog::Level enum class
Severity of a message, backed by uint8_t. Higher value means
more verbose. A message is emitted only when its level is less than or
equal to the configured level, so setting the level to
Debug also shows Error, Warn, and
Info.
| Value | Tag | Meaning |
|---|---|---|
None | — | Disables all output. |
Error | E | A failure that needs attention. |
Warn | W | Unexpected but recoverable condition. |
Info | I | Normal operational messages. Default level. |
Debug | D | Diagnostic detail for development. |
Verbose | V | High-volume tracing. |
API reference
static void begin(unsigned long baud = 115200, Level level = Level::Info) static
Initializes the underlying serial transport and sets the active log
level. Call once from setup() before emitting any messages;
calls before begin() are silently ignored.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baud | unsigned long | 115200 | Serial bit rate. Must match your monitor's baud setting. |
level | Level | Level::Info | Initial minimum severity emitted; messages below it are dropped. Change later with setLevel(). |
static void setLevel(Level level) static
Changes the minimum level emitted at runtime.
| Parameter | Type | Meaning |
|---|---|---|
level | Level | New minimum severity. Messages with a higher (more verbose) level than this are dropped. |
static Level getLevel() static
Returns the currently configured level.
static void error(const char *fmt, ...) static
Emits at Error level. printf-style arguments;
no trailing newline needed.
static void warn(const char *fmt, ...) static
Emits at Warn level.
static void info(const char *fmt, ...) static
Emits at Info level.
static void debug(const char *fmt, ...) static
Emits at Debug level.
static void verbose(const char *fmt, ...) static
Emits at Verbose level.
The logging methods are annotated with
__attribute__((format(printf, 1, 2))), so the compiler checks
your format string against its arguments just like a real
printf.
| Parameter | Type | Meaning |
|---|---|---|
fmt | const char * | printf-style format string (e.g. "battery %d%%"). No trailing \n — one is added automatically. |
... | variadic | Values substituted into the format specifiers, same rules as printf: %d int, %u unsigned, %s C-string, %lu unsigned long, %f double, %02x hex, etc. |
File-backed logs
OXLog can also persist diagnostics to external storage. The
device creates /log/yyyyMMdd.log, keeps the newest entries at
the top of the file, and caps the file at a configurable size
(200 KB by default). The implementation uses a small RAM
staging buffer and rewrites through a temp file, so the ESP32-S3 does not
need a 200 KB RAM allocation.
static bool beginFileLogging(OXFileManager &files, size_t maxBytes = 200 KB, uint32_t flushIntervalMs = 10000, const char *dir = "/log") static
Enables SD-backed logging. External storage must already be mounted. The current boot's staged log lines are flushed immediately.
static void poll() static
Cooperative flush pump. Call from loop(); it writes only
when the buffer is dirty and the interval has elapsed.
static bool flushFileLog() static
Forces an immediate flush. readLog calls this before reading.
static bool readLatestLog(...)
Reads a chunk from the latest yyyyMMdd.log. Use
offset and maxBytes to page through the log.
OXLog::begin();
if (files.beginExternal()) {
OXLog::beginFileLogging(files); // /log/yyyyMMdd.log, max 200 KB
}
void loop() {
OXLog::poll(); // periodic flush
}
Example
Try it
Paste the sketch below into src/main.cpp, then build and
watch the serial monitor:
pio run -e esp32-s3-super-mini -t upload && pio device monitor.
You should see the four messages from the sample output appear.
A minimal sketch that brings up the logger and emits messages at several levels:
#include <Arduino.h>
#include "OXLog.h"
using OXRecorder::OXLog;
void setup() {
// Bring up serial at 115200 and show Info and above.
OXLog::begin(115200, OXLog::Level::Info);
OXLog::info("Boot complete, firmware v%d.%d", 1, 0);
OXLog::warn("Battery at %d%%", 18);
OXLog::error("Sensor %s failed to init", "IMU");
// Dropped at the default Info level — no output.
OXLog::debug("raw adc = %d", 2048);
// Raise verbosity at runtime to see Debug messages.
OXLog::setLevel(OXLog::Level::Debug);
OXLog::debug("now visible: adc = %d", 2048);
}
void loop() {
static uint32_t counter = 0;
OXLog::info("Loop count: %lu", counter++);
delay(1000);
}
Sample output
[12][I] Boot complete, firmware v1.0
[12][W] Battery at 18%
[13][E] Sensor IMU failed to init
[13][D] now visible: adc = 2048
[1013][I] Loop count: 0
[2013][I] Loop count: 1
The number in the first bracket is millis() since boot; the
letter is the level tag.