ros2 / ros2/rclcpp

Add per node & component log level support

Open
#3,091 11 comments 0 reactions 1 assignee View on GitHub

@penww is already working on this.

Since Apr 2, 2026.

enhancement
Dominant language
C++
Stars
805
Forks
564
Avg merge
1d 17h
Merged PRs (30d)
27

Description

Description

This issue tracks the addition of a log_level field to NodeOptions, allowing users to set the initial log severity for a node at construction time. This enables per-component log level customization, particularly useful in component container deployments.

Motivation

In ROS 2, all nodes loaded into a component container share the same process. Prior to this change, there was no way to specify a different initial log level for individual components at load time — the only option was to set a global log level or call set_level() programmatically after construction.

This is a common need in production deployments where:

  • Different components have different verbosity requirements (e.g., a sensor driver at WARN, a planner at DEBUG).
  • Operators want to configure log levels declaratively via launch files or LoadNode service calls without modifying node source code.
  • Debugging a single component in a multi-component container should not require restarting the entire process with a global log level change.

We can see this feature has designed but not full implementation:

Expected Behavior:
  • Set component log_level with CLI:
ros2 component load /ComponentManager <PKG> <PLUGIN> --log-level debug
  • Set component log_level with launch:
def generate_launch_description():
    return LaunchDescription([ComposableNodeContainer(
        name='component_demo_container',
        namespace='',
        package='rclcpp_components',
        executable='component_container',
        composable_node_descriptions=[
            ComposableNode(
                package='<PKG>',
                plugin='<PLUGIN>',
                log_level='DEBUG',  # component log level
            ),
        ],
        arguments=['--ros-args', '--log-level', 'DEBUG'],  # container log level
    )])
Design / Implementation Considerations
NodeOptions API

A new log_level getter/setter pair is added to NodeOptions:

// Get the log level (RCUTILS_LOG_SEVERITY_* value; 0 = unset/default)
int log_level() const;

// Set the initial log level for this node
NodeOptions & log_level(int log_level);

The default value is RCUTILS_LOG_SEVERITY_UNSET (0), which preserves existing behavior — no level is applied at construction.

Node construction (node.cpp)

After the node is fully constructed, if log_level is not UNSET, the logger level is applied:

if (options.log_level() != RCUTILS_LOG_SEVERITY_UNSET) {
  node_logging_->get_logger().set_level(
    static_cast<rclcpp::Logger::Level>(options.log_level()));
}

This is intentionally applied after construction so the logger is fully initialized.

ComponentManager integration (component_manager.cpp)

When handling a LoadNode service request, the log_level field from the request is validated and forwarded to NodeOptions:

if (request->log_level != 0) {
  // Validate against known RCUTILS severity values
  options.log_level(request->log_level);
}

Invalid values (not one of DEBUG, INFO, WARN, ERROR, FATAL) throw a ComponentManagerException with a descriptive message.

Additional Information

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.