Skip to content

Boot log - #2938

Open
sergeuz wants to merge 52 commits into
developfrom
feature/boot-log
Open

Boot log#2938
sergeuz wants to merge 52 commits into
developfrom
feature/boot-log

Conversation

@sergeuz

@sergeuz sergeuz commented Aug 4, 2026

Copy link
Copy Markdown
Member

Stores the messages logged by the system and the application in a file so that they can be retrieved later — in particular the messages logged while the device is booting or when it's in safe mode, which the application can't see otherwise.

API

  • spark_wiring_system.h — the application API:
    • System.enableLogFile() — enable logging to a file. The log starts capturing the messages immediately. Can be called again to reconfigure the log.
    • System.disableLogFile() — stop capturing the messages and delete the contents of the log.
    • System.printLogFile() — print the contents of the log via the app's logger.
    • System.readLogFile() — read the contents of the log into the application's own buffer.
    • System.clearLogFile() — delete the contents of the log. The log keeps capturing the messages.
  • system_config.h — the underlying system API, exported via dynalib.

Usage

SerialLogHandler logHandler(LOG_LEVEL_ALL);

void setup() {
    System.enableLogFile();
    Log.info("setup");
}

void loop() {
    static bool wasConnected = false;

    if (Serial.isConnected() != wasConnected) {
        if (Serial.isConnected()) {
            // Print the log when the serial connects
            System.printLogFile();
        }
        wasConnected = Serial.isConnected();
    }

    static system_tick_t lastLoopMessage = 0;

    if (millis() - lastLoopMessage >= 1000) {
        Log.info("loop");
        lastLoopMessage = millis();
    }
}

Implementation

  • Messages are captured in the logging service, independently of the log handlers registered by the application.
  • A logging call appends the message to a ring buffer in RAM, so no filesystem I/O happens in the logging call itself. The buffer is 2048 bytes by default and is allocated only while the log is enabled.
    • The system thread drains the buffer to the file about once a second. The buffer is also flushed before the device goes to sleep and before it is reset.
    • A message is stored either in its entirety or not at all. If the buffer overflows, the number of the dropped bytes is reported in the log itself.
  • The log is stored in two rotating files, /sys/log.1 and /sys/log.2, retaining the last max_size bytes of the log data (50000 by default). Up to twice that amount of storage is used in the filesystem.
  • The configuration is stored in /sys/log_config, encoded with Protobuf.

Known issues

  • The feature is disabled on Gen 3 platforms due to flash space constraints.

Other changes

  • fs::File::close() now releases the file handle even if the file cannot be synced. Previously the file was left open from the caller's perspective while LittleFS had already freed its cache buffer, causing a use-after-free on the next write and a double free when the object was destroyed.
  • Added fs::createTempFile() to create a uniquely named file under /tmp.
  • Removed the dead compatibility callback code from the logging service.

@sergeuz
sergeuz marked this pull request as ready for review August 7, 2026 11:08
@sergeuz
sergeuz marked this pull request as draft August 7, 2026 11:58
@sergeuz
sergeuz marked this pull request as ready for review August 7, 2026 14:15
@sergeuz
sergeuz requested a review from avtolstoy August 7, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant