Logging APIs

Format

Format is a simple component which exposes libfmt for use within esp-idf as a single include.

Logger

The logger provides a cross-platform wrapper around libfmt for providing configurable log output with different levels that can be turned on / off at runtime.

Code examples for the logging API are provided in the logger example folder.

API Reference

Header File

Macros

ESPP_LOGGER_LOG_LEVEL_NONE
ESPP_LOGGER_LOG_LEVEL_ERROR
ESPP_LOGGER_LOG_LEVEL_WARN
ESPP_LOGGER_LOG_LEVEL_INFO
ESPP_LOGGER_LOG_LEVEL_DEBUG
CONFIG_ESPP_LOGGER_LOG_LEVEL
ESPP_LOGGER_DEBUG_ENABLED
ESPP_LOGGER_INFO_ENABLED
ESPP_LOGGER_WARN_ENABLED
ESPP_LOGGER_ERROR_ENABLED
ESPP_LOGGER_CURSOR_COMMANDS_ENABLED

Classes

class Logger

Logger provides a wrapper around nicer / more robust formatting than standard ESP_LOG* macros with the ability to change the log level at run-time. Logger currently is a light wrapper around libfmt (future std::format).

To save on code size, the logger has the ability to be compiled out based on the log level set in the sdkconfig. This means that if the log level is set to ERROR, all debug, info, and warn logs will be compiled out. This is done by checking the log level at compile time and only compiling in the functions that are needed.

The logger can also be compiled with support for cursor commands. This allows the logger to move the cursor up, down, clear the line, clear the screen, and move the cursor to a specific position. This can be useful for creating various types of interactive output or to maintian context with long-running logs.

Basic Example

    float num_seconds_to_run = 10.0f;
    // create loggers
    auto logger = espp::Logger({.tag = "Cool Logger", .level = espp::Logger::Verbosity::DEBUG});
    auto start = std::chrono::high_resolution_clock::now();
    auto now = std::chrono::high_resolution_clock::now();
    float elapsed = std::chrono::duration<float>(now - start).count();
    while (elapsed < num_seconds_to_run) {
      now = std::chrono::high_resolution_clock::now();
      elapsed = std::chrono::duration<float>(now - start).count();
      auto remaining = num_seconds_to_run - elapsed;
      logger.debug("debug: {:%Y-%m-%d %H:%M:%S} - {:%Y-%m-%d %H:%M:%S} = {}", now, start, elapsed);
      logger.info("elapsed: {:.3f}s", elapsed);
      logger.warn("remaining: {:.3f}s", remaining);
      if (remaining < 0) {
        logger.error("You overstayed your welcome by {:.03}s!", -remaining);
      }
      std::this_thread::sleep_for(500ms);
    }

Threaded Logging and Verbosity Example

    // create loggers
    auto logger1 = espp::Logger(
        {.tag = "Thread 1", .rate_limit = 500ms, .level = espp::Logger::Verbosity::INFO});
    auto logger2 = espp::Logger(
        {.tag = "Thread 2", .rate_limit = 1s, .level = espp::Logger::Verbosity::DEBUG});
    // lambda for logging to those two loggers from multiple threads
    auto logger_fn = [](espp::Logger *logger) {
      size_t loop_iteration{0};
      while (true) {
        // log - note: debug shouldn't be shown!
        logger->debug("some debug info: {}", loop_iteration);
        logger->info("some info: {}", loop_iteration);
        logger->warn("some warning: {}", loop_iteration);
        logger->error("some error: {}", loop_iteration);
        logger->info_rate_limited("some rate limited info: {}", loop_iteration);
        // update loop variables
        loop_iteration++;
        // sleep
        std::this_thread::sleep_for(300ms);
      }
    };
    // start two threads, binding the lambda to each logger
    auto logger1_thread = std::thread(std::bind(logger_fn, &logger1));
    auto logger2_thread = std::thread(std::bind(logger_fn, &logger2));
    uint8_t level{static_cast<uint8_t>(espp::Logger::Verbosity::DEBUG)};
    // every 1 second, change the loggers' verbosity
    while (true) {
      // update the loggers' verbosity
      level++;
      if (level > static_cast<uint8_t>(espp::Logger::Verbosity::NONE)) {
        level = static_cast<uint8_t>(espp::Logger::Verbosity::DEBUG);
      }
      espp::Logger::Verbosity verbosity = static_cast<espp::Logger::Verbosity>(level);
      logger1.set_verbosity(verbosity);
      logger2.set_verbosity(verbosity);
      // sleep
      std::this_thread::sleep_for(1s);
    }

Cursor Commands Example

    float num_seconds_to_run = 10.0f;
    // create loggers
    auto logger = espp::Logger({.tag = "Cursor Commands", .level = espp::Logger::Verbosity::DEBUG});
    auto start = std::chrono::high_resolution_clock::now();
    auto now = std::chrono::high_resolution_clock::now();
    float elapsed = std::chrono::duration<float>(now - start).count();
    logger.info("Long running log... {}", elapsed);
    while (elapsed < num_seconds_to_run) {
      now = std::chrono::high_resolution_clock::now();
      elapsed = std::chrono::duration<float>(now - start).count();
      auto remaining = num_seconds_to_run - elapsed;
      logger.move_up();
      logger.clear_line();
      logger.info("Long running log... {}", remaining);
      std::this_thread::sleep_for(100ms);
    }

Public Types

enum class Verbosity

Verbosity levels for the logger, in order of increasing priority.

Values:

enumerator DEBUG

Debug level verbosity.

enumerator INFO

Info level verbosity.

enumerator WARN

Warn level verbosity.

enumerator ERROR

Error level verbosity.

enumerator NONE

No verbosity - logger will not print anything.

Public Functions

inline explicit Logger(const Config &config)

Construct a new Logger object.

Parameters

config – configuration for the logger.

inline espp::Logger::Verbosity get_verbosity() const

Get the current verbosity for the logger.

Returns

The current verbosity level.

inline void set_verbosity(const espp::Logger::Verbosity level)

Change the verbosity for the logger.

Parameters

level – new verbosity level

inline void set_tag(const std::string_view tag)

Change the tag for the logger.

Parameters

tag – The new tag.

inline const std::string &get_tag() const

Get the current tag for the logger.

Returns

A const reference to the current tag.

inline void set_include_time(bool include_time)

Whether to include the time in the log.

Note

The time is in seconds since boot and is represented as a floating point number with precision to the millisecond.

Parameters

include_time – Whether to include the time in the log.

inline void set_rate_limit(const std::chrono::duration<float> rate_limit)

Change the rate limit for the logger.

Note

Only calls that have _rate_limited suffixed will be rate limited.

Parameters

rate_limit – The new rate limit.

inline std::chrono::duration<float> get_rate_limit() const

Get the current rate limit for the logger.

Returns

The current rate limit.

template<typename ...Args>
inline std::string format(std::string_view rt_fmt_str, Args&&... args)

Format args into string according to format string. From: https://en.cppreference.com/w/cpp/utility/format/format.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

Returns

formatted std::string

template<typename ...Args>
inline void debug(std::string_view rt_fmt_str, Args&&... args)

Print log in GRAY if level is Verbosity::DEBUG or greater.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void info(std::string_view rt_fmt_str, Args&&... args)

Print log in GREEN if level is Verbosity::INFO or greater.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void warn(std::string_view rt_fmt_str, Args&&... args)

Print log in YELLOW if level is Verbosity::WARN or greater.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void error(std::string_view rt_fmt_str, Args&&... args)

Print log in RED if level is Verbosity::ERROR or greater.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void debug_rate_limited(std::string_view rt_fmt_str, Args&&... args)

Print log in GRAY if level is Verbosity::DEBUG or greater. This function is rate limited by the rate specified in the constructor.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void info_rate_limited(std::string_view rt_fmt_str, Args&&... args)

Print log in GREEN if level is Verbosity::INFO or greater This function is rate limited by the rate specified in the constructor.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void warn_rate_limited(std::string_view rt_fmt_str, Args&&... args)

Print log in YELLOW if level is Verbosity::WARN or greater This function is rate limited by the rate specified in the constructor.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

template<typename ...Args>
inline void error_rate_limited(std::string_view rt_fmt_str, Args&&... args)

Print log in RED if level is Verbosity::ERROR or greater This function is rate limited by the rate specified in the constructor.

Parameters
  • rt_fmt_str – format string

  • args – optional arguments passed to be formatted.

Public Static Functions

static inline void move_up()

Move the cursor up one line.

static inline void move_up(int lines)

Move the cursor up a number of lines.

Parameters

lines – The number of lines to move up.

static inline void move_down()

Move the cursor down one line.

static inline void move_down(int lines)

Move the cursor down a number of lines.

Parameters

lines – The number of lines to move down.

static inline void move_to_start()

Move the cursor to the beginning of the line.

static inline void clear_line()

Clear the line.

static inline void clear_screen()

Clear the screen and move the cursor to the top left.

static inline void move_to(int x, int y)

Move the cursor to a specific position.

Parameters
  • x – The x position to move to.

  • y – The y position to move to.

static inline std::string get_time()

Get the current time in seconds since the start of the logging system.

Returns

time in seconds since the start of the logging system.

struct Config

Configuration struct for the logger.

Public Members

std::string_view tag

The TAG that will be prepended to all logs.

bool include_time = {true}

Include the time in the log.

std::chrono::duration<float> rate_limit = std::chrono::duration<float>(0)

The rate limit for the logger. Optional, if <= 0 no rate limit.

Note

Only calls that have _rate_limited suffixed will be rate limited.

espp::Logger::Verbosity level = espp::Logger::Verbosity::WARN

The verbosity level for the logger.