Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support setting log-level via command-line #383

Open
norro opened this issue Feb 18, 2020 · 9 comments
Open

Support setting log-level via command-line #383

norro opened this issue Feb 18, 2020 · 9 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@norro
Copy link

norro commented Feb 18, 2020

Feature request

Feature description

Allow setting log-level via command line, similar as documented for ros2 run, ros2 service, etc. see ros2/Tutorials/Logging-and-logger-configuration

Steps to reproduce issue

ros2 launch demo_nodes_cpp talker_listener.launch.py --ros-args --log-level debug

Expected behavior

log level is set to debug

Actual behavior

ros2: error: unrecognized arguments: --ros-args --log-level debug

@claireyywang claireyywang added the enhancement New feature or request label Feb 26, 2020
@claireyywang claireyywang self-assigned this Feb 27, 2020
@claireyywang
Copy link

@norro Could you provide more information about why this feature is needed and what it would do?

@claireyywang claireyywang added the more-information-needed Further information is required label Mar 5, 2020
@tim-fan
Copy link

tim-fan commented Oct 22, 2020

Hello, I am also interested in this feature, for my use case I'd like to sometimes launch my system at logging level WARN, and sometimes at logging level ERROR (basically I'd like to easily switch between more or less verbose options).

@hidmic
Copy link
Contributor

hidmic commented Oct 22, 2020

First of all, it's important not to mix up ROS 2 node arguments with ROS 2 cli arguments. --ros-args applies to ROS 2 nodes only. You may pass it to ros2 run solely because it parses none of it and forwards it all to the underlying process.

Having said that, currently this can be achieved by explicitly declaring a launch argument and then using that argument to set launch_ros.actions.Node arguments. Something along the lines of:

def generate_launch_description():
      return launch.LaunchDescription([
          launch.actions.DeclareArgument(name='log_level', default_value='info'),
          launch_ros.actions.Node(
                # name, namespace, executable, etc.
                arguments=['--ros-args', '--log-level', LaunchConfiguration('log_level')]
          )
      ])

should do.

It could be made implicit and applicable to all nodes, though in that case I wonder if it's worth all the plumbing instead of simply having rcl look at some environment variable to select the default logger level. Would something like that satisfy your use cases @norro @tim-fan? CC @wjwwood for valuable feedback.

@hidmic hidmic added help wanted Extra attention is needed and removed more-information-needed Further information is required labels Oct 22, 2020
@norro
Copy link
Author

norro commented Oct 26, 2020

That would satisfy my needs and would even provide a more fine-grained handle than I initially envisioned.
As this is currently already possible, I would close this issue if @tim-fan doesn't object.

Thanks for the great suggestion, @hidmic!

@tim-fan
Copy link

tim-fan commented Oct 26, 2020

Hi, thanks for the feedback.

I had considered the suggestion above of passing log-level arguments down to individual nodes. An issue with this for me is when I am including other launch files from external packages, in which case I cannot add the extra arguments. I'd say it may get a bit unwieldy in general for larger projects, if every launch file needs to pass logging levels to every node, in order to achieve this global level of control over logging.

As an alternative, the "environment variable sets default logging level" suggestion sounds good to me 👍

@wjwwood
Copy link
Member

wjwwood commented Oct 27, 2020

I have a slight preference for command line arguments over environment variables, but I think that would be ok too.

Typically in ROS 1, this kind of thing was done with a launch argument as @hidmic suggested simply because you often did not want all nodes to change log level, but instead you wanted to target a specific node or namespace to change the level. This is increasingly important with larger systems. So at some point setting an env var before ros2 launch will stop scaling, but it can be useful for now. It can also be useful for changing the log level for groups of nodes/processes within a launch file or in included launch files with less effort than adding additional command line arguments. We do need to set some precedence order between the two methods (env var vs command line) in case both are used. Another feature that could scale is using a parameter, we could have all the nodes declare a parameter for controlling the log level and it has many of the benefits of both env vars and command line arguments within a launch file, as you can override it using command line arguments or for a group of nodes with SetParameter:

https://github.com/ros2/launch_ros/blob/a8c12a95f169334e09eca2502d2c629847fa82bb/launch_ros/launch_ros/actions/set_parameter.py#L33

Alternatively we could have some special handling for --ros-args in ros2 launch, but that would need to be a more carefully thought out feature, ideally not just passing these args to all node entries in the launch file, but instead having the ability to target it to specific nodes (in the case of dynamically loaded component nodes) and/or executables.

@Aposhian
Copy link

This applies equally to name remapping and parameter overrides, which are also often done at runtime (desirable as a command line option). It would be very convenient to forward these options to all of the nodes, since these are things that are good candidates to change at runtime, and it is burdensome to have to edit the launch code to do so, even to add boilerplate to forward these options. There would be some edge cases that wouldn't make a ton of sense, especially for name remapping, which can be node specific like __node:=new_node_name. However, we could just say that the expected behavior in that case is just giving all the nodes the same name, and if that is a bug, then it is your fault for specifying that command line option.

@saahu27
Copy link

saahu27 commented Nov 8, 2022

This way, you can set log level to nodes. Try this launch file. This worked for me.

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
import launch_ros.actions
from launch.substitutions import TextSubstitution
from launch.substitutions import LaunchConfiguration



def generate_launch_description():
    return LaunchDescription([

        DeclareLaunchArgument(
                "Parameter_launch_argument", default_value=TextSubstitution(text=str("Parameter_launch")),
                description="Parameter launch default value"
            ),

        DeclareLaunchArgument(
            "log_level",
            default_value = TextSubstitution(text=str("WARN")),
            description="Logging level"
        ),

        launch_ros.actions.Node(
            package="serverpublisher",
            executable="talker",
            name="custom_msg_publisher_to_Life_iteration_topic",
            parameters=[
                {"Parameter_Publisher":  LaunchConfiguration('Parameter_launch_argument')}
            ],
            output="screen",
            arguments=['--ros-args', '--log-level', LaunchConfiguration('log_level')]
        ),

        launch_ros.actions.Node(
            package="serverpublisher",
            executable="server",
            name="custom_server_to_add_three_ints",
            output="screen",
            arguments=['--ros-args', '--log-level', LaunchConfiguration('log_level')]
        ),


        launch_ros.actions.Node(
            package="serverpublisher",
            executable="talkerandlistner",
            name="custom_msg_subscriber_to_No_Life_iteration_topic",
            output="screen",
            arguments=['--ros-args', '--log-level', LaunchConfiguration('log_level')]
        )
    ])

@artemiialessandrini
Copy link

Coming from Galactic, node logging has been introduced, which sets up log level to specific node, avoiding global log level

From the last example, it looks like this:

        <...>
        DeclareLaunchArgument(
            "log_level",
            default_value = TextSubstitution(text=str("WARN")),
            description="Logging level"
        ),

        launch_ros.actions.Node(
            package="serverpublisher",
            executable="talker",
            name="custom_msg_publisher_to_Life_iteration_topic",
            parameters=[
                {"Parameter_Publisher":  LaunchConfiguration('Parameter_launch_argument')}
            ],
            output="screen",
            arguments=['--ros-args', '--log-level', ['custom_msg_publisher_to_Life_iteration_topic:=', LaunchConfiguration('log_level')]]
        ), # change here

        launch_ros.actions.Node(
            package="serverpublisher",
            executable="server",
            name="custom_server_to_add_three_ints",
            output="screen",
            arguments=['--ros-args', '--log-level', ['custom_server_to_add_three_ints:=', LaunchConfiguration('log_level')]]
        ), # change here

Slightly upsetting, from my understanding you cannot pass the Node name making it more elegant:
arguments=['--ros-args', '--log-level', [name, ':=', LaunchConfiguration('log_level')]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

8 participants