feat(log): Refactoring buffer log APIs

This commit is contained in:
Konstantin Kondrashov 2024-03-11 15:44:33 +02:00
parent 7a70647a01
commit 0f4fc2bf55
11 changed files with 396 additions and 146 deletions

View File

@ -1,22 +1,27 @@
idf_build_get_property(target IDF_TARGET)
set(srcs "log.c" "log_buffers.c")
set(srcs "")
set(priv_requires "")
if(${target} STREQUAL "linux")
list(APPEND srcs "log_linux.c")
if(BOOTLOADER_BUILD)
list(APPEND srcs "log_noos.c")
else()
list(APPEND priv_requires soc hal esp_hw_support)
list(APPEND srcs "log.c")
if(${target} STREQUAL "linux")
list(APPEND srcs "log_linux.c")
else()
list(APPEND srcs "log_freertos.c")
list(APPEND priv_requires soc hal esp_hw_support)
endif()
# Buffer APIs call ESP_LOG_LEVEL -> esp_log_write, which can not used in bootloader.
list(APPEND srcs "src/buffer/log_buffers.c"
"src/util.c")
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "include/esp_private"
LDFRAGMENTS linker.lf
PRIV_REQUIRES ${priv_requires})
if(NOT ${target} STREQUAL "linux")
# Ideally, FreeRTOS shouldn't be included into bootloader build, so the 2nd check should be unnecessary
if(freertos IN_LIST BUILD_COMPONENTS AND NOT BOOTLOADER_BUILD)
target_sources(${COMPONENT_TARGET} PRIVATE log_freertos.c)
else()
target_sources(${COMPONENT_TARGET} PRIVATE log_noos.c)
endif()
endif()

View File

@ -24,6 +24,7 @@ public:
BasicLogFixture(esp_log_level_t log_level = ESP_LOG_VERBOSE)
{
std::memset(print_buffer, 0, BUFFER_SIZE);
buffer_idx = 0;
esp_log_level_set("*", log_level);
}
@ -40,11 +41,13 @@ public:
void reset_buffer()
{
std::memset(print_buffer, 0, BUFFER_SIZE);
buffer_idx = 0;
additional_reset();
}
protected:
char print_buffer [BUFFER_SIZE];
int buffer_idx;
virtual void additional_reset() { }
};
@ -75,7 +78,9 @@ private:
int print_to_buffer(const char *format, va_list args)
{
int ret = vsnprintf(print_buffer, BUFFER_SIZE, format, args);
// Added support for multi-line log, for example ESP_LOG_BUFFER...
int ret = vsnprintf(&print_buffer[buffer_idx], BUFFER_SIZE, format, args);
buffer_idx += ret;
return ret;
}
@ -215,6 +220,19 @@ TEST_CASE("log bytes > 127")
CHECK(regex_search(fix.get_print_buffer_string(), buffer_regex));
}
TEST_CASE("log buffer char")
{
PrintFixture fix(ESP_LOG_INFO);
const char g[] = "The way to get started is to quit talking and begin doing. - Walt Disney";
const std::regex buffer_regex("I \\([0-9]*\\) test: The way to get s.*\n\
.*I \\([0-9]*\\) test: tarted is to qui.*\n\
.*I \\([0-9]*\\) test: t talking and be.*\n\
.*I \\([0-9]*\\) test: gin doing. - Wal.*\n\
.*I \\([0-9]*\\) test: t Disney", std::regex::ECMAScript);
ESP_LOG_BUFFER_CHAR(TEST_TAG, g, sizeof(g));
CHECK(regex_search(fix.get_print_buffer_string(), buffer_regex) == true);
}
TEST_CASE("log buffer dump")
{
PrintFixture fix(ESP_LOG_INFO);

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -12,24 +12,13 @@
#include <inttypes.h>
#include "sdkconfig.h"
#include "esp_rom_sys.h"
#include "esp_log_level.h"
#include "esp_log_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Log level
*
*/
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
typedef int (*vprintf_like_t)(const char *, va_list);
/**
@ -172,113 +161,6 @@ void esp_log_writev(esp_log_level_t level, const char* tag, const char* format,
/** @cond */
#include "esp_log_internal.h"
#ifndef LOG_LOCAL_LEVEL
#ifndef BOOTLOADER_BUILD
#define LOG_LOCAL_LEVEL CONFIG_LOG_MAXIMUM_LEVEL
#else
#define LOG_LOCAL_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL
#endif
#endif
/** @endcond */
/**
* @brief Log a buffer of hex bytes at specified level, separated into 16 bytes each line.
*
* @param tag description tag
* @param buffer Pointer to the buffer array
* @param buff_len length of buffer in bytes
* @param level level of the log
*
*/
#define ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, level ) \
do {\
if ( LOG_LOCAL_LEVEL >= (level) ) { \
esp_log_buffer_hex_internal( tag, buffer, buff_len, level ); \
} \
} while(0)
/**
* @brief Log a buffer of characters at specified level, separated into 16 bytes each line. Buffer should contain only printable characters.
*
* @param tag description tag
* @param buffer Pointer to the buffer array
* @param buff_len length of buffer in bytes
* @param level level of the log
*
*/
#define ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, level ) \
do {\
if ( LOG_LOCAL_LEVEL >= (level) ) { \
esp_log_buffer_char_internal( tag, buffer, buff_len, level ); \
} \
} while(0)
/**
* @brief Dump a buffer to the log at specified level.
*
* The dump log shows just like the one below:
*
* W (195) log_example: 0x3ffb4280 45 53 50 33 32 20 69 73 20 67 72 65 61 74 2c 20 |ESP32 is great, |
* W (195) log_example: 0x3ffb4290 77 6f 72 6b 69 6e 67 20 61 6c 6f 6e 67 20 77 69 |working along wi|
* W (205) log_example: 0x3ffb42a0 74 68 20 74 68 65 20 49 44 46 2e 00 |th the IDF..|
*
* It is highly recommended to use terminals with over 102 text width.
*
* @param tag description tag
* @param buffer Pointer to the buffer array
* @param buff_len length of buffer in bytes
* @param level level of the log
*/
#define ESP_LOG_BUFFER_HEXDUMP( tag, buffer, buff_len, level ) \
do { \
if ( LOG_LOCAL_LEVEL >= (level) ) { \
esp_log_buffer_hexdump_internal( tag, buffer, buff_len, level); \
} \
} while(0)
/**
* @brief Log a buffer of hex bytes at Info level
*
* @param tag description tag
* @param buffer Pointer to the buffer array
* @param buff_len length of buffer in bytes
*
* @see ``esp_log_buffer_hex_level``
*
*/
#define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) \
do { \
if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \
ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \
}\
} while(0)
/**
* @brief Log a buffer of characters at Info level. Buffer should contain only printable characters.
*
* @param tag description tag
* @param buffer Pointer to the buffer array
* @param buff_len length of buffer in bytes
*
* @see ``esp_log_buffer_char_level``
*
*/
#define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) \
do { \
if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \
ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \
}\
} while(0)
/** @cond */
//to be back compatible
#define esp_log_buffer_hex ESP_LOG_BUFFER_HEX
#define esp_log_buffer_char ESP_LOG_BUFFER_CHAR
#if CONFIG_LOG_COLORS
#define LOG_COLOR_BLACK "30"
#define LOG_COLOR_RED "31"

View File

@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_log_level.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !BOOTLOADER_BUILD || __DOXYGEN__
/**
* @brief 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.
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param level Log level indicating the severity of the log message.
*/
void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level);
/**
* @brief 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.
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param 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);
/**
* @brief 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.
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param log_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);
/**
* @brief 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
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param level Log level
*/
#define ESP_LOG_BUFFER_HEX_LEVEL(tag, buffer, buff_len, level) \
do { if (LOG_LOCAL_LEVEL >= (level)) {esp_log_buffer_hex_internal(tag, buffer, buff_len, level);} } while(0)
/**
* @brief 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
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param level Log level.
*
*/
#define ESP_LOG_BUFFER_CHAR_LEVEL(tag, buffer, buff_len, level) \
do { if (LOG_LOCAL_LEVEL >= (level)) {esp_log_buffer_char_internal(tag, buffer, buff_len, level);} } while(0)
/**
* @brief 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.
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
* @param level Log level.
*/
#define ESP_LOG_BUFFER_HEXDUMP(tag, buffer, buff_len, level) \
do { if (LOG_LOCAL_LEVEL >= (level)) {esp_log_buffer_hexdump_internal(tag, buffer, buff_len, level);} } while(0)
/**
* @brief Log a buffer of hex bytes at Info level
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
*
* @see ``ESP_LOG_BUFFER_HEX_LEVEL``
*
*/
#define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) \
do { if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {ESP_LOG_BUFFER_HEX_LEVEL(tag, buffer, buff_len, ESP_LOG_INFO);} } while(0)
/**
* @brief Log a buffer of characters at Info level. Buffer should contain only printable characters.
*
* @param tag Description tag to identify the log.
* @param buffer Pointer to the buffer array containing the data to be logged.
* @param buff_len Length of the buffer in bytes.
*
* @see ``ESP_LOG_BUFFER_CHAR_LEVEL``
*
*/
#define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) \
do { if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {ESP_LOG_BUFFER_CHAR_LEVEL(tag, buffer, buff_len, ESP_LOG_INFO);} } while(0)
/** @cond */
/**
* @note For back compatible
* @deprecated This function is deprecated and will be removed in the future.
* Please use ESP_LOG_BUFFER_HEX
*/
// __attribute__((deprecated("Use 'ESP_LOG_BUFFER_HEX' instead")))
static inline void esp_log_buffer_hex(const char *tag, const void *buffer, uint16_t buff_len)
{
ESP_LOG_BUFFER_HEX(tag, buffer, buff_len);
}
/**
* @note For back compatible
* @deprecated This function is deprecated and will be removed in the future.
* Please use ESP_LOG_BUFFER_CHAR
*/
// __attribute__((deprecated("Use 'ESP_LOG_BUFFER_CHAR' instead")))
static inline void esp_log_buffer_char(const char *tag, const void *buffer, uint16_t buff_len)
{
ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len);
}
/** @endcond */
#endif // !BOOTLOADER_BUILD || __DOXYGEN__
#ifdef __cplusplus
}
#endif

View File

@ -1,15 +1,9 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_LOG_INTERNAL_H__
#define __ESP_LOG_INTERNAL_H__
//these functions do not check level versus ESP_LOCAL_LEVEL, this should be done in esp_log.h
void esp_log_buffer_hex_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level);
void esp_log_buffer_char_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t level);
void esp_log_buffer_hexdump_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level);
#endif
#pragma once
#warning "esp_log_internal.h is deprecated, please migrate to esp_log_buffer.h"
#include "esp_log_buffer.h"

View File

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Log level
*/
typedef enum {
ESP_LOG_NONE = 0, /*!< No log output */
ESP_LOG_ERROR = 1, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN = 2, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO = 3, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG = 4, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE = 5, /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
ESP_LOG_MAX = 6, /*!< Number of levels supported */
} esp_log_level_t;
/** @cond */
#ifndef LOG_LOCAL_LEVEL
#ifndef BOOTLOADER_BUILD
#define LOG_LOCAL_LEVEL CONFIG_LOG_MAXIMUM_LEVEL
#else
#define LOG_LOCAL_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL
#endif
#endif
/** @endcond */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Convert an unsigned integer value to a string representation in the specified radix.
*
* This function converts the given unsigned integer value to a string representation in the specified radix.
* The resulting string is stored in the provided character buffer `buf`.
*
* @param val The unsigned integer value to be converted.
* @param buf Pointer to the character buffer where the resulting string will be stored.
* The buffer must have enough space to accommodate the entire converted string,
* including the null-terminator.
* @param radix The base of the numeral system to be used for the conversion.
* It determines the number of unique digits in the numeral system
* (e.g., 2 for binary, 10 for decimal, 16 for hexadecimal).
* @param digits Pointer to a character array representing the digits of the numeral system.
* The array must contain characters in the order of increasing values,
* corresponding to the digits of the radix. For example, "0123456789ABCDEF" for hexadecimal.
*
* @return The length of the resulting string (excluding the null-terminator).
*
* @note The buffer `buf` must have sufficient space to hold the entire converted string, including the null-terminator.
* The caller is responsible for ensuring the buffer's size is large enough to prevent buffer overflow.
* @note The provided `digits` array must have enough elements to cover the entire radix used for conversion. Otherwise, undefined behavior may occur.
*/
int esp_log_util_cvt(unsigned long long val, char *buf, long radix, const char *digits);
/**
* @brief Convert an unsigned integer to a hexadecimal string with optional padding.
*
* This function converts an unsigned integer value to a hexadecimal string representation.
* This function calls esp_log_util_cvt(val, buf, 16, pad, "0123456789abcdef") inside.
*
* @param val The unsigned integer value to be converted.
* @param pad The optional padding width for the resulting string.
* @param buf The buffer to store the hexadecimal string.
* @return The length of the converted string.
*/
int esp_log_util_cvt_hex(unsigned long long val, int pad, char *buf);
/**
* @brief Convert an unsigned integer to a decimal string with optional padding.
*
* This function converts an unsigned integer value to a decimal string representation.
* This function calls esp_log_util_cvt(val, buf, 10, pad, "0123456789") inside.
*
* @param val The unsigned integer value to be converted.
* @param pad The optional padding width for the resulting string.
* @param buf The buffer to store the decimal string.
* @return The length of the converted string.
*/
int esp_log_util_cvt_dec(unsigned long long val, int pad, char *buf);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

58
components/log/src/util.c Normal file
View File

@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
int esp_log_util_cvt(unsigned long long val, char *buf, long radix, int pad, const char *digits)
{
#ifdef SUPPORT_LITTLE_RADIX
char temp[64];
#else
char temp[32];
#endif
char *buf_or = buf;
char *cp = temp;
int length = 0;
if (val == 0) {
/* Special case */
*cp++ = '0';
} else {
while (val) {
*cp++ = digits[val % radix];
val /= radix;
}
}
while (cp != temp) {
*buf++ = *--cp;
length++;
}
*buf = '\0';
if (length < pad) {
pad = pad - length;
int i = 0;
while (pad-- > 0) {
temp[i] = buf_or[i];
buf_or[i] = '0';
i++;
length++;
}
for (int k = 0; k < i; k++) {
buf_or[i + k] = temp[k];
}
}
return (length);
}
int esp_log_util_cvt_hex(unsigned long long val, int pad, char *buf)
{
return esp_log_util_cvt(val, buf, 16, pad, "0123456789abcdef");
}
int esp_log_util_cvt_dec(unsigned long long val, int pad, char *buf)
{
return esp_log_util_cvt(val, buf, 10, pad, "0123456789");
}

View File

@ -267,6 +267,8 @@ INPUT = \
$(PROJECT_PATH)/components/ieee802154/include/esp_ieee802154_types.h \
$(PROJECT_PATH)/components/ieee802154/include/esp_ieee802154.h \
$(PROJECT_PATH)/components/log/include/esp_log.h \
$(PROJECT_PATH)/components/log/include/esp_log_level.h \
$(PROJECT_PATH)/components/log/include/esp_log_buffer.h \
$(PROJECT_PATH)/components/lwip/include/apps/esp_sntp.h \
$(PROJECT_PATH)/components/lwip/include/apps/ping/ping_sock.h \
$(PROJECT_PATH)/components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h \

View File

@ -135,3 +135,5 @@ API Reference
-------------
.. include-build-file:: inc/esp_log.inc
.. include-build-file:: inc/esp_log_level.inc
.. include-build-file:: inc/esp_log_buffer.inc