-
Lightweight: The firmware transmits only Log IDs and raw data, offloading all parsing and formatting to the host side.
-
Seamless Binary Integration: Decouples ID assignment from compilation. Pre-compiled libraries (
.a) can be integrated without any pre-negotiated ID ranges. -
Log Groups: Different software components can have independent log levels.
-
Log Levels: Multiple log levels enable efficient noise filtering, with optional support for runtime adjustment.
-
A subset of this project is available at Trlog for firmware development, avoiding unneeded host-side code and docs.
Embedded systems demand logging with minimal resource overhead.
Tokenized logging is a well-established approach to meet this need, notably adopted by projects like Trice (C), pw_tokenizer (C++), and defmt (Rust).
In the C ecosystem, Trice is an excellent solution with a rich feature set.
However, it introduces some friction in team collaboration:
-
ID Conflicts: Automatically generated IDs can easily conflict during parallel development. Resolving these conflicts produces large, meaningless diffs in the version control system, adding noise to code reviews. While Git hooks can mitigate this by ensuring only uninstrumented source code is committed, the setup is cumbersome and error-prone.
-
Integration Overhead: When integrating binary libraries from different teams, ID ranges must be carefully pre-negotiated to avoid collisions.
TreeLog addresses the above collaboration pain points through a linker-based ID generation scheme:
-
Linker-Based ID Generation: Log metadata is stored in dedicated linker sections, with pointers to each entry collected in a separate section. The Log ID is simply the address offset of each pointer within that section. Since the linker guarantees every address is unique, ID collisions are avoided — even across parallel teams or pre-compiled binaries. These sections are stripped out when producing the firmware, which ensures zero runtime FLASH overhead.
-
Host-Side Stream Decoding: The firmware transmits only compact Log IDs and raw data. A host tool parses the stream by matching IDs against the ELF metadata to decode the logs. This metadata can also be exported to JSON to enable standalone log decoding without the original ELF.
Heavily based on components of Trice, the project was originally named trlog (inheriting the tr prefix), and later respelled as TreeLog for better pronunciation.
In a fitting twist of wordplay, the name also mirrors the very nature of logging — after all, logs come from trees.
Its core contribution lies in the automated ID generation scheme, complemented by features like Log Groups and Runtime-adjustable Log Level.
While initially conceived as a fully compatible fork of Trice, the project first introduced the linker-based ID scheme as an alternative, and later dropped the original pre-compile instrumentation approach to make the code lean and focused.
defmt |
pw_tokenizer |
Trice |
TreeLog |
|
Language |
Rust |
C++ |
C |
C |
Token Generation |
linker-based |
hash algorithm |
pre-compile instrumentation |
linker-based |
Token Collision |
Never |
Occasional |
Not parallel-development friendly |
Never |
Log Group |
Y |
Y |
N |
Y |
Runtime-adjustable Log Level |
N |
Y (custom code) |
N |
Y |
.
├── firmware/ # C library and examples
├── host/ # Go host-side tools (CLI)
├── thirdparty/ # Upstream Trice submodule
└── docs/ # Documentation-
Developer Manual — technical details for those who want to understand the underlying implementation or contribute to this project.
-
User Manual — usage instructions for those who want to integrate this project into their own projects.
-
Roadmap — planned features.
-
C99 or later is required.
-
Currently, only GCC is supported. Support for additional compilers is not yet implemented.
-
This project is only tested on 32-bit little-endian architectures. Compatibility with other architectures has not been verified and is therefore not guaranteed.
This project is licensed under the MIT License — see the LICENSE file for details.