Monitoring APIs

Heap Monitor

The heap monitor provides some simple utilities for monitoring and printing out the state of the heap memory in the system. It uses various heap_caps_get_* functions to provide information about a memory region specified by a bitmask of capabilities defining the region:

  • minimum free bytes: The minimum free bytes available in the region over the lifetime of the region.

  • free bytes: The current number of free bytes available in the region.

  • allocated bytes: The current number of allocated bytes in the region.

  • largest free block: The size of the current largest free block (in bytes) in the region. Any mallocs over the size will fail.

  • total size: The size (in bytes) of the memory region.

It provides some utilities for formatting the output as single line output, CSV output, or a nice table.

Finally, the class provides some static methods for some common use cases to quickly get the available memory for various regions as well as easily format them into csv/table output.

Code examples for the monitor API are provided in the monitor example folder.

Heap Monitor API Reference

Header File

Classes

class HeapMonitor : public espp::BaseComponent

HeapMonitor class This class provides functionality to monitor and report heap memory usage in ESP32 systems. It can be used to get information about different heap regions based on their flags (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.).

It provides methods to retrieve heap information, format it as a string, and log it. The class can be configured with specific heap flags and a name for the monitor.

Heap Monitor Example

    // test a single monitor
    {
      espp::HeapMonitor hm({});
      auto info = hm.get_info();
      fmt::print("Heap Monitor Info (single line 's', default):\n");
      fmt::print("{}\n", info);
      // should be the exact same as the default
      fmt::print("{:s}\n", info);
    }

    std::vector<int> heap_caps = {MALLOC_CAP_DEFAULT, MALLOC_CAP_INTERNAL, MALLOC_CAP_SPIRAM,
                                  MALLOC_CAP_DMA};

    // now test multiple monitors
    {
      std::vector<espp::HeapMonitor> heap_monitors;
      for (const auto &heap_cap : heap_caps) {
        // cppcheck-suppress useStlAlgorithm
        heap_monitors.push_back(espp::HeapMonitor({.heap_flags = heap_cap}));
      }
      // print a table with all the monitors
      fmt::print("Heap Monitor Info (table 't'):\n");
      fmt::print("{}\n", espp::HeapMonitor::get_table_header());
      for (const auto &hm : heap_monitors) {
        auto info = hm.get_info();
        fmt::print("{:t}\n", info);
      }
      // print a csv with all the monitors
      fmt::print("Heap Monitor Info (csv 'c'):\n");
      fmt::print("{}\n", espp::HeapMonitor::get_csv_header());
      for (const auto &hm : heap_monitors) {
        auto info = hm.get_info();
        fmt::print("{:c}\n", info);
      }
    }

    // Print a table with the static API
    fmt::print("Heap monitor table:\n");
    fmt::print("{}\n", espp::HeapMonitor::get_table(heap_caps));
    // Print a CSV with the static API
    fmt::print("Heap monitor CSV:\n");
    fmt::print("{}\n", espp::HeapMonitor::get_csv(heap_caps));

Public Functions

inline explicit HeapMonitor(const Config &config)

Constructor.

Parameters:

config – Configuration for heap monitor

inline HeapInfo get_info() const

Get heap info for the configured heap region.

Returns:

HeapInfo structure with heap information

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

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

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

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

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

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

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Functions

static std::string get_region_name(int heap_flags)

Get the name of the heap region based on the heap flags.

Parameters:

heap_flags – Heap region flags bitmask (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

Returns:

Name of the heap region as a string

static HeapInfo get_info(int heap_flags)

Get heap info for a specific heap region.

Parameters:

heap_flags – Heap region flags bitmask (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

Returns:

HeapInfo structure with heap information

static std::vector<HeapInfo> get_info(const std::vector<int> &heap_flags)

Get heap info for a specific heap region.

Parameters:

heap_flags – Vector of heap region flags bitmasks (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

Returns:

Vector of HeapInfo structures with heap information for each region

static inline const std::string get_csv_header()

Get the header for the CSV output.

Returns:

CSV header string

static inline const std::string get_table_header()

Get the header for the table output.

Returns:

Table header string

static std::string get_table(const std::vector<int> &heap_flags)

Get a string representation of the heap info in table format.

Parameters:

heap_flags – Heap region flags bitmask(s) (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

Returns:

Table string representation of the heap info, each line representing a heap region (entry in heap_flags vector)

static std::string get_csv(const std::vector<int> &heap_flags)

Get a string representation of the heap info in CSV format.

Parameters:

heap_flags – Heap region flags bitmask(s) (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

Returns:

CSV string representation of the heap info, each line representing a heap region (entry in heap_flags vector)

struct Config

Configuration for HeapMonitor.

Public Members

int heap_flags = MALLOC_CAP_DEFAULT

Heap region flags bitmask (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

std::string_view name = "HeapMonitor"

Name of the heap monitor.

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::INFO

Log level for heap info.

struct HeapInfo

Info about a heap region.

Public Members

int heap_flags

Heap region flags bitmask (e.g., MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL, etc.)

size_t free_bytes

Total free heap in bytes.

size_t min_free_bytes

Minimum free heap in bytes.

size_t largest_free_block

Largest free block in bytes.

size_t allocated_bytes

Total allocated heap in bytes.

size_t total_size

Total heap size in bytes.

Task Monitor

The task monitor provides the ability to use the FreeRTOS trace facility to output information about the CPU utilization (%), stack high water mark (bytes), and priority of all the tasks running on the system.

There is an associated task-monitor python gui which can parse the output of this component and render it as a chart or into a table for visualization.

Code examples for the monitor API are provided in the monitor example folder.

Task Monitor API Reference

Header File

Classes

class TaskMonitor : public espp::BaseComponent

Class which monitors the currently running tasks in the system and periodically logs their states. See also FreeRTOS::vTaskGetInfo().

Basic Task Monitor Example

    // create the monitor
    espp::TaskMonitor tm({.period = 500ms});
    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(5s);

get_latest_info_vector() Example

    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(1s);
    auto task_info = espp::TaskMonitor::get_latest_info_vector();
    for (const auto &info : task_info) {
      fmt::print("{}\n", info);
    }

get_latest_info_*() Example

    // create threads
    auto start = std::chrono::high_resolution_clock::now();
    auto task_fn = [&start](int task_id, auto &, auto &, auto &) {
      auto now = std::chrono::high_resolution_clock::now();
      auto seconds_since_start = std::chrono::duration<float>(now - start).count();
      // do some work
      float x = 2.0f * M_PI * sin(exp(task_id) * seconds_since_start);
      // sleep
      std::this_thread::sleep_for((10ms * std::abs(x)) + 1ms);
      // don't want to stop the task
      return false;
    };
    std::vector<std::unique_ptr<espp::Task>> tasks;
    size_t num_tasks = 10;
    tasks.resize(num_tasks);
    for (size_t i = 0; i < num_tasks; i++) {
      std::string task_name = fmt::format("Task {}", i);
      auto task = espp::Task::make_unique(
          {.callback = std::bind(task_fn, i, _1, _2, _3),
           .task_config = {.name = task_name, .stack_size_bytes = 5 * 1024}});
      tasks[i] = std::move(task);
      tasks[i]->start();
    }
    // now sleep for a while to let the monitor do its thing
    std::this_thread::sleep_for(1s);
    // single line string
    fmt::print("Task Monitor Info (single line):\n");
    fmt::print("{}\n", espp::TaskMonitor::get_latest_info_string());
    // pretty table
    fmt::print("Task Monitor Info (pretty table):\n");
    auto task_table = espp::TaskMonitor::get_latest_info_table();
    std::cout << task_table << std::endl;

Note

you must enable CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS for this class to do anything. This means that you can always instantiate this class in your app_main, and then based on those two config settings it will either do nothing (default) or print out the stats for you to analyze. Finally, the monitoring period can be configured as well.

Note

If you wish to also get the core id of the task, you must enable CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID. If you do not enable this option, the core id will be -2.

Public Functions

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

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

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

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

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

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

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Functions

static inline std::vector<TaskInfo> get_latest_info_vector()

Get information about all the tasks running. Will provide for each task the following information: * name * % CPU run time the task has used * stack high water mark (bytes) * current priority of the task.

Returns:

std::vector<TaskInfo> vector containing info for each task.

static inline std::string get_latest_info_string()

Get information about all the tasks running. Will provide for each task the following information: * name * % CPU run time the task has used * stack high water mark (bytes) * current priority of the task * core the task is running on.

Where each entry is separated by ‘,’ and each set of task data is separated by ‘;’.

This is a static function, so it can be called without having to instantiate a TaskMonitor object.

name, cpu%, high_water_mark, priority, core_id;;

Note

There is no newline returned.

Note

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a single line string separated by , and ;.

Returns:

std::string containing sequence of entries, formatted:

static inline auto get_latest_info_table()

Print the latest task information in a nice table format. This is a static function, so it can be called without having to instantiate a TaskMonitor object.

Note

This function calls TaskMonitor::get_latest_info_vector() and then formats the data into a table using the libfmt library.

Returns:

A string containing the information in a table format.

struct Config

Config structure for TaskMonitor object.

Public Members

std::chrono::duration<float> period

Period (s) the TaskMonitor::task_callback runs at.

size_t task_stack_size_bytes{8 * 1024}

Stack size (B) allocated to the TaskMonitor::task_callback.

struct TaskInfo

Info structure for each task monitored.

Public Members

std::string name

Name of the task.

uint32_t cpu_percent

% CPU run time the task has used.

uint32_t high_water_mark

Stack high water mark (bytes).

uint32_t priority

Current priority of the task.

int core_id

Core the task is running on. Will be 0,1, or -1 if task is not pinned to a core. Only valid if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set to y, otherwise will be -2.

Monitor Service

The MonitorService class serves the heap-region and task statistics above over any byte stream as a dispatcher module (espp.monitor v1, module id 8 by default; Config::module moves an instance and hosts find it through discovery by its protocol id). GET_HEAP answers with one record per configured heap region (Config::heap_regions, MALLOC_CAP_* masks; regions the chip does not have are left out), GET_TASKS with the TaskMonitor table (name, CPU %, stack high-water mark, priority, core — it needs CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS, else the list is empty; both replies are capped so the whole frame fits Config::max_frame_bytes, 4096 by default, regions / tasks beyond it being dropped from the end), and SET_STREAM starts a task that sends either or both periodically so a host can plot them live. Replies echo the request frame’s correlation id so a host can pair them and drop stale ones (streamed events carry none). The wire codec (detail/monitor_protocol.hpp) is host-buildable and unit-tested (test/monitor_host_test.cpp). The hosted espp System Console web app renders the heap gauges and a live task table; see the system component’s example, which exposes both services over USB.

espp System Console streaming the task table from MonitorService (name, CPU %, stack high-water mark, priority, core)

Monitor Service API Reference

Header File

Classes

class MonitorService : public espp::BaseComponent

Serves heap-region and task statistics over any framed byte stream (dispatcher module 8 by default; see Config::module).

GET_HEAP answers with one record per configured heap region (Config::heap_regions, MALLOC_CAP_* masks; regions that do not exist on the chip, i.e. report a total size of 0, are left out). GET_TASKS answers with espp::TaskMonitor’s per-task table (name, CPU %, stack high-water mark, priority, core); it needs CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS &#8212; without them the list is empty (logged once), never an error. A TASKS payload is capped at the frame payload limit: tasks that do not fit are dropped from the end (logged). SET_STREAM starts (or stops) a task that sends HEAP and / or TASKS events periodically (period clamped to Config::min_stream_period), so a host can plot them live without polling.

**Threading**: an internal mutex covers the parser and request handling; every outbound frame (replies and streamed events alike) is serialized on a send mutex held across the `send` callback, so frames never interleave and `send` never runs concurrently with itself. `send` must therefore not re-enter this object.

MonitorService Example

  // Boot banner: everything SystemInfo knows, in one string.
  logger.info("System:\n{}", espp::SystemInfo::to_string());
  logger.info("Reboot into the bootloader is {} on this chip",
              espp::SystemControl::bootloader_reboot_supported() ? "supported" : "NOT supported");

  // The OTA and core-dump engines, shared by the per-transport services below.
  // A panic core-dumps to the `coredump` partition (sdkconfig / partitions.csv)
  // and is reported here on the next boot; the coredump console downloads /
  // erases it. OTA alternates between ota_0 / ota_1 with host-driven rollback
  // confirmation, exactly as the ota example does.
  espp::CoreDump core_dump({.log_level = espp::Logger::Verbosity::INFO});
  const std::string crash_report = core_dump.format_report();
  if (crash_report.empty())
    logger.info("Clean boot history (reset reason: {})",
                espp::CoreDump::reset_reason_name(espp::CoreDump::reset_reason()));
  else
    logger.error("Previous abnormal reset:\n{}", crash_report);
  espp::Ota ota({.reject_same_version = false, .log_level = espp::Logger::Verbosity::INFO});
  if (ota.is_pending_verify())
    logger.warn("This image is PENDING VERIFY (first boot after an OTA update): it rolls back on "
                "the next reset unless the host confirms it (MARK_VALID from the OTA console)");

  // USB composite device: a vendor/WebUSB function and a CDC function, both
  // carrying the same framed protocol.
  espp::UsbDevice::Config usb_cfg;
  usb_cfg.pid = 0x0d37; // distinct from the espp default so the webapp filter is specific
  usb_cfg.manufacturer = "espp";
  usb_cfg.product = "espp System";
  usb_cfg.log_level = espp::Logger::Verbosity::WARN;
  espp::UsbDevice::CdcFunction cdc;
  cdc.interface_name = "espp System (CDC)";
  usb_cfg.cdc = cdc;
  espp::UsbDevice::VendorFunction vendor;
  vendor.interface_name = "espp System (WebUSB)";
  vendor.webusb = true; // advertise BOS / WebUSB / MS OS 2.0 descriptors
  vendor.landing_page_url = "esp-cpp.github.io/espp/apps/system_console.html";
  usb_cfg.vendor = vendor;
  espp::UsbDevice usb(usb_cfg);

  // Replies go back on the stream the request came in on: one send function
  // per transport. Both services share each transport and only serialize
  // their OWN frames (a streamed monitor event and a system reply come from
  // different tasks), so every device->host write on a transport goes through
  // one application-level mutex; write_vendor / write_cdc are all-or-nothing
  // per call, so a frame is never truncated or interleaved.
  std::mutex vendor_tx_mutex, cdc_tx_mutex;
  auto vendor_send = [&](std::span<const uint8_t> frame) {
    std::lock_guard<std::mutex> lock(vendor_tx_mutex);
    usb.write_vendor(frame);
  };
  auto cdc_send = [&](std::span<const uint8_t> frame) {
    std::lock_guard<std::mutex> lock(cdc_tx_mutex);
    usb.write_cdc(frame);
  };

  // The application decides whether a reboot may happen right now: this demo
  // permits every request and logs it. A real application would refuse (or
  // defer) while, say, a motor is running or a file is being written.
  auto reboot_request = [&](espp::SystemService::RebootKind kind) {
    logger.warn("Host requested a {}; allowing it",
                kind == espp::SystemService::RebootKind::Bootloader ? "reboot into the bootloader"
                                                                    : "reboot");
    return true;
  };

  // One service instance per transport (they are cheap; each replies on its
  // own stream). Declared BEFORE the workers that call into them.
  espp::SystemService vendor_system({.send = vendor_send,
                                     .on_reboot_request = reboot_request,
                                     .log_level = espp::Logger::Verbosity::INFO});
  espp::SystemService cdc_system({.send = cdc_send,
                                  .on_reboot_request = reboot_request,
                                  .log_level = espp::Logger::Verbosity::INFO});
  espp::MonitorService vendor_monitor(
      {.send = vendor_send,
       .task_config = {.name = "monitor_v", .stack_size_bytes = 6 * 1024},
       .log_level = espp::Logger::Verbosity::INFO});
  espp::MonitorService cdc_monitor(
      {.send = cdc_send,
       .task_config = {.name = "monitor_c", .stack_size_bytes = 6 * 1024},
       .log_level = espp::Logger::Verbosity::INFO});
  // OTA and core dump: one service per transport over the shared engines (each
  // OtaService only touches the session IT began, so the two cannot interfere).
  espp::OtaService vendor_ota(ota,
                              {.send = vendor_send, .log_level = espp::Logger::Verbosity::INFO});
  espp::OtaService cdc_ota(ota, {.send = cdc_send, .log_level = espp::Logger::Verbosity::INFO});
  espp::CoreDumpService vendor_coredump(
      core_dump, {.send = vendor_send, .log_level = espp::Logger::Verbosity::INFO});
  espp::CoreDumpService cdc_coredump(
      core_dump, {.send = cdc_send, .log_level = espp::Logger::Verbosity::INFO});

  // One DispatcherWorker per byte stream: a bounded receive queue + worker
  // task feeding its Dispatcher, so the services never run on the TinyUSB
  // task. Registering a service routes its module to it and advertises it for
  // discovery; serve_discovery() answers the hub's ListModules query.
  // On an RX overflow the OTA service aborts a transfer it owned and tells the
  // host (an OTA image with dropped bytes is unusable).
  espp::DispatcherWorker vendor_link(
      {.send = vendor_send,
       .on_overflow = [&]() { vendor_ota.on_rx_overflow(); },
       .task_config = {.name = "system_rx_vendor", .stack_size_bytes = 8192}});
  espp::DispatcherWorker cdc_link(
      {.send = cdc_send,
       .on_overflow = [&]() { cdc_ota.on_rx_overflow(); },
       .task_config = {.name = "system_rx_cdc", .stack_size_bytes = 8192}});
  vendor_link.register_module(vendor_system);
  vendor_link.register_module(vendor_monitor);
  vendor_link.register_module(vendor_ota);
  vendor_link.register_module(vendor_coredump);
  cdc_link.register_module(cdc_system);
  cdc_link.register_module(cdc_monitor);
  cdc_link.register_module(cdc_ota);
  cdc_link.register_module(cdc_coredump);
  vendor_link.serve_discovery(usb_cfg.product);
  cdc_link.serve_discovery(usb_cfg.product);

Public Types

using send_fn = std::function<void(std::span<const uint8_t> frame)>

Transmits one encoded frame to the host.

Public Functions

inline explicit MonitorService(const Config &config)

Construct the service.

inline uint8_t module_id() const

The dispatcher module id this service answers on (Config::module).

inline Dispatcher::ModuleInfo module_info() const

Discovery metadata for registering this service on a Dispatcher.

inline bool streaming() const

Whether periodic HEAP / TASKS events are being sent.

inline void stop_stream()

Stop streaming (also done by the destructor and by SET_STREAM 0).

inline void handle(const espp::stream_frame::Frame &frame)

Dispatcher entry point: handle one routed frame. Frames for other modules and reply-flagged frames are ignored, so this can be registered directly: `dispatcher.register_module(service)`.

inline void feed(std::span<const uint8_t> data)

Feed received transport bytes (standalone use, without a Dispatcher).

inline void reset_parser()

Discard any partially-buffered frame bytes (standalone feed() use).

inline bool handle_frame(uint8_t type, std::span<const uint8_t> payload, std::optional<uint16_t> correlation = std::nullopt)

Handle one already-parsed request frame.

Parameters:

correlation – The request frame’s correlation id, if it carried one; every reply echoes it (streamed events carry none).

Returns:

true if the type belongs to the monitor protocol (a reply was sent), false if it was ignored.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

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

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

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

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

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

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Attributes

static constexpr uint8_t kModule = espp::detail::monitor_protocol::kModule

Default dispatcher module id (8). A routing key only: Config::module serves on any id, and hosts find it through discovery (by kProtocol).

static constexpr const char *kProtocol = espp::detail::monitor_protocol::kProtocol

Stable protocol identifier + version advertised through discovery.

struct Config

Configuration for the MonitorService.

Public Members

send_fn send = {nullptr}

Transmits an encoded frame (required).

uint8_t module = {kModule}

Dispatcher module id this instance answers on (and stamps on every frame it sends). A routing key only (0x00..0xEF).

std::vector<int> heap_regions = {MALLOC_CAP_DEFAULT, MALLOC_CAP_INTERNAL, MALLOC_CAP_SPIRAM}

Heap regions reported, as MALLOC_CAP_* masks (HeapMonitor::get_info).

std::chrono::milliseconds min_stream_period = {100}

Shortest streaming period a host may request (SET_STREAM is clamped to it).

size_t max_frame_bytes = {4096}

Largest encoded frame (header + payload + CRC) `send` can carry in one write: the HEAP and TASKS payloads are capped so the whole frame fits (regions / tasks that do not fit are dropped from the end, logged). 4096 matches the default TinyUSB vendor / CDC TX FIFO of the espp examples; the stream_frame maximum is kMaxFrameSize (4111).

Task::BaseConfig task_config   = {.name = "monitor_stream", .stack_size_bytes = 6 * 1024}

The streaming task (started on the first SET_STREAM enable).

espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}

Logger verbosity.