ENDVR

EFL engineering guide

An embedded logging library in C: from message to file

Follow a record through timestamps, filtering and output callbacks. Then make the file output fail and see what the example reports.

A useful log tells you what happened, when it happened, and which part of the product was involved. A useful logging example lets you see how that record gets to its destination.

The EFL Logging Starter Kit brings together Log, Strings, Time and File from the Endeavor Firmware Library. Core, their shared dependency, is included. The example runs on a Windows host so you can examine the flow without setting up a board or an RTOS project first.

Start with a repeatable record

The example trims a device label, copies it into a bounded buffer, and parses a numeric device ID using Strings. A fixed clock callback supplies the same UTC time on every run. Log uses Time to format it.

The resulting first record is:

[20260929-12:00:00] [INFO] [boot] controller-17 ready; device_id=17

The clock is deliberately fixed, and the sensor readings that follow are simulated. That makes the expected result easy to compare with your own run. When you move to a device, replace the clock callback with your time source.

Choose what reaches the outputs

The global logging threshold is INFO. The example submits a DEBUG message and checks that the library reports it as filtered. It then submits two INFO records and one WARN record.

Two callbacks receive the three accepted records. One writes to the terminal. The other writes through the File module's host stdio backend. The file should contain exactly three records and no DEBUG message.

This arrangement does not require EFL Console. An output callback and an interactive command console are different pieces of an application.

Check the file output

EFL's sink callback returns void. A successful call to submit a log message does not confirm that a file was written successfully.

The starter example supplies its own checked file callback, DemoCheckedFileSink. It checks:

  • Whether the file opened.
  • Whether the requested bytes were written.
  • Whether flush and close succeeded.

It records failures in application-owned state and reports them through standard error rather than sending another message into the same failing sink.

Reproduce a file-open failure

Extract the kit, open a terminal in its folder, and pass a path whose parent directory does not exist. For example, if missing-directory is absent:

.\bin\efl-demo.exe .\missing-directory\demo.log

The terminal records still appear. File output reports failures, the successful file-record count stays at zero, and the example exits with code 2.

This exercises file-open failure. It does not simulate every storage failure, and a successful host flush is not proof that a device will retain data through a power interruption.

Run it, then make one change

  1. Extract the kit into a writable folder on Windows x64.
  2. Open Run-Demo.cmd and read demo.log beside the launcher.
  3. Open example/logging_demo.c and find the clock and output callbacks.
  4. Change the device label, rebuild with the included MinGW-w64 GCC build script, and compare the output.

The source build script and existing logging regression test are included. The compiler is not bundled. After the first edit, connect a real clock or substitute your output transport, keeping the failure reporting visible.

The recorded checks cover this Windows host configuration. A target port still needs its own checks for timing, concurrency, backend behavior and the ways its storage can fail.

These tools are part of the Endeavor Firmware Library. When your project needs a command console, cellular connectivity or Windows file transfer, explore the wider library.