ROS Log Command Line Interface
Abstract
This REP proposes a new ros2log command-line package for ROS that provides a unified, user-friendly interface for runtime logging configuration and inspection. The ros2 log command will enable users to list, get, set, and monitor logging levels for ROS nodes, improving the debugging and diagnostic capabilities of ROS systems. This proposal consolidates and standardizes logging-related operations that are currently scattered across different tools and manual service calls.
Motivation
Currently, logging configuration in ROS from the command line is limited and inconsistent. Users must resort to verbose and error-prone manual service calls to configure logging at runtime. For example, to set a logger level, users must type:
1
ros2 service call /NodeWithLoggerService/set_logger_levels rcl_interfaces/srv/SetLoggerLevels '{levels: [{name: "NodeWithLoggerService", level: 20}, {name: "rcl", level: 10}]}'
This approach has several drawbacks:
- Poor User Experience: The command is verbose, complex, and requires knowledge of service interfaces and message structures.
- Error-Prone: Manual construction of service request messages is prone to syntax errors.
- Low Discoverability: Users may not be aware that logging services exist or how to use them.
- Inconsistent Interface: Logging operations do not follow the established pattern of having dedicated command groups like
ros2 topic,ros2 service,ros2 lifecycle, etc. - Limited Functionality: There is no built-in way to list available loggers, monitor logs in real-time, or easily inspect logging configuration.
As ROS logging is crucial for debugging and production diagnostics, a dedicated, ergonomic CLI is necessary to improve developer productivity and system maintainability. A unified ros2 log command would provide:
- Consistent CLI user experience for logging across ROS
- Reduced likelihood of errors through simplified syntax
- Improved discoverability via
ros2 log --help - Enhanced production debugging and runtime introspection capabilities
- Alignment with existing ROS CLI patterns
Specification
This REP introduces a new top-level command group ros2 log with the following subcommands:
Command Overview
| Subcommand | Description |
|---|---|
ros2 log list | List nodes that support runtime log configuration |
ros2 log levels | Show all valid log level values |
ros2 log get <node> | Retrieve the current log levels of a node |
ros2 log set <node> <level> | Set the log level of a node |
ros2 log watch [options] | Monitor and display logs in real-time |
ros2 log describe <node> | Display logger metadata for a node |
Detailed Command Specifications
ros2 log list
Lists all nodes in the ROS graph that have the logger services enabled (i.e., nodes with enable_logger_service set to true). You can see more information about Logger level configuration: externally.
Usage:
1
ros2 log list
Output Example:
1
2
3
/my_node
/another_node
/third_node
ros2 log levels
Displays all valid log severity levels supported by ROS.
Usage:
1
ros2 log levels
Output Example:
1
2
3
4
5
6
UNSET : The logger level is not set explicitly and will use the default or inherited level.
DEBUG : Debug is for pedantic information, which is useful when debugging issues.
INFO : Info is the standard informational level and is used to report expected information.
WARN : Warning is for information that may potentially cause issues or possibly unexpected behavior.
ERROR : Error is for information that this node cannot resolve.
FATAL : Information about a impending node shutdown.
Note:
The ros2 log commands accept these human-readable log level names (UNSET, DEBUG, INFO, WARN, ERROR, FATAL) as arguments, eliminating the need to use numeric integer values (0, 10, 20, 30, 40, 50) that are required when calling the underlying services directly. This improves usability and reduces errors compared to the manual service call approach.
ros2 log get <node>
Retrieves and displays the current log levels for the loggers in the specified node.
Usage:
1
2
ros2 log get <node_name> [<logger_name>]
ros2 log get --all
Arguments:
<node_name>: The fully qualified name of the node (e.g.,/my_node)<logger_name>: (Optional) The name of a specific logger to query. If not specified, all loggers in the node will be displayed.
Options:
--all, -a: Get log levels for all nodes with logger services enabled
Output Example (all loggers in a specific node):
1
2
3
4
5
6
7
Node: /my_node
Logger: my_node
Level: INFO
Logger: my_node.vision
Level: WARN
Logger: my_node.perception
Level: ERROR
Output Example (specific logger):
1
2
3
Node: /my_node
Logger: my_node.speech_recognizer
Level: WARN
Output Example (all nodes with –all option):
1
2
3
4
5
6
7
8
9
10
11
12
13
Node: /my_node
Logger: my_node
Level: INFO
Logger: my_node.vision
Level: WARN
Node: /another_node
Logger: another_node
Level: DEBUG
Node: /third_node
Logger: third_node
Level: ERROR
Error Handling:
If the node does not have the enable_logger_service option enabled, the command will display:
1
2
Error: Logger service not available for node '/my_node'.
The 'enable_logger_service' node option must be enabled for this node.
If the specified logger name does not exist in the node, the command will display:
1
Error: Logger 'nonexistent_logger' not found in node '/my_node'.
When using --all option, nodes without logger services enabled will be skipped silently, and only nodes with enabled logger services will be queried and displayed.
ros2 log set <node> <level>
Sets the log level for the logger(s) in the node.
Usage:
1
2
ros2 log set <node_name> <level> [<logger_name>]
ros2 log set --all <level>
Arguments:
<node_name>: The fully qualified name of the node (e.g.,/my_node)<level>: The log level to set (UNSET, DEBUG, INFO, WARN, ERROR, FATAL)<logger_name>: (Optional) The name of a specific logger to set. If not specified, the level will be applied to all loggers in the node.
Options:
--all, -a: Set the log level for all loggers in all nodes with logger services enabled
Examples:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Set the log level for all loggers in a node
ros2 log set /my_node DEBUG
# Set a specific logger's level
ros2 log set /my_node WARN my_node.vision
# Set another specific logger under the node
ros2 log set /my_node INFO my_node.perception
# Set all loggers in all nodes to ERROR level
ros2 log set --all ERROR
# Set all loggers in all nodes to DEBUG level (useful for system-wide debugging)
ros2 log set -a DEBUG
Error Handling:
If the service is not available, the command will provide a clear error message as described in the get command. If the specified logger name does not exist in the node, the command will display:
1
Error: Logger 'nonexistent_logger' not found in node '/my_node'.
When using --all option, nodes without logger services enabled will be skipped silently, and the command will set the specified log level for all loggers in all nodes with enabled logger services.
ros2 log watch [options]
Monitors and displays log messages in real-time by subscribing to the /rosout topic. This command provides filtering capabilities to display only relevant log messages.
Usage:
1
ros2 log watch [options]
Options:(T.B.D)
--level <level>: Show only logs at or above the specified severity level--logger <logger_name>: Filter logs by logger name--regex <pattern>: Filter log messages matching the specified regular expression pattern--no-color: Disable colorized output (default: false)--no-timestamp: Disable timestamp (default: false)--function-detail: Output function name, file, and line number (default: false)
Examples:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Watch all logs from /rosout topic
ros2 log watch
# Watch logs from a specific logger
ros2 log watch --logger my_node.perception
# Watch only ERROR and FATAL logs
ros2 log watch --level ERROR
# Watch logs containing specific text pattern
ros2 log watch --regex "sensor.*timeout"
# Combine filters: ERROR logs from specific logger matching pattern
ros2 log watch --level ERROR --logger my_node.vision --regex "camera"
Implementation Notes:
The watch command should leverage Content Filtered Topics when the underlying RMW implementation supports it, to reduce network traffic and improve performance by filtering messages at the publisher side. When Content Filtered Topics are not supported by the RMW implementation, ros2 log watch will perform client-side filtering to ensure consistent behavior across all platforms. The --regex option applies pattern matching to the message content field of the log message, allowing users to filter based on specific keywords, error codes, or message patterns.
ros2 log describe <node>
Displays comprehensive metadata about the loggers available in a node, including logger names, current levels, and effective configuration.
Usage:
1
ros2 log describe <node_name>
Arguments:
<node_name>: The fully qualified name of the node
Output Example:
1
2
3
4
5
6
7
8
9
10
Node: /my_node
Logger Service: Enabled
Available Loggers:
- my_node (INFO)
- my_node.vision (WARN)
- my_node.perception (ERROR)
- my_node.speech_recognizer (INFO)
Total Loggers: 4
Service Requirements
All commands that interact with node logger configuration (get, set, describe) require that the target node has the enable_logger_service node option set to true.
The logger services are:
<node_name>/get_logger_levels(rcl_interfaces/srv/GetLoggerLevels)<node_name>/set_logger_levels(rcl_interfaces/srv/SetLoggerLevels)
By default, these services are disabled in nodes. Developers must explicitly enable them when creating nodes, see more details for Logger level configuration: externally.
Rationale
Why a New Top-Level Command Group?
Several design alternatives were considered:
- Adding to
ros2 nodecommand: Initially proposed in this approach was rejected because:- It creates inconsistency where setting is done via
ros2 node logbut getting requiresros2 service - Logging is a cross-cutting concern that applies to multiple loggers, not just the node itself
- The
ros2 nodenamespace is already focused on node lifecycle and introspection
- It creates inconsistency where setting is done via
- Using
ros2 servicedirectly: While this is technically possible, it is:- Too verbose and error-prone for common operations
- Not discoverable for users unfamiliar with the service interface
- Inconsistent with the pattern established by
ros2 lifecycle,ros2 topic, etc.
- New
ros2 logcommand group (chosen approach):- Follows the established pattern in ROS CLI (similar to
ros2 lifecycle,ros2 topic, etc.) - Provides a dedicated namespace for all logging-related operations
- Offers better discoverability and user experience
- Allows for future expansion of logging features
- Follows the established pattern in ROS CLI (similar to
Logger Service Requirement
The requirement that nodes must enable enable_logger_service is maintained from the existing ROS design.
This is a deliberate choice to:
- Reduce overhead for nodes that do not need runtime log reconfiguration
- Allow nodes to opt-in to providing runtime logging control
- Maintain backward compatibility with existing systems
Clear error messages guide users when services are not available, helping them understand how to enable the functionality.
Content Filtered Topics for Watch
The watch command is designed to support Content Filtered Topics (CFT) when available in the RMW implementation.
This provides:
- Reduced network bandwidth by filtering at the publisher side
- Better performance when monitoring large-scale systems
- Graceful fallback to client-side filtering when CFT is not available
Backwards Compatibility
This REP introduces new functionality and does not modify or remove any existing interfaces.
It is fully backward compatible:
- Existing
ros2 servicecommands continue to work as before - Nodes that do not enable
enable_logger_serviceare unaffected - No changes to the ROS logging infrastructure or APIs are required
- The new commands are purely additive to the ROS CLI
Users who currently use manual service calls can continue to do so, though the new ros2 log commands provide a more ergonomic alternative.
How to Teach This
For New Users
New users learning ROS will benefit from the intuitive command structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Discover logging commands
ros2 log --help
# See what log levels are available
ros2 log levels
# Find nodes with logging support
ros2 log list
# Check current log level
ros2 log get /my_node
# Change log level for debugging
ros2 log set /my_node DEBUG
Documentation Updates
The following documentation should be updated:
- ROS Tutorials: Update the “Logging and logger configuration” tutorial to demonstrate
ros2 logcommands - CLI Reference: Add comprehensive documentation for all
ros2 logsubcommands - Node Development Guide: Mention the need to enable
enable_logger_servicewhen runtime log configuration is desired - Migration Guide: Provide examples showing how to transition from service calls to
ros2 logcommands
Implementation
Testing Requirements
The implementation must include:
- Unit tests for each verb
- Integration tests with actual nodes
- Tests for error conditions (service not enabled, invalid arguments, etc.)
- Tests for filtering options in
watchcommand
API Extensions
To support the ros2 log list and ros2 log describe commands effectively, the following enhancements are needed in the ROS logging infrastructure. The existing logger services (get_logger_levels and set_logger_levels) are necessary but not sufficient for the full ros2 log specification.
The following API extensions should be proposed and implemented in the rcl and rcutils repositories:
A new function in rcutils/logging.h to query available logger names from the logger registry maintained in rcutils:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Get all logger names matching a base logger name pattern.
*
* \param[in] base_logger_name The base logger name to search for.
* If NULL, returns all loggers in the system.
* If non-NULL (e.g., "my_node"), returns:
* - Exact match: "my_node"
* - Descendants: "my_node.vision", "my_node.control", "my_node.control.pid", etc.
* \param[in] allocator Allocator to use for the output string array
* \param[out] logger_names Output string array containing matching logger names
* \return RCUTILS_RET_OK if successful
*/
rcutils_ret_t rcutils_logging_get_logger_names(
const char * base_logger_name,
rcutils_allocator_t allocator,
rcutils_string_array_t * logger_names);
Use Cases:
ros2 log describe /my_node: Calls withbase_logger_name = "my_node"to find all loggers under that noderos2 log get /my_node: Retrieves all logger names, then queries their levels- Debugging tools: Calls with
base_logger_name = NULLto get all system loggers
This enhancement would allow ros2 log get to discover and retrieve all loggers in a single service call.
System Logger Attribution
System loggers (such as rcl, rcutils, rclcpp, etc.) are explicitly excluded from this REP’s scope for the following reasons:
Why System Loggers Are Not Handled:
- Shared Process Space: System loggers exist in the process space and are shared among all nodes in that process, including composable nodes.
- No Clear Ownership: These loggers are not under the control of any specific node, making it impossible to definitively attribute them to a single node.
- Composable Node Complexity: In deployments using composable nodes, multiple nodes coexist in the same process, all sharing the same system logger instances.
- Global Scope: Changes to system logger levels affect the entire process, not just individual nodes, making node-specific logger services inappropriate for managing them.
Implications for ros2 log Commands:
ros2 log get <node_name>: Will return only loggers that belong to or are created by the specified node (e.g.,node_name,node_name.subsystem), excluding system loggers likercl,rcutils,rclcpp.ros2 log set <node_name> <level>: Will only affect loggers owned by the node, not system-level loggers.ros2 log describe <node_name>: Will list only the node’s own loggers, not system loggers.
Rationale:
Associating system loggers with specific nodes would be misleading and could cause confusion:
- Users might expect that setting a system logger level via one node would only affect that node, when in reality it affects all nodes in the process.
- In composable node scenarios, the same system logger would appear in multiple nodes’ logger lists, creating ambiguity about which “instance” is being modified.
- The ownership model breaks down: if Node A and Node B both use
rcutils, which node “owns” its log level?
This separation maintains clear semantics and prevents user confusion about the scope of logger changes.
License
This document is marked CC0 1.0 Universal. To view a copy of this mark, visit https://creativecommons.org/publicdomain/zero/1.0/.