Class LogManager

Class Documentation

class LogManager

Manages /rosout log collection via the default ring-buffer backend.

Subscribes to /rosout, normalizes logger names (strips leading ‘/’), and stores entries per node-name in fixed-size deque ring buffers.

Plugin integration (two modes):

  • Observer mode (default): If a LogProvider plugin is registered, get_logs() and get_config() delegate to it. on_log_entry() is called on ALL LogProvider observers for every /rosout message. Observers returning true suppress ring-buffer storage.

  • Full ingestion (manages_ingestion() == true): The primary LogProvider owns the entire log pipeline. LogManager skips the /rosout subscription and ring buffer entirely. All queries and config operations delegate to the plugin.

FQN normalization:

  • entity.fqn from the entity cache has a leading ‘/’ (e.g. “/powertrain/engine/temp_sensor”)

  • /rosout msg.name does NOT have a leading ‘/’ (rcl_node_get_logger_name convention)

  • Callers pass raw FQNs from entity.fqn; LogManager strips leading ‘/’ internally.

Public Types

using NodeToEntityFn = std::function<std::string(const std::string&)>

Callback that maps a ROS 2 node FQN to a manifest entity ID. Returns empty string if the FQN cannot be resolved.

Public Functions

explicit LogManager(rclcpp::Node *node, PluginManager *plugin_mgr = nullptr, size_t max_buffer_size = kDefaultBufferSize)

Construct LogManager.

If the primary LogProvider’s manages_ingestion() returns true, the /rosout subscription and ring buffer are skipped entirely. Otherwise subscribes to /rosout as usual.

Parameters:
  • node – ROS 2 node (used for subscription and logging)

  • plugin_mgrPluginManager for LogProvider lookup (may be nullptr)

  • max_buffer_size – Ring buffer size per node (override for unit testing)

~LogManager()
tl::expected<json, std::string> get_logs(const std::vector<std::string> &node_fqns, bool prefix_match, const std::string &min_severity, const std::string &context_filter, const std::string &entity_id)

Query log entries for a set of node FQNs.

If a LogProvider plugin is registered, delegates to it. Otherwise uses the local ring buffer.

Parameters:
  • node_fqns – Node FQNs from entity.fqn (WITH leading ‘/’ — normalized internally)

  • prefix_match – If true, match all buffered nodes whose name starts with the given prefix (used for Component queries). If false, exact match (App queries).

  • min_severity – Additional severity filter from query parameter. Empty = no override.

  • context_filter – Substring filter applied to log entry’s name (logger name). Empty = no filter.

  • entity_id – Entity ID for config lookup. Empty = use defaults.

Returns:

JSON array of LogEntry objects sorted by id ascending, capped at entity config max_entries.

tl::expected<LogConfig, std::string> get_config(const std::string &entity_id) const

Get current log configuration for entity (returns defaults if unconfigured)

std::string update_config(const std::string &entity_id, const std::optional<std::string> &severity_filter, const std::optional<size_t> &max_entries)

Update log configuration for an entity.

Returns:

Empty string on success, error message on validation failure

void add_log_entry(const std::string &entity_id, const std::string &severity, const std::string &message, const nlohmann::json &metadata)

Programmatically add a log entry (e.g. from trigger log_settings)

Creates a LogEntry and pushes it to the internal ring buffer using the same path as on_rosout(). If a ResourceChangeNotifier is set, emits a “logs” CREATED notification so triggers can observe log changes.

Parameters:
  • entity_id – Entity to associate the log with (used as logger name)

  • severity – SOVD severity string (debug, info, warning, error, fatal)

  • message – Human-readable log message

  • metadata – Additional JSON metadata stored in the message (appended)

void set_notifier(ResourceChangeNotifier *notifier)

Set the ResourceChangeNotifier for emitting log change events. Called by GatewayNode after both LogManager and the notifier are available.

void set_node_to_entity_resolver(NodeToEntityFn resolver)

Set the node-to-entity resolver for trigger notifications. When set, on_rosout() resolves node names to manifest entity IDs before notifying the ResourceChangeNotifier.

void inject_entry_for_testing(LogEntry entry)

Inject a log entry directly into the ring buffer (bypasses /rosout subscription)

Used by unit tests to populate the buffer without a live ROS 2 graph. In production the buffer is populated exclusively by the /rosout callback.

Public Static Functions

static std::string level_to_severity(uint8_t level)

Convert ROS 2 uint8 log level -> SOVD severity string (“debug” for unknown levels)

static uint8_t severity_to_level(const std::string &severity)

Convert SOVD severity string -> ROS 2 uint8 log level (0 for invalid/empty)

static bool is_valid_severity(const std::string &severity)

Check if a severity string is valid (one of: debug, info, warning, error, fatal)

static json entry_to_json(const LogEntry &entry)

Format a LogEntry as SOVD JSON (id, timestamp, severity, message, context)

static std::string normalize_fqn(const std::string &fqn)

Strip leading ‘/’ from a node FQN for ring-buffer key normalization.

Public Static Attributes

static constexpr size_t kDefaultBufferSize = 200

Default maximum number of entries retained per node in the ring buffer.