Skip to content

Commit d8edc31

Browse files
authored
Merge pull request #569 from espressif/article/logging
Added logging article
2 parents 67ebe44 + d7e011e commit d8edc31

File tree

9 files changed

+386
-0
lines changed

9 files changed

+386
-0
lines changed
6.23 KB
Loading
5.79 KB
Loading
16.9 KB
Loading
13 KB
Loading
39.2 KB
Loading
12.9 KB
Loading
10.2 KB
Loading
7.94 KB
Loading
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
---
2+
title: "ESP-IDF tutorial series: Logging"
3+
date: "2025-09-26"
4+
showAuthor: false
5+
# Add a summary
6+
summary: "This article shows how ESP-IDF’s logging system uses tags and verbosity levels to produce structured, configurable output, helping you keep code clean and debug more effectively."
7+
# Create your author entry
8+
# - Create your page at `content/authors/<author-name>/_index.md`
9+
# - Add your personal data at `data/authors/<author-name>.json`
10+
# - Add your author name(s) below
11+
authors:
12+
- "francesco-bez" # same as in the file paths above
13+
# Add tags
14+
tags: ["ESP32C3", "ESP-IDF", "errors"]
15+
---
16+
17+
## Introduction
18+
19+
The most straightforward way to see what your C program is doing is to drop in a few `printf` statements. It’s simple, immediate, and every developer knows how to use it. But as soon as your application grows beyond a toy example, `printf` starts to show its limits: output becomes messy, important details get buried, and managing those statements turns into a chore. Using a logging library, on the other hand, gives you structured, configurable, and context-rich feedback without scattering prints all over your code.
20+
21+
It lets you control what gets recorded, where it goes, and how it looks, all while keeping your source clean. Additionally, logging can be easily disabled in production builds via a configuration option, so you don’t have to worry about performance or leaking sensitive information. In the sections that follow, we’ll refer to the logging library simply as “logging,” and we’ll explore why it is better than `printf` for debugging, as well as how adopting it can make your codebase easier to maintain and scale.
22+
23+
24+
## Logging library
25+
26+
The ESP-IDF provides its logging functionality through the `log` component, included via `esp_log.h`. You’ve probably already seen this logging in action, as it’s used extensively throughout the ESP-IDF libraries.
27+
28+
ESP-IDF offers two logging implementations: __Log V1__ and __Log V2__, selectable through `CONFIG_LOG_VERSION`. Log V1 is the simpler, default option optimized for early and DRAM logging but with higher flash usage and limited flexibility, while Log V2 reduces flash usage, adds powerful customization features, and centralizes formatting at the cost of slightly higher stack usage. In this article, we will focus on Log V1, while Log V2 will be covered in a future article.
29+
30+
31+
Let’s examine the output from the `hello_world` example. When you monitor your device while running `hello_world`, you’ll see something like:
32+
<!--
33+
```bash
34+
[...]
35+
I (223) spi_flash: flash io: dio
36+
W (226) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
37+
I (238) sleep_gpio: Configure to isolate all GPIO pins in sleep state
38+
I (245) sleep_gpio: Enable automatic switching of GPIO sleep configuration
39+
I (251) main_task: Started on CPU0
40+
I (251) main_task: Calling app_main()
41+
[...]
42+
``` -->
43+
44+
{{< figure
45+
default=true
46+
src="img/hello_world.webp"
47+
caption="Fig.1 - Hello World output"
48+
49+
>}}
50+
51+
52+
Lines starting with `I` are shown in green, while those starting with `W` appear in orange. These are examples of log messages: `I` denotes an informational message, and `W` denotes a warning. Although both are essentially printed messages with some extra formatting, they represent conceptually different types of messages. Their visibility can be controlled through a configuration parameter called *verbosity*.
53+
54+
### Logging core elements
55+
56+
To grasp how logging works in ESP-IDF, we will examine its three core elements:
57+
58+
* Tags
59+
* Logging macros
60+
* Verbosity levels
61+
62+
<!--
63+
In the ESP-IDF logging system, verbosity levels such as ERROR, WARNING, INFO, DEBUG, and VERBOSE let you control the amount and type of information your application produces. By adjusting the log level, you can focus on critical errors in production while enabling detailed debug information during development or troubleshooting. This selective filtering keeps logs readable, improves performance, and helps you quickly pinpoint issues without wading through irrelevant messages. -->
64+
65+
#### Tags
66+
67+
A tag is simply a string used to group related log messages, typically by file or component. Tags are passed to the logging macros, as demonstrated in the next section. A common convention is to define a `TAG` constant as a `static const char *` pointer. In ESP-IDF, tags are usually declared at the top of the file like this:
68+
69+
```c
70+
static const char *TAG = "TAG_NAME";
71+
```
72+
73+
{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}}
74+
The `static` keyword limits the symbol’s visibility to the current file, while `const` ensures the string is stored in read-only memory instead of consuming RAM.
75+
{{< /alert >}}
76+
77+
#### Logging macros
78+
79+
ESP-IDF offers a powerful logging system through the `ESP_LOGx` family of macros that are used for reporting errors, warnings, and other runtime information. These macros are task-safe, lightweight, and can be grouped per tag.
80+
81+
The available macros are:
82+
83+
* `ESP_LOGE` – Error
84+
* `ESP_LOGW` – Warning
85+
* `ESP_LOGI` – Info
86+
* `ESP_LOGD` – Debug
87+
* `ESP_LOGV` – Verbose
88+
89+
Here is a sample showing how to use one of these macros in your code:
90+
91+
```c
92+
ESP_LOGE(TAG, "Failed to initialize sensor: %s", esp_err_to_name(ret));
93+
```
94+
95+
Each logging macro takes two main arguments:
96+
97+
* __Tag__ - the label under which the log will be grouped.
98+
* __Message__ – a `printf`-style format string followed by variadic arguments.
99+
100+
#### Verbosity
101+
102+
The difference between the logging macros is not just visual, it’s also tied to the _verbosity level_.
103+
Verbosity levels determine which messages are actually printed to the serial console.
104+
105+
The reason why it’s possible to change the verbosity is that reducing it in ESP-IDF (e.g., via `CONFIG_LOG_DEFAULT_LEVEL`) provides several advantages:
106+
107+
* **Smaller binary size:** Fewer log strings and logging calls reduce the compiled code size.
108+
* **Lower CPU load:** With fewer logs generated, the CPU spends less time formatting and outputting messages, improving runtime performance.
109+
* **Reduced memory usage:** Less memory is needed for log strings and temporary buffers, which helps applications with tight memory limits.
110+
111+
These optimizations make logging more efficient without losing control over critical messages.
112+
113+
114+
The `esp_log` component supports the following levels, from lowest to highest:
115+
116+
* __No output__
117+
* __Error__
118+
* __Warning__
119+
* __Info__
120+
* __Debug__
121+
* __Verbose__
122+
123+
This order matters: for example, `ESP_LOGE` messages will appear even at the lowest verbosity setting that allows output, while `ESP_LOGV` messages are only shown when verbosity is set to the highest level.
124+
125+
You can change the default verbosity level in `menuconfig`:
126+
127+
* `> ESP-IDF: SDK Configuration Editor (menuconfig)`<br>
128+
&rarr; `Component Config Log Level` &rarr; `Default Log Verbosity`
129+
130+
131+
Fig.2 illustrates how different verbosity settings affect which log messages are shown. The default verbosity level is _info_.
132+
133+
{{< figure
134+
default=true
135+
src="img/logging_diagram.webp"
136+
height=500
137+
caption="Fig.2 - Logging diagram"
138+
>}}
139+
140+
### Filtering Logs
141+
142+
ESP-IDF gives you fine-grained control over log output, allowing you to filter messages by verbosity level and tag. You can do this both __at runtime in your application__ and __from the host using the IDF monitor__.
143+
144+
#### Filtering at Runtime
145+
146+
You can also adjust log verbosity directly within your application using the `esp_log_level_set()` function:
147+
148+
```c
149+
esp_log_level_set("TAG", ESP_LOG_WARN); // Only warnings and errors for "TAG"
150+
esp_log_level_set("TAG", ESP_LOG_NONE); // Disable all logs for "TAG"
151+
```
152+
153+
This makes it possible to dynamically change log levels for specific modules or components while your program is running.
154+
155+
156+
#### Filtering in the IDF Monitor
157+
158+
When using the IDF monitor, you can control which logs are displayed by filtering them by tag and verbosity level. This can be done with the `--print-filter` option or by setting the `ESP_IDF_MONITOR_PRINT_FILTER` environment variable. All logs are still transferred to the host over the serial port, but only those that match the filter are shown.
159+
160+
A filter is defined as a series of `<tag>:<log_level>` pairs, where `<log_level>` can be one of:
161+
162+
* `N` (None)
163+
* `E` (Error)
164+
* `W` (Warning)
165+
* `I` (Info)
166+
* `D` (Debug)
167+
* `V` (Verbose)
168+
* `*` (all)
169+
170+
For example you can write
171+
172+
```sh
173+
idf.py monitor --print-filter="tag1:W"
174+
```
175+
176+
Shows only warnings and errors for `tag1`.
177+
178+
```sh
179+
idf.py monitor --print-filter="tag1:I tag2:W"
180+
```
181+
182+
Shows `tag1` logs at Info level or less, and `tag2` logs at Warning level or less.
183+
184+
If no log level is specified, the default is __verbose__. You can also define global filters. For instance, `*:E` displays only errors across all tags.
185+
186+
{{< alert iconColor="#df8e1d" cardColor="#edcea3">}}
187+
Tag names must not include spaces, asterisks `*`, or colons `:`.
188+
More details: [ESP-IDF Monitor Output Filtering](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-monitor.html#output-filtering).
189+
{{< /alert >}}
190+
191+
192+
## Putting it all together
193+
194+
Let’s try out the logging system in practice.
195+
We’ll start from a bare-bones example available on [this GitHub repository](https://github.com/FBEZ-docs-and-templates/devrel-tutorials-code/tree/main/tutorial-basic-project).
196+
197+
The `main.c` file for this example looks like this:
198+
```c
199+
#include <stdio.h>
200+
#include "sdkconfig.h"
201+
202+
203+
void app_main(void)
204+
{
205+
printf("Hello tutorial!\n");
206+
}
207+
```
208+
209+
In this section we will
210+
1. Assign a tag to the logs (i.e. `TAG`)
211+
2. Log a message for each level
212+
3. Change verbosity level and check the output
213+
214+
### Assign a tag to the logs
215+
216+
When using a logging macro, the first argument is a _tag_ that groups related log messages.
217+
You can pass a string literal directly, but it’s usually better to define a constant and reuse it throughout the same component or file.
218+
219+
220+
In our example, we’ll use:
221+
222+
```c
223+
static const char *TAG = "APP_MAIN";
224+
```
225+
226+
### Log a message for each level
227+
228+
Before using the log macros, include the `esp_log.h` header:
229+
230+
```c
231+
#include "esp_log.h"
232+
```
233+
234+
Next, replace the `app_main` function with the following:
235+
236+
```c
237+
void app_main(void)
238+
{
239+
printf("\n\n\n*** STARTING LOGS ***\n\n");
240+
ESP_LOGE(TAG, "Log ERROR!");
241+
ESP_LOGW(TAG, "Log WARNING!");
242+
ESP_LOGI(TAG, "Log INFO!");
243+
ESP_LOGD(TAG, "Log DEBUG!");
244+
ESP_LOGV(TAG, "Log VERBOSE!");
245+
printf("\n\n\n*** ENDING LOGS ***\n\n\n");
246+
}
247+
```
248+
249+
{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}}
250+
The `printf` statements are used simply to separate the logs we created from the default ESP-IDF logs.
251+
{{< /alert >}}
252+
253+
Now, build, flash, and monitor the code:
254+
255+
* `> ESP-IDF: Build, Flash and Start a Monitor on Your Device`
256+
257+
The relevant output is shown in Fig. 3.
258+
259+
<!-- ![first output](img/first_output.webp) -->
260+
261+
{{< figure
262+
default=true
263+
src="img/first_output.webp"
264+
caption="Fig.3 - Logging output - Info level"
265+
266+
>}}
267+
268+
You can see that the error log appears in red, the warning log in yellow, and the info log in green.
269+
The debug and verbose logs are missing because the current verbosity level does not allow them to be displayed.
270+
271+
### Change verbosity level and check the output
272+
273+
Let’s inspect the current verbosity level in `menuconfig`:
274+
275+
* `> ESP-IDF: SDK Configuration Editor (menuconfig)`<br>
276+
&rarr; `Component Config` &rarr; `Log Level` &rarr; `Default Log Verbosity`
277+
278+
The dropdown menu (see Fig. 4) lists all available levels. By default, it is set to `info`.
279+
280+
{{< figure
281+
default=true
282+
src="img/menuconfig.webp"
283+
height=600
284+
caption="Fig.4 - Choosing verbosity level"
285+
286+
>}}
287+
288+
Now, let’s see what happens when we increase the verbosity:
289+
290+
* Change the dropdown value to `verbose`
291+
* Save the configuration
292+
* Build, flash, and start the monitor:<br>
293+
294+
* `> ESP-IDF: Build, Flash and Start a Monitor on Your Device`
295+
296+
As expected, all log levels are now displayed, as shown in Fig. 5.
297+
298+
{{< figure
299+
default=true
300+
src="img/second_output.webp"
301+
height=600
302+
caption="Fig.5 - Logging output - Verbose level"
303+
304+
>}}
305+
306+
Note that the `ESP_LOGD` and `ESP_LOGV` messages appear in white, similar to `printf`.
307+
308+
{{< alert icon="lightbulb" iconColor="#179299" cardColor="#9cccce">}}
309+
For production, logs are usually disabled. You can do this by selecting `No output` in the dropdown menu.
310+
{{< /alert >}}
311+
312+
### Change verbosity at runtime
313+
314+
You can also adjust the logging verbosity while your program is running.
315+
Update your `app_main` function as follows:
316+
317+
```c
318+
void app_main(void)
319+
{
320+
printf("\n\n\n*** STARTING LOGS ***\n\n");
321+
ESP_LOGE(TAG, "Log ERROR!");
322+
ESP_LOGW(TAG, "Log WARNING!");
323+
ESP_LOGI(TAG, "Log INFO!");
324+
ESP_LOGD(TAG, "Log DEBUG!");
325+
ESP_LOGV(TAG, "Log VERBOSE!");
326+
327+
esp_log_level_set("main", ESP_LOG_WARN);
328+
329+
ESP_LOGE(TAG, "Log ERROR after set level");
330+
ESP_LOGW(TAG, "Log WARNING set level");
331+
ESP_LOGI(TAG, "Log INFO set level");
332+
ESP_LOGD(TAG, "Log DEBUG!");
333+
ESP_LOGV(TAG, "Log VERBOSE!");
334+
printf("\n\n\n*** ENDING LOGS ***\n\n\n");
335+
}
336+
```
337+
338+
In this example, we first print all log levels, then change the verbosity level of the `main` component to `WARN`. After that, only warnings and errors will appear in the output.
339+
340+
* Build, flash, and monitor your device:
341+
342+
* `> ESP-IDF: Build, Flash and Start a Monitor on Your Device`
343+
344+
Your output should now look similar to Fig.5.
345+
346+
{{< figure
347+
default=true
348+
src="img/runtime_change.webp"
349+
height=500
350+
caption="Fig.5 - Runtime filtering"
351+
>}}
352+
353+
As you can see, the configuration log level is set to verbose, so in the first block all messages—including verbose—are printed. After calling `esp_log_level_set`, the log level for the _main_ component is reduced to warning, so only warnings and errors are displayed from that point on.
354+
355+
356+
### Filtering with esp-idf monitor
357+
358+
As a last step, let's use the `idf.py monitor` to filter only the logs with tag "main" and just the ones with verbosity level less than info.
359+
360+
* `> ESP-IDF: Open ESP-IDF Terminal`
361+
* In the terminal type: `idf.py monitor --print-filter="main:I"`
362+
363+
The output should look like Fig. 6.
364+
365+
{{< figure
366+
default=true
367+
src="img/runtime_change.webp"
368+
height=500
369+
caption="Fig.6 - idf.py monitor filtering"
370+
>}}
371+
372+
In this case, even though the verbosity level is set to __verbose__, the monitor filters out all messages with the main tag below _info_.
373+
374+
In this example, this process is equivalent to setting the verbosity level to info in `menuconfig`. However, when working with multiple components, you can set a different displayed verbosity level for each one individually.
375+
376+
## Conclusion
377+
378+
In this article, we explored the ESP-IDF logging system, showed how to define a module tag, used the `ESP_LOGx` macros for different severity levels, and adjusted verbosity to control which messages to display.
379+
380+
We also demonstrated how to change log levels at runtime and filter messages in the IDF monitor, giving developers fine-grained control over log visibility and improving both development efficiency and application performance.
381+
Unlike `printf`, logging provides structured, context-rich output that can be filtered by level, grouped by module, and disabled in production, making debugging and monitoring much easier.
382+
383+
### Further Reading
384+
385+
* For a deeper dive into the **logging library**, see the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/log.html).
386+
* To explore all host-side filtering options, refer to the [IDF Monitor documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-monitor.html#output-filtering).

0 commit comments

Comments
 (0)