Summary: uLog is a tool that, once integrated into your embedded project, can immediately print out information such as “Where did I go?” and “Where did it go wrong?” It is compact, low overhead, and user-friendly.
What is uLog?
uLog is a logging library specifically designed for resource-constrained MCUs (Microcontrollers), consisting of only 1 header file + 1 source file, implemented entirely in C, with minimal reliance on external libraries. It brings the well-known Log4c/Log4j concept of “level + output” to the embedded world, stripping away heavyweight features while retaining the core CRITICAL, ERROR, WARNING, INFO, DEBUG, and TRACE log levels.
Tip: If
<span>ULOG_ENABLED</span>is not defined at compile time, the entire logging code will not be included, resulting in zero cost.
What Problems Does It Solve?
| Common Issues | Traditional Approach | uLog’s Solution |
| Large log size | Writing your own <span>printf</span> or using a complete logging framework, resulting in code size of several KB or even MB |
Only requires about 2 KB (depending on compile options), extremely lightweight |
| Log level control is difficult | Manual <span>#ifdef</span> and macro definitions, significant changes required |
Unified level thresholds, dynamically switchable at runtime |
| Multiple output targets | Only a single path (e.g., UART), writing to files/memory requires a separate implementation | Supports any number of subscribers (console, file, circular buffer, etc.), each with independent thresholds |
| Log overhead even when disabled | Commenting out <span>printf</span>, the compiler still generates code |
<span>ULOG_ENABLED</span> undefined means log macros expand to empty statements, consuming no code space |
| Debug information is hard to trace | Relying on manual <span>printf</span>, information is scattered |
uLog automatically includes timestamps and level tags, all in one line |
Installation & Getting Started
In a nutshell: Just include
<span>ulog.h</span>and<span>ulog.c</span>in your project, define<span>ULOG_ENABLED</span>, and let the macros do the rest.
- 1. Download the source code
git clone https://github.com/rdpoor/ulog.git - 2. Copy the files to your project
- •
<span>ulog.h</span>→ include/ - •
<span>ulog.c</span>→ src/
#define ULOG_ENABLED // Place at the top of any source file, or add -DULOG_ENABLED in compile options
void my_uart_logger(ulog_level_t level, const char *msg) {
// Assume you have a uart_write function
char buf[128];
snprintf(buf, sizeof(buf), "%s [%s]: %s\r\n",
get_timestamp(), ulog_level_name(level), msg);
uart_write(buf, strlen(buf));
}
<span>main()</span>
int main(void) {
ULOG_INIT(); // Necessary initialization
ULOG_SUBSCRIBE(my_uart_logger, ULOG_WARNING); // Only print WARNING and above
int temp = 27;
ULOG_INFO("Current temperature %d℃", temp); // Will not print (INFO < WARNING)
ULOG_ERROR("Temperature anomaly: %d℃", temp); // Will print
// Dynamically lower the threshold to allow INFO to be printed
ULOG_SUBSCRIBE(my_uart_logger, ULOG_INFO);
ULOG_INFO("Reporting temperature again %d℃", temp);
return 0;
}
gcc -o demo main.c ulog.c -DULOG_ENABLED
Tip: If you want to write logs to a circular buffer, just implement a
<span>my_buf_logger</span>, pass the pointer in, and read it when needed.
Pros and Cons Overview
| Pros | Description |
| Extremely lightweight | Only takes a few KB, almost no impact on MCU resources |
| Flexible subscription | Any number of output targets, each with independent thresholds |
| Runtime adjustable | Dynamic enabling/disabling through <span>ULOG_SUBSCRIBE</span>/<span>ULOG_UNSUBSCRIBE</span> |
| No intrusion | No code generated when not enabled |
| Pure C implementation | Compatible with all mainstream compilers, easy to port |
| Cons | Description |
| Relatively simple functionality | Does not have advanced features like configuration files or rolling files as in Log4j |
| No built-in timestamp | Must implement <span>get_timestamp()</span><span>, which may be a hurdle for beginners</span> |
| Single-threaded safety | Does not provide locks by default; must implement locking in multi-threaded/RTOS environments |
In Summary
uLog is like a “sticky note” in the embedded world, transferring your habit of logging on a PC to resource-constrained MCUs. Its lightweight + flexible + no intrusion features allow you to debug without having to sift through source code, add <span>printf</span><span>, or reflash—just write a few lines of macros and a custom output function, and log information will appear immediately.</span>
If you are struggling with “How can I print debug information from a microcontroller?” or want to unify log levels in RTOS projects, consider integrating uLog for a time-saving, efficient, and clean code solution.
In a nutshell: Treat uLog as your embedded project’s “personal notebook” to jot down every “What did I just do?” moment.
Project Address: https://github.com/rdpoor/ulog