Logging library
Overview
ESP-IDF provides a flexible logging system with two configurable versions, Log V1 and Log V2, selectable via CONFIG_LOG_VERSION. This document outlines their features, configurations, usage guidelines, and performance comparisons.
Log V1 (default): The original implementation designed for simplicity. It is optimized for early and DRAM logging but has higher flash usage and lacks flexibility.
Log V2: The enhanced implementation improves flexibility, reduces flash usage, and centralizes log formatting but requires a bit more stack.
Log V2 is backward-compatible with Log V1, meaning projects written using Log V1 can switch to Log V2 without modification. However, projects utilizing Log V2-specific features cannot revert to Log V1 due to compatibility constraints.
Features of Log V1
Formatting is included in the
format
argument and compiled into Flash.Fast early and DRAM logging compared to ESP_LOG.
Simple implementation but has limitations:
Larger binary size due to redundant formatting items.
Inflexible due to the lack of support for custom log formatting.
Build errors point to the wrong argument number in macros.
Features of Log V2
Centralized formatting via a single function,
esp_log()
.Reduces binary size by only storing the user-defined format string.
The timestamp is captured only when it is required for output and the log level permits logging.
Allows customization for log output:
Disable/enable color, timestamps, or tags globally, per file or per message log.
Output logs without formatting (useful for binary logging).
Apply different log settings for bootloader and app.
The format argument can be dynamic and set as a variable, allowing greater flexibility in constructing log messages.
Unified handler for logs across bootloader, ISR, startup code, and constrained environments.
Drawbacks:
Consumes more stack and memory.
The log handler is slightly slower than Log V1, but the difference is negligible compared to the time spent transferring the data, e.g. over UART.
Log Levels
Log levels are configured separately for application and bootloader. This separation allows developers to apply different logging settings via Kconfig options for each. For example, concise logs can be enabled for the bootloader while detailed debugging is enabled for the application. Use the bootloader-specific Kconfig options to configure log levels for the bootloader independently of the main application.
There are six verbosity levels:
Verbose - Highly detailed and frequent debugging messages, often including internal states, that may overwhelm the output. (highest)
Debug - Detailed diagnostic messages intended to aid in debugging (e.g., variable values, pointer addresses).
Info - General information messages that describe the normal operation of the system.
Warning - Events that could potentially cause issues but have been handled or mitigated.
Error - Critical errors indicating that the software cannot recover without intervention.
None - No log output. Used to completely disable logging. (lowest)
Log Level Settings
Log level settings control which logs are included in the binary and their visibility at runtime. There are two types of log level settings:
Log level: Specifies which log levels are displayed at runtime. The bootloader's log level is configured via CONFIG_BOOTLOADER_LOG_LEVEL, while the application's log level is set via CONFIG_LOG_DEFAULT_LEVEL. The current log level can be retrieved using the function
esp_log_get_default_level
.Maximum log level: Determines which log levels are included in the binary. Logs above this level are discarded at compile time and excluded from the final image. It can be set higher than the log level, allowing additional logs to be included in the binary and enabling them for debugging later if needed via
esp_log_level_set()
. The CONFIG_LOG_MAXIMUM_LEVEL option enables this feature for the application, but the bootloader does not support it. For the bootloader, the maximum log level is always the same as the log level.
Example for the application: if the log level is set to Warning and the maximum log level is set to Debug, the binary will include log messages of levels Error, Warning, Info, and Debug. However, at runtime, only log messages of levels Error and Warning will be outputted unless the log level is explicitly changed using esp_log_level_set()
. The log level can be adjusted, increased or decreased, depending on the user's needs.
Maximum Log Level
Setting
The LOG_LOCAL_LEVEL
definition allows you to override the maximum log level for a specific source file or component without modifying the Kconfig options. It effectively sets the maximum log level locally, enabling or excluding specific logs in the binary.
This approach is especially useful when you need more detailed logs for specific areas of the code without globally increasing the maximum log level, thereby avoiding unnecessary impacts on the binary size.
Change the maximum log level for a source file (do not add it in header files, as it may not work due to the single-inclusion approach used by header files). Define
LOG_LOCAL_LEVEL
with one of the values fromesp_log_level_t
before includingesp_log.h
. This allows you to control which log messages are included in the binary for that specific source file.// in a my_file.c file #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE #include "esp_log.h"
Change the maximum log level for an entire component by defining
LOG_LOCAL_LEVEL
in the component's CMakeLists.txt. This ensures that the specified log level is applied across all source files within the component, controlling which log messages are included in the binary:# in a component's CMakeLists.txt file target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE")
Runtime Log Level Setting
Only the application supports changing the log level at runtime. The bootloader does not support this feature.
By default, all log levels up to the log level are enabled at the startup. The function esp_log_level_set()
can be used to set the log level globally or on a per-module basis. Modules are identified by their tags, which are human-readable ASCII zero-terminated strings. This functionality depends on CONFIG_LOG_DYNAMIC_LEVEL_CONTROL, which is enabled by default. If this feature is not required, you can disable it to reduce code size and improve performance.
Example: Set the log level to ERROR
for all components (global setting):
esp_log_level_set("*", ESP_LOG_ERROR);
Adjusting log output per module (tag) depends on CONFIG_LOG_TAG_LEVEL_IMPL, which is enabled by default. If this feature is not required, you can disable it to reduce code size and improve performance:
Example: Set the log level to WARNING
only for the Wi-Fi component (module-specific setting):
esp_log_level_set("wifi", ESP_LOG_WARN);
Use Logging Library
In each C file that uses the logging functionality, define the TAG
variable.
// #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE // Optional: Increase log level that will be included in binary (only for this file)
#include "esp_log.h"
static const char* TAG = "MyModule";
// ...
ESP_LOGI(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real);
ESP_EARLY_LOGW(TAG, "Early log message %d", i++);
ESP_DRAM_LOGE(DRAM_STR("TAG_IN_DRAM"), "DRAM log message %d", i++); // Use DRAM_STR macro to put in DRAM if needed
I (112500) MyModule: Baud rate error 1.5%. Requested: 115200 baud, actual: 116928 baud
W (112500) MyModule: Early log message 1
E TAG_IN_DRAM: DRAM log message 2
Note
The TAG
variable points to a string literal stored in flash memory. If the same TAG
string is used multiple times within a single build unit (translation unit), the compiler and linker typically optimize it to a single copy in flash through a process called string pooling. However, if the same TAG
string is used across different components or translation units, each component or unit will have its own copy in flash unless global linker optimizations are applied.
The logging library provides a wide range of macros to accommodate various use cases, from general-purpose logging to early startup and constrained environments. Choosing the right macro and structuring your program accordingly can help optimize performance and ensure reliable operation. However, it is recommended to structure your program to avoid logging in constrained environments whenever possible.
Verbose:
ESP_LOGV
,ESP_EARLY_LOGV
,ESP_DRAM_LOGV
.Debug:
ESP_LOGD
,ESP_EARLY_LOGD
,ESP_DRAM_LOGD
.Info:
ESP_LOGI
,ESP_EARLY_LOGI
,ESP_DRAM_LOGI
.Warning:
ESP_LOGW
,ESP_EARLY_LOGW
,ESP_DRAM_LOGW
.Error:
ESP_LOGE
,ESP_EARLY_LOGE
,ESP_DRAM_LOGE
.
There are three groups of macros available:
ESP_LOGx: Standard logging macros suitable for most use cases during normal operation. Use these in your application code for logging in non-constrained environments, avoiding use in ISRs, early startup, or when the flash cache is disabled. A key characteristic of these macros is that they use the vprintf function from the Newlib library for formatting and outputting logs.
ESP_EARLY_LOGx: Designed for use in constrained environments during early startup, before the heap allocator or syscalls are initialized. These macros are commonly used in critical startup code or in critical sections where interrupts are disabled. A key characteristic of these macros is that they use the ROM printf function, always output timestamps in microseconds, and do not support per-module log verbosity settings.
ESP_DRAM_LOGx: Designed for use in constrained environments where logging occurs with interrupts disabled or when the flash cache is inaccessible. These macros should be used sparingly, as they can impact performance. They are suitable for critical sections or interrupt routines where other logging macros may not work reliably. A key characteristic of these macros is that they use the ROM printf function, do not output timestamps, allocate the format argument in DRAM to ensure accessibility when the cache is disabled, and do not support per-module log verbosity settings.
Note
Use the DRAM_STR("my_tag") macro to allocate the tag in DRAM. This is necessary to ensure access to the tag when the flash cache is disabled.
The difference between Log V1 and Log V2 is that in Log V2, all logs from these macros are routed through a single handler. This handler can automatically detect constrained environments (e.g., early startup, disabled interrupts, or flash cache inaccessible) and dynamically selects the appropriate printing function, ensuring efficient logging across various runtime contexts.
Log Format
Log V1: Only supports disabling color formatting globally. Other formatting options, such as timestamp and tag, are always enabled.
Log V2:
Allows complete customization of formatting, including the ability to disable color, tag, and timestamp formatting globally, per file, per module, or even for individual log messages.
Provides finer control over log output, making it more adaptable to specific use cases and environments.
// #define ESP_LOG_COLOR_DISABLED (1) /* For Log v2 only */
// #define ESP_LOG_TIMESTAMP_DISABLED (1) /* For Log v2 only */
#include "esp_log.h"
static const char* TAG = "boot";
// ...
ESP_LOGI(TAG, "chip revision: v%d.%d", major, minor);
I (56) boot: chip revision: v3.0
level name |end of line
| |
[0;32mI (56) boot: chip revision: v3.0[0m
|_____| |___||____||_________________||_|
|start | |tag | |end color
|color | |user string
|timestamp
The logging system supports the following formatting options, applicable for both the application and bootloader:
Color: Adds color codes to enhance log visibility globally. Controlled by CONFIG_LOG_COLORS, which is disabled by default because the ESP-IDF monitor tool (idf.py monitor) can detect the log level by its level name and apply the standard IDF color scheme.
For Log V2, the CONFIG_LOG_COLORS_SUPPORT option enables runtime support for adding color output to specific logs, files, or components, even if global color is disabled. To enable color for a specific context use
ESP_LOG_COLOR_DISABLED
.
Level Name: A single letter (I, W, E, D, V) indicating log verbosity, displayed at the start of each message. Useful for identifying log levels, especially when color is disabled, as utilized by the ESP-IDF monitor tool.
Timestamp: Adds a timestamp to log messages globally. Controlled by CONFIG_LOG_TIMESTAMP_SOURCE.
None: No timestamp. Useful for log analysis or debugging where timing is not critical. Saves processing power and memory. Available only for Log V2.
Milliseconds since boot (18532) (default): Derived from the RTOS tick count multiplied by the tick period.
System time (HH:MM:SS.sss) (14:31:18.532): Displays time in hours, minutes, seconds, and milliseconds.
System time (YY-MM-DD HH:MM:SS.sss) (2023-08-15 14:31:18.532): Similar to the above, but also includes the date.
Unix time in milliseconds (1692099078532): Displays Unix time in milliseconds.
For Log V2, the CONFIG_LOG_TIMESTAMP_SUPPORT option enables runtime support for adding timestamp output to specific logs, files, or components, even if global timestamp is disabled. To enable the Milliseconds since boot timestamp for a specific context, use
ESP_LOG_TIMESTAMP_DISABLED
.
Tag: Displays a user-defined identifier for the source module.
For Log V2, the tag can be passed to the macros as
NULL
, in which case it will not be printed, and per-component log level check will not work.
End Line: Adds a newline character at the end of the log messages.
The following options are applicable only for Log V2 and are used alongside the provided log macros. These definitions can be set in the same manner as LOG_LOCAL_LEVEL
. Their scope depends on where they are defined (e.g., file, component, or globally):
ESP_LOG_CONSTRAINED_ENV:
Define as
1
to force the log handleresp_log()
to use a safe printf function suitable for the specified scope.
ESP_LOG_FORMATTING_DISABLED:
Default:
0
(enables all formatting items such as color, timestamps, tags, and end line).Define as
1
to disable all formatting items for the specified scope.
ESP_LOG_COLOR_DISABLED: Requires CONFIG_LOG_COLORS_SUPPORT to be enabled.
If global color (CONFIG_LOG_COLORS) is disabled, define as
0
to enable color output for the specified scope.If global color (CONFIG_LOG_COLORS) is enabled, define as
1
to disable color output for the specified scope.
ESP_LOG_TIMESTAMP_DISABLED: Requires CONFIG_LOG_TIMESTAMP_SUPPORT to be enabled.
If global timestamping (CONFIG_LOG_TIMESTAMP_SOURCE) is disabled, define as
0
to enable tick timestamp output for the specified scope.If global timestamping (CONFIG_LOG_TIMESTAMP_SOURCE) is enabled, define as
1
to disable tick timestamp output for the specified scope.
Per-Log Formatting
The above definition works seamlessly with the provided log macros. However, if you require more flexibility or the ability to change settings at runtime, such as adjusting the log level based on a value (for example, temperature), this can be done using alternative macros. Note that in this case, the logs cannot be discarded from the binary, as they bypass compile-time log level checks.
The example below demonstrates how to adjust formatting for individual log messages:
#include "esp_log.h"
esp_log_config_t configs = {
.opts = {
.log_level = ESP_LOG_INFO, // Set log level
.constrained_env = false, // Specify constrained environment
.require_formatting = true, // Enable formatting
.dis_color = ESP_LOG_COLOR_DISABLED, // Use global color setting
.dis_timestamp = ESP_LOG_TIMESTAMP_DISABLED, // Use global timestamp setting
.reserved = 0, // Reserved for future use
}
};
// ...
if (temperature > 55) {
configs.opts.log_level = ESP_LOG_WARN;
}
// Similar to ESP_LOGx macros but allows applying custom configurations
// If the configs var is constant, the compiler can exclude the log during compilation
// if it is below the maximum log level, otherwise not.
ESP_LOG_LEVEL_LOCAL(configs, TAG, "Temp = %dC", temperature);
// Note: The following calls bypass compile-time log level checks,
// they cannot be discarded from the binary
esp_log(configs, TAG, "Temp = %dC", temperature);
ESP_LOG_LEVEL(configs, TAG, "Temp = %dC", temperature);
Log Level Control
Only the application supports changing the log level at runtime. The bootloader does not support this feature.
The logging library allows adjusting log output per module (tag) at runtime using the function esp_log_level_set()
. This feature applies only to non-constrained environments (ESP_LOGx macros). Constrained environments (e.g., ESP_EARLY_LOGx or ESP_DRAM_LOGx) do not support dynamic log levels due to the absence of locks and lightweight requirements in their log handlers.
// Set log level to ERROR for all components (global setting)
esp_log_level_set("*", ESP_LOG_ERROR);
// Set log level to WARNING for the WiFi component (module-specific setting)
esp_log_level_set("wifi", ESP_LOG_WARN);
// Set log level to INFO for the DHCP client (module-specific setting)
esp_log_level_set("dhcpc", ESP_LOG_INFO);
There are three settings that control the ability to change the log level at runtime globally or per module (tag):
Dynamic Log Level Control (CONFIG_LOG_DYNAMIC_LEVEL_CONTROL, enabled by default): Enables runtime log level changes via
esp_log_level_set()
. This feature increases flexibility but adds memory and performance overhead. If binary size is a concern and dynamic log level changes are unnecessary, consider disabling this option, especially when CONFIG_LOG_TAG_LEVEL_IMPL is set to None, to minimize program size.If your application does not require dynamic log level adjustments, disabling this option can improve efficiency by:
Reducing memory consumption:
IRAM: about 260 bytes
DRAM: about 264 bytes
Flash: about 1 KB
Boosting log operation performance by up to 10 times.
Tag-Level Checks (CONFIG_LOG_TAG_LEVEL_IMPL, default Cache + Linked List): Determines how per-tag log level checks are performed, affecting memory usage and lookup speed:
None: Disables per-tag log level checks entirely, reducing overhead but removing runtime flexibility.
Linked List: Enables per-tag log level settings using a linked list-only implementation (no cache). This method searches through all tags in the linked list to determine the log level, which may result in slower lookups for a large number of tags but consumes less memory compared to the Cache approach. The linked list approach performs full string comparisons of log tags to identify the appropriate log level. Unlike Cache, it does not rely on tag pointer comparisons, making it suitable for dynamic tag definitions. Select this option if you prioritize memory savings, need to enable or disable logs for specific modules, or want to use tags defined as variables. Selecting this option automatically enables Dynamic Log Level Control. The linked list entries are allocated on the heap during the execution of
ESP_LOGx
macros when a new tag is encountered.Cache + Linked List (Default): It is a hybrid mode that combines caching with a linked list for log tag level checks. This hybrid approach offers a balance between speed and memory usage. The cache stores recently accessed log tags and their corresponding log levels, providing faster lookups for frequently used tags. The cache approach compares the tag pointers, which is faster than performing full string comparisons. For less frequently used tags, the linked list is utilized to search for the log level. This option may not work properly when dynamic tag definitions are used, as it relies on tag pointer comparisons in the cache, which are not suitable for dynamically defined tags. This hybrid approach improves the efficiency of log level retrieval by leveraging the speed of caching for common tags and the memory efficiency of a linked list for less frequently used tags. Selecting this option automatically enables Dynamic Log Level Control.
There are some cache configurations to balance memory usage and lookup performance. These settings determine how log tag levels are stored and accessed: CONFIG_LOG_TAG_LEVEL_CACHE_IMPL.
Array: A simple implementation without reordering, suitable for low-memory applications that prioritize simplicity.
Binary Min-Heap (default): An optimized implementation for fast lookups with automatic reordering. Ideal for high-performance applications with sufficient memory. The Cache Size (CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE) defines the capacity, which defaults to 31 entries.
A larger cache size enhances lookup performance for frequently accessed log tags but increases memory consumption. In contrast, a smaller cache size conserves memory but may result in more frequent evictions of less commonly used log tags.
Master Log Level (CONFIG_LOG_MASTER_LEVEL, disabled by default): It is an optional setting designed for specific debugging scenarios. It enables a global "master" log level check that occurs before timestamps and tag cache lookups. This is useful for compiling numerous logs that can be selectively enabled or disabled at runtime while minimizing performance impact when log output is unnecessary.
Common use cases include temporarily disabling logs during time-critical or CPU-intensive operations and re-enabling them later.
Note
For Log V1, this feature may significantly increase program size based on the number of compiled logs. For Log V2, the impact is minimal as the check is integrated within the log handler.
If enabled, the master log level defaults to CONFIG_LOG_DEFAULT_LEVEL and can be adjusted at runtime using
esp_log_set_level_master()
. This global check takes precedence overesp_log_get_default_level
.The snippet below shows how it works. Setting the Master log level to
ESP_LOG_NONE
disables all logging globally.esp_log_level_set()
does not currently affect logging. However, after the Master log level is adjusted to a higher level, logs will be printed as configured byesp_log_level_set()
:// Master logging level is CONFIG_LOG_DEFAULT_LEVEL at start-up and = ESP_LOG_INFO ESP_LOGI("lib_name", "Message for print"); // Prints an INFO message esp_log_level_set("lib_name", ESP_LOG_WARN); // Enables WARN logs for lib_name // Disables all logs globally. esp_log_level_set has no effect at the moment esp_log_set_level_master(ESP_LOG_NONE); ESP_LOGW("lib_name", "Message for print"); // No print, Master logging level blocks it esp_log_level_set("lib_name", ESP_LOG_INFO); // Enables INFO logs for lib_name ESP_LOGI("lib_name", "Message for print"); // No print, Master logging level blocks it // Enables all INFO logs globally esp_log_set_level_master(ESP_LOG_INFO); ESP_LOGI("lib_name", "Message for print"); // Prints an INFO message
Note
Even when logs are disabled by tag, processing still takes approximately 10.9 microseconds. To reduce this overhead, consider using the Master Log Level or disabling Tag-Level Checks functionality.
Logging of Buffers
The logging system provides macros for logging buffer data. These macros can be used in both bootloader and application, and they are independent of the log version. Available macros:
ESP_LOG_BUFFER_HEX
andESP_LOG_BUFFER_HEX_LEVEL
: Logs a buffer of hexadecimal bytes. The data is split into lines with 16 bytes per line.ESP_LOG_BUFFER_HEX
is only for theInfo
log level.#include "esp_log_buffer.h" uint8_t buffer[] = { 0x54, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66 }; ESP_LOG_BUFFER_HEX_LEVEL(TAG, buffer, sizeof(buffer), ESP_LOG_DEBUG);
I (954) MyModule: 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73 I (964) MyModule: 74 61 72 74 65 64 20 69 73 20 61 6e 64 20 66
ESP_LOG_BUFFER_CHAR
andESP_LOG_BUFFER_CHAR_LEVEL
: Logs a buffer of printable characters. Each line contains up to 16 characters.ESP_LOG_BUFFER_CHAR
is only for theInfo
log level.#include "esp_log_buffer.h" char buffer[] = "The quick brown fox jumps over the lazy dog."; ESP_LOG_BUFFER_CHAR_LEVEL(TAG, buffer, sizeof(buffer), ESP_LOG_WARN);
I (980) MyModule: The quick brown I (985) MyModule: fox jumps over I (990) MyModule: the lazy dog.
ESP_LOG_BUFFER_HEXDUMP
: Dumps a buffer in a formatted hex dump style, displaying both the memory address and corresponding ASCII values. This is especially useful for debugging raw memory content.#include "esp_log_buffer.h" uint8_t buffer[] = { 0x54, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x65, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x69 }; ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, sizeof(buffer), ESP_LOG_INFO);
I (1013) MyModule: 0x3ffb5bc0 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73 |The way to get s| I (1024) MyModule: 0x3ffb5bd0 74 61 72 74 65 64 20 69 73 20 74 6f 20 71 75 69 |tarted is to qui|
The number of lines in the output depends on the size of the buffer.
Performance and Measurements
When logging is used in a task, the task stack must be configured with at least 2 KB of space to ensure sufficient memory for logging operations.
The following measurements were performed using tests inside the log component with default settings (the maximum and default log levels were set to INFO, color support was disabled, without master log and timestamps were enabled) across different chips:
Performance measurements for log APIs
Stack usage for log APIs
esp_rom_printf
and esp_rom_vprintf
produce similar results. Similarly, vprintf
and printf
yield comparable outcomes. Hence, only one of each pair is included in the tables below.
Function |
ESP32 |
ESP32C2 |
ESP32C3 |
---|---|---|---|
esp_rom_printf |
128 |
192 |
192 |
ESP_EARLY_LOGI V1 |
128 |
192 |
192 |
ESP_EARLY_LOGI V2 |
336 |
324 |
324 |
ESP_DRAM_LOGI V1 |
128 |
192 |
192 |
ESP_DRAM_LOGI V2 |
336 |
324 |
324 |
vprintf |
1168 |
384 |
1344 |
ESP_LOGI V1 |
1184 |
384 |
1344 |
ESP_LOGI V2 |
1152 |
592 |
1504 |
The stack usage differences between Log V1 and Log V2 are negligible.
Function |
ESP32 |
ESP32C2 |
ESP32C3 |
---|---|---|---|
esp_rom_printf |
1 |
2 |
1 |
ESP_EARLY_LOGI V1 |
15 |
24 |
14 |
ESP_EARLY_LOGI V2 |
28 |
36 |
25 |
ESP_DRAM_LOGI V1 |
6 |
9 |
5 |
ESP_DRAM_LOGI V2 |
19 |
22 |
14 |
vprintf |
15 |
9 |
7 |
ESP_LOGI V1 |
27 |
16 |
12 |
ESP_LOGI V2 |
77 |
54 |
40 |
If logging to UART is measured, the performance numbers for Log V1 and Log V2 are nearly identical. The slight differences in processing overhead introduced by Log V2 become negligible compared to the time it takes to send logs over UART. Thus, in most practical use cases, the performance impact of switching to Log V2 will be unnoticeable.
Memory Usage (bytes)
The following measurements were performed using the esp_timer
example with default settings for ESP32: the maximum and default log levels were set to INFO, color support was disabled, and timestamps were enabled. After enabling the Log V2 option, the example was rebuilt, and the memory usage differences were compared using the command:
idf.py size --diff ~/esp/logv2/build_v1
Version |
IRAM |
DRAM |
Flash Code |
Flash Data |
App binary size |
---|---|---|---|---|---|
Log V2 |
+1772 |
–36 |
–956 |
–1172 |
181104 (–384) |
Version |
Bootloader binary size |
---|---|
Log V2 |
26272 (+160) |
Enabling Log V2 increases IRAM usage while reducing the overall application binary size, Flash code, and data usage.
Logging to Host via JTAG
By default, the logging library uses the vprintf-like function to write formatted output to the dedicated UART. By calling a simple API, all log output may be routed to JTAG instead, making logging several times faster. For details, please refer to Section Logging to Host.
Thread Safety
Logging from constrained environments (or for ESP_EARLY_LOGx and ESP_DRAM_LOGx) does not use locking mechanisms, which can lead to rare cases of log corruption if other tasks are logging in parallel. To minimize such risks, it is recommended to use general-purpose macros whenever possible.
General-purpose macros (ESP_LOGx) ensure thread safety by acquiring locks during log output. In Log V2, additional protection is provided by flockfile
during multiple vprintf
calls for formatting.
Logs are first written to a memory buffer before being sent to the UART, ensuring thread-safe operations across different tasks. Avoid logging from constrained environments unless necessary to maintain reliable log output.
Application Example
The logging library is commonly used by most ESP-IDF components and examples. For demonstration of log functionality, check ESP-IDF's examples directory. The most relevant examples that deal with logging are the following:
API Reference
Header File
This header file can be included with:
#include "esp_log.h"
Functions
-
void esp_log(esp_log_config_t config, const char *tag, const char *format, ...)
Logs a formatted message using the provided log message configs and a variable argument list.
- Parameters
config -- Configuration and level of the log message.
tag -- The tag string used to indicate the component from which to log. It is also used to check whether logging is enabled for that tag (depends on CONFIG_LOG_TAG_LEVEL_IMPL). If NULL then the tag is not printed.
format -- The format string for the log message.
... -- Optional arguments to be formatted according to the format string.
-
void esp_log_va(esp_log_config_t config, const char *tag, const char *format, va_list args)
Logs a formatted message using the provided log message configs and a variable argument list.
- Parameters
config -- Configuration and level of the log message.
tag -- The tag string used to indicate the component from which to log. It is also used to check whether logging is enabled for that tag (depends on CONFIG_LOG_TAG_LEVEL_IMPL). If NULL then the tag is not printed.
format -- The format string for the log message.
args -- List of arguments.
Macros
-
ESP_EARLY_LOGE(tag, format, ...)
Early log macros to output logs in startup code, before heap allocator and syscalls have been initialized. The log level can be changed per-tag using
esp_log_level_set(TAG, level)
.macro to output logs in startup code, before heap allocator and syscalls have been initialized. Log at
ESP_LOG_ERROR
level.See also
printf
,ESP_LOGE
,ESP_DRAM_LOGE
In the future, we want to become compatible with clang. Hence, we provide two versions of the following macros which are using variadic arguments. The first one is using the GNU extension##__VA_ARGS__
. The second one is using the C++20 feature__VA_OPT__(,)
. This allows users to compile their code with standard C++20 enabled instead of the GNU extension. Below C++20, we haven't found any good alternative to using##__VA_ARGS__
. macro to output logs in startup code atESP_LOG_ERROR
level.
-
ESP_EARLY_LOGW(tag, format, ...)
macro to output logs in startup code at
ESP_LOG_WARN
level.
-
ESP_EARLY_LOGI(tag, format, ...)
macro to output logs in startup code at
ESP_LOG_INFO
level.
-
ESP_EARLY_LOGD(tag, format, ...)
macro to output logs in startup code at
ESP_LOG_DEBUG
level.
-
ESP_EARLY_LOGV(tag, format, ...)
macro to output logs in startup code at
ESP_LOG_VERBOSE
level.
-
ESP_LOGE(tag, format, ...)
Normal logging macros to output logs. The log level can be changed per-tag using
esp_log_level_set(TAG, level)
.macro to output logs at
ESP_LOG_ERROR
level.
-
ESP_LOGW(tag, format, ...)
macro to output logs at
ESP_LOG_WARN
level.
-
ESP_LOGI(tag, format, ...)
macro to output logs at
ESP_LOG_INFO
level.
-
ESP_LOGD(tag, format, ...)
macro to output logs at
ESP_LOG_DEBUG
level.
-
ESP_LOGV(tag, format, ...)
macro to output logs at
ESP_LOG_VERBOSE
level.
-
ESP_DRAM_LOGE(tag, format, ...)
Macros to output logs when the cache is disabled. Unlike normal logging macros, it's possible to use this macro when interrupts are disabled or inside an ISR. Placing log strings in DRAM reduces available DRAM, so only use when absolutely essential.
Usage:
ESP_DRAM_LOGE(DRAM_STR("my_tag"), "format", ...), or
ESP_DRAM_LOGE(TAG, "format", ...)`, where TAG is a char* that points to a str in the DRAM. macro to output logs when the cache is disabled atESP_LOG_ERROR
level.
-
ESP_DRAM_LOGW(tag, format, ...)
macro to output logs when the cache is disabled at
ESP_LOG_WARN
level.
-
ESP_DRAM_LOGI(tag, format, ...)
macro to output logs when the cache is disabled at
ESP_LOG_INFO
level.
-
ESP_DRAM_LOGD(tag, format, ...)
macro to output logs when the cache is disabled at
ESP_LOG_DEBUG
level.
-
ESP_DRAM_LOGV(tag, format, ...)
macro to output logs when the cache is disabled at
ESP_LOG_VERBOSE
level.
-
ESP_LOG_LEVEL_LOCAL(configs, tag, format, ...)
runtime macro to output logs at a specified configs. Also check the level with
LOG_LOCAL_LEVEL
.
-
ESP_LOG_LEVEL(configs, tag, format, ...)
runtime macro to output logs at a specified level and with ESP_LOG_CONFIGS_DEFAULT.
See also
printf
- Parameters
configs -- it includes level and other log configurations.
tag -- tag of the log, which can be used to change the log level by
esp_log_level_set
at runtime.format -- format of the output log. See
printf
... -- variables to be replaced into the log. See
printf
Header File
This header file can be included with:
#include "esp_log_level.h"
Functions
-
static inline esp_log_level_t esp_log_get_default_level(void)
Get the default log level.
This function returns the default log level. The default log level is used by the definition of ESP_LOGx macros and can be overridden for specific tags using
esp_log_level_set("*", level)
. If CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=n, changing the default log level is not possible.- Returns
The default log level.
-
void esp_log_set_level_master(esp_log_level_t level)
Master log level.
Allows one to set a higher CONFIG_LOG_MAXIMUM_LEVEL but not impose a performance hit during normal operation (only when instructed). An application may set esp_log_set_level_master(level) to globally enforce a maximum log level. ESP_LOG macros above this level will be skipped, rather than doing a tag lookup.
The Master log level is not applicable for the bootloader.
- Parameters
level -- Master log level
-
esp_log_level_t esp_log_get_level_master(void)
Returns master log level. The Master log level is not applicable for the bootloader.
- Returns
Master log level
-
void esp_log_level_set(const char *tag, esp_log_level_t level)
Set log level for given tag.
If logging for given component has already been enabled, changes previous setting.
To raise log level above the default one for a given file, define LOG_LOCAL_LEVEL to one of the ESP_LOG_* values, before including esp_log.h in this file.
If CONFIG_LOG_DYNAMIC_LEVEL_CONTROL is not selected the static (no-op) implementation of log level is used. Changing the log level is not possible, esp_log_level_set does not work.
Note
Note that this function can not raise log level above the level set using CONFIG_LOG_MAXIMUM_LEVEL setting in menuconfig.
- Parameters
tag -- Tag of the log entries to enable. Must be a non-NULL zero terminated string. Value "*" resets log level for all tags to the given value. If the tag is NULL then a silent return happens.
level -- Selects log level to enable. Only logs at this and lower verbosity levels will be shown.
-
esp_log_level_t esp_log_level_get(const char *tag)
Get log level for a given tag, can be used to avoid expensive log statements.
If CONFIG_LOG_DYNAMIC_LEVEL_CONTROL is not selected the static (no-op) implementation of log level is used. Changing the log level is not possible, esp_log_level_set does not work. This function returns the default log level.
- Parameters
tag -- Tag of the log to query current level. Must be a zero terminated string. If tag is NULL then the default log level is returned (see esp_log_get_default_level()).
- Returns
The current log level for the given tag.
Macros
-
ESP_LOG_LEVEL_LEN
Number of bits used to represent the log level
-
ESP_LOG_LEVEL_MASK
Mask for log level
-
ESP_LOG_GET_LEVEL(config)
Returns level from config.
-
ESP_LOG_ENABLED(configs)
Check if a specific log level is enabled at compile-time.
This macro checks whether logging for the specified log level is enabled based on the current local log level setting (
LOG_LOCAL_LEVEL
). It uses a compile-time check to determine if logging for the specified level should be included in the binary, helping to exclude logs that are not configured.- Parameters
configs -- it includes log configs and level.
- Returns
true if the specified log level is enabled, false otherwise.
Enumerations
-
enum esp_log_level_t
Log level.
Values:
-
enumerator ESP_LOG_NONE
No log output
-
enumerator ESP_LOG_ERROR
Critical errors, software module can not recover on its own
-
enumerator ESP_LOG_WARN
Error conditions from which recovery measures have been taken
-
enumerator ESP_LOG_INFO
Information messages which describe normal flow of events
-
enumerator ESP_LOG_DEBUG
Extra information which is not necessary for normal use (values, pointers, sizes, etc).
-
enumerator ESP_LOG_VERBOSE
Bigger chunks of debugging information, or frequent messages which can potentially flood the output.
-
enumerator ESP_LOG_MAX
Number of levels supported
-
enumerator ESP_LOG_NONE
Header File
This header file can be included with:
#include "esp_log_buffer.h"
Functions
-
void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level)
Logs a buffer of hexadecimal bytes at the specified log level.
This function logs a buffer of hexadecimal bytes with 16 bytes per line. The log level determines the severity of the log message.
Note
This function does not check the log level against the ESP_LOCAL_LEVEL. The log level comparison should be done in esp_log.h.
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
level -- Log level indicating the severity of the log message.
-
void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level)
This function logs a buffer of characters with 16 characters per line. The buffer should contain only printable characters. The log level determines the severity of the log message.
Note
This function does not check the log level against the ESP_LOCAL_LEVEL. The log level comparison should be done in esp_log.h.
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
level -- Log level indicating the severity of the log message.
-
void esp_log_buffer_hexdump_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level)
This function dumps a buffer to the log in a formatted hex dump style, displaying both the memory address and the corresponding hex and ASCII values of the bytes. The log level determines the severity of the log message.
Note
This function does not check the log level against the ESP_LOCAL_LEVEL. The log level comparison should be done in esp_log.h.
Note
It is recommended to use terminals with a width of at least 102 characters to display the log dump properly.
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
log_level -- Log level indicating the severity of the log message.
Macros
-
ESP_LOG_BUFFER_HEX_LEVEL(tag, buffer, buff_len, level)
Log a buffer of hex bytes at specified level, separated into 16 bytes each line.
The hex log shows just like the one below:
I (954) log_example: 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73 I (962) log_example: 74 61 72 74 65 64 20 69 73 20 74 6f 20 71 75 69 I (969) log_example: 74 20 74 61 6c 6b 69 6e 67 20 61 6e 64 20 62 65 I (977) log_example: 67 69 6e 20 64 6f 69 6e 67 2e 20 2d 20 57 61 6c I (984) log_example: 74 20 44 69 73 6e 65 79 00
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
level -- Log level
-
ESP_LOG_BUFFER_CHAR_LEVEL(tag, buffer, buff_len, level)
Log a buffer of characters at specified level, separated into 16 bytes each line. Buffer should contain only printable characters.
The char log shows just like the one below:
I (980) log_example: The way to get s I (985) log_example: tarted is to qui I (989) log_example: t talking and be I (994) log_example: gin doing. - Wal I (999) log_example: t Disney
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
level -- Log level.
-
ESP_LOG_BUFFER_HEXDUMP(tag, buffer, buff_len, level)
Dump a buffer to the log at specified level.
The dump log shows just like the one below:
I (1013) log_example: 0x3ffb5bc0 54 68 65 20 77 61 79 20 74 6f 20 67 65 74 20 73 |The way to get s| I (1024) log_example: 0x3ffb5bd0 74 61 72 74 65 64 20 69 73 20 74 6f 20 71 75 69 |tarted is to qui| I (1034) log_example: 0x3ffb5be0 74 20 74 61 6c 6b 69 6e 67 20 61 6e 64 20 62 65 |t talking and be| I (1044) log_example: 0x3ffb5bf0 67 69 6e 20 64 6f 69 6e 67 2e 20 2d 20 57 61 6c |gin doing. - Wal| I (1054) log_example: 0x3ffb5c00 74 20 44 69 73 6e 65 79 00 |t Disney.|
Note
It is highly recommended to use terminals with over 102 text width.
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
level -- Log level.
-
ESP_LOG_BUFFER_HEX(tag, buffer, buff_len)
Log a buffer of hex bytes at Info level.
See also
ESP_LOG_BUFFER_HEX_LEVEL
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
-
ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len)
Log a buffer of characters at Info level. Buffer should contain only printable characters.
See also
ESP_LOG_BUFFER_CHAR_LEVEL
- Parameters
tag -- Description tag to identify the log.
buffer -- Pointer to the buffer array containing the data to be logged.
buff_len -- Length of the buffer in bytes.
Header File
This header file can be included with:
#include "esp_log_timestamp.h"
Functions
-
uint32_t esp_log_timestamp(void)
Function which returns timestamp to be used in log output.
This function is used in expansion of ESP_LOGx macros. In the 2nd stage bootloader, and at early application startup stage this function uses CPU cycle counter as time source. Later when FreeRTOS scheduler start running, it switches to FreeRTOS tick count.
For now, we ignore millisecond counter overflow.
- Returns
timestamp, in milliseconds
-
char *esp_log_system_timestamp(void)
Function which returns system timestamp to be used in log output.
This function is used in expansion of ESP_LOGx macros to print the system time as "HH:MM:SS.sss". The system time is initialized to 0 on startup, this can be set to the correct time with an SNTP sync, or manually with standard POSIX time functions.
Currently, this will not get used in logging from binary blobs (i.e. Wi-Fi & Bluetooth libraries), these will still print the RTOS tick time.
- Returns
timestamp, in "HH:MM:SS.sss"
-
uint32_t esp_log_early_timestamp(void)
Function which returns timestamp to be used in log output.
This function uses HW cycle counter and does not depend on OS, so it can be safely used after application crash.
- Returns
timestamp, in milliseconds
Header File
This header file can be included with:
#include "esp_log_color.h"
Header File
This header file can be included with:
#include "esp_log_write.h"
Functions
-
vprintf_like_t esp_log_set_vprintf(vprintf_like_t func)
Set function used to output log entries.
By default, log output goes to UART0. This function can be used to redirect log output to some other destination, such as file or network. Returns the original log handler, which may be necessary to return output to the previous destination.
Note
Please note that function callback here must be re-entrant as it can be invoked in parallel from multiple tasks context.
- Parameters
func -- new Function used for output. Must have same signature as vprintf.
- Returns
func old Function used for output.
-
void esp_log_write(esp_log_level_t level, const char *tag, const char *format, ...)
Write message into the log.
This function is not intended to be used directly. Instead, use one of ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros.
This function or these macros should not be used from an interrupt.
This function does not add any formatting elements such as color, timestamp, or tag. It checks the level and tag level. If logging is allowed then it outputs it as is.
- Parameters
level -- Log level of the message.
tag -- It is used to check whether logging is enabled for that tag (depends on CONFIG_LOG_TAG_LEVEL_IMPL).
format -- The format string for the log message. It has to be fully formatted, no additional formatting items will be added.
... -- Optional arguments to be formatted according to the format string.
-
void esp_log_writev(esp_log_level_t level, const char *tag, const char *format, va_list args)
Write message into the log, va_list variant.
This function is provided to ease integration toward other logging framework, so that esp_log can be used as a log sink.
See also
esp_log_write()
This function does not add any formatting elements such as color, timestamp, or tag. It checks the level and tag level. If logging is allowed then it outputs it as is.
- Parameters
level -- Log level of the message.
tag -- It is used to check whether logging is enabled for that tag (depends on CONFIG_LOG_TAG_LEVEL_IMPL).
format -- The format string for the log message. It has to be fully formatted, no additional formatting items will be added.
args -- List of arguments.
Type Definitions
-
typedef int (*vprintf_like_t)(const char*, va_list)