forked from ros2/ros2cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Command to monitor and pretty print the rosout logs ros2#849
Creation of a rosout print command that generates pretty prints of the content of the `/rosout` topic. The commands also allows for the filtering of nodes based on a regular expression applied to the node name itself. Output color can be disabled (enabled by default) and the function information detail can also be displayed. issue: ros2#849
- Loading branch information
1 parent
c43e064
commit 7e32799
Showing
12 changed files
with
390 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# ros2rosout | ||
|
||
This is the `ros2 rosout print` utility command which displaies the content of `/rosout` topic in a nicely formatted and colorized output. | ||
|
||
## Usage | ||
|
||
Run `ros2 rosout print` to get the live stream of the logs. | ||
|
||
Run `ros2 rosout print -h/--help` to print all available command arguments. | ||
|
||
|
||
## Output format | ||
|
||
The command outputs the log line with the following format: | ||
`[` _datetime_ `] [` _level_ `] [` _nodename_ `]: ` _log_ `:[` _file_ `:` _line_ `(` _function_ `)]` | ||
|
||
File, line and function are all optional and are displays when the `-f/--function-detail` switch is provided. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?xml version="1.0"?> | ||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> | ||
<package format="3"> | ||
<name>ros2rosout</name> | ||
<version>0.0.0</version> | ||
<description>A command line tool to print the rosout logs in a ROS 2 system</description> | ||
|
||
<maintainer email="[email protected]">Guillaume Autran</maintainer> | ||
|
||
<license>Apache License 2.0</license> | ||
|
||
<author email="[email protected]">Guillaume Autran</author> | ||
|
||
<exec_depend>ament_index_python</exec_depend> | ||
<exec_depend>rclpy</exec_depend> | ||
<exec_depend>ros2cli</exec_depend> | ||
<exec_depend>rcl_interfaces</exec_depend> | ||
|
||
<test_depend>ament_copyright</test_depend> | ||
<test_depend>ament_flake8</test_depend> | ||
<test_depend>ament_pep257</test_depend> | ||
<test_depend>ament_xmllint</test_depend> | ||
<test_depend>launch</test_depend> | ||
<test_depend>launch_ros</test_depend> | ||
|
||
<export> | ||
<build_type>ament_python</build_type> | ||
</export> | ||
</package> |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Copyright 2023 Clearpath Robotics Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ros2cli.command import add_subparsers_on_demand | ||
from ros2cli.command import CommandExtension | ||
|
||
|
||
class RosoutCommand(CommandExtension): | ||
"""Prints the '/rosout' log stream """ | ||
|
||
def add_arguments(self, parser, cli_name): | ||
self._subparser = parser | ||
# add arguments and sub-commands of verbs | ||
add_subparsers_on_demand( | ||
parser, cli_name, '_verb', 'ros2rosout.verb', required=False) | ||
|
||
def main(self, *, parser, args): | ||
if not hasattr(args, '_verb'): | ||
# in case no verb was passed | ||
self._subparser.print_help() | ||
return 0 | ||
|
||
extension = getattr(args, '_verb') | ||
|
||
# call the verb's main method | ||
return extension.main(args=args) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Copyright 2023 Clearpath Robotics Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from ros2cli.plugin_system import PLUGIN_SYSTEM_VERSION | ||
from ros2cli.plugin_system import satisfies_version | ||
|
||
|
||
class VerbExtension: | ||
""" | ||
The extension point for 'print' verb extensions. | ||
The following properties must be defined: | ||
* `NAME` (will be set to the entry point name) | ||
The following methods must be defined: | ||
* `main` | ||
The following methods can be defined: | ||
* `add_arguments` | ||
""" | ||
|
||
NAME = None | ||
EXTENSION_POINT_VERSION = '0.1' | ||
|
||
def __init__(self): | ||
super(VerbExtension, self).__init__() | ||
satisfies_version(PLUGIN_SYSTEM_VERSION, '^0.1') | ||
|
||
def add_arguments(self, parser, cli_name): | ||
pass | ||
|
||
def main(self, *, args): | ||
raise NotImplementedError() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# Copyright 2023 Clearpath Robotics | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from datetime import datetime | ||
from rcl_interfaces.msg import Log | ||
from ros2cli.node.strategy import NodeStrategy | ||
from ros2cli.node.strategy import add_arguments | ||
from ros2rosout.verb import VerbExtension | ||
import rclpy | ||
import re | ||
|
||
|
||
class PrintVerb(VerbExtension): | ||
"""Outputs the '/rosout' content in a nicely formatted way""" | ||
|
||
BLACK_TEXT = "\033[30;1m" | ||
BLUE_TEXT = "\033[34;1m" | ||
BOLD_TEXT = "\033[1m" | ||
CYAN_TEXT = "\033[36;1m" | ||
GREEN_TEXT = "\033[32;1m" | ||
MAGENTA_TEXT = "\033[35;1m" | ||
RED_TEXT = "\033[31;1m" | ||
WHITE_TEXT = "\033[37;1m" | ||
YELLOW_TEXT = "\033[33;1m" | ||
|
||
COLOR_RESET = "\033[0m" | ||
|
||
def add_arguments(self, parser, cli_name): | ||
add_arguments(parser) | ||
parser.add_argument( | ||
'-l', '--level', default=int.from_bytes(Log.INFO, 'big'), type=int, | ||
help='Print log statement with priority level greater than this value') | ||
parser.add_argument( | ||
'-n', '--node-regex', default=None, | ||
help='Only print log statements from node(s) matching the regular expression provided') | ||
parser.add_argument( | ||
'--no-color', action='store_true', default=False, | ||
help='Disables the use of ASCII colors for the output of the command') | ||
parser.add_argument( | ||
'-f', '--function-detail', action='store_true', default=False, | ||
help='Output function name, file, and line number') | ||
|
||
def level_to_string(self, level): | ||
if type(level) is not bytes: | ||
level = level.to_bytes(1, 'big') | ||
|
||
match level: | ||
case Log.DEBUG: | ||
return "DEBUG" | ||
case Log.INFO: | ||
return "INFO " | ||
case Log.WARN: | ||
return "WARN " | ||
case Log.ERROR: | ||
return "ERROR" | ||
case Log.FATAL: | ||
return "FATAL" | ||
case _: | ||
return "_____" | ||
|
||
def stamp_to_string(self, stamp): | ||
dt = datetime.fromtimestamp(stamp.sec) | ||
s = dt.strftime('%Y-%m-%d %H:%M:%S') | ||
s += '.' + str(int(stamp.nanosec % 1000000000)).zfill(9) | ||
return f"{s}" | ||
|
||
def add_color(self, txt, color=WHITE_TEXT): | ||
if self.args_.no_color: | ||
return txt | ||
|
||
return f"{color}{txt}{self.COLOR_RESET}" | ||
|
||
def get_color(self, level): | ||
if type(level) is not bytes: | ||
level = level.to_bytes(1, 'big') | ||
|
||
match level: | ||
case Log.DEBUG: | ||
return self.GREEN_TEXT | ||
case Log.INFO: | ||
return self.WHITE_TEXT | ||
case Log.WARN: | ||
return self.YELLOW_TEXT | ||
case Log.ERROR: | ||
return self.RED_TEXT | ||
case Log.FATAL: | ||
return f"{self.RED_TEXT}{self.BOLD_TEXT}" | ||
case _: | ||
return self.BOLD_TEXT | ||
|
||
def rosout_cb(self, msg): | ||
if msg.level < self.args_.level: | ||
return | ||
if self.args_.node_regex and not re.search(self.args_.node_regex, msg.name): | ||
return | ||
color = self.get_color(msg.level) | ||
lvl = self.add_color(self.level_to_string(msg.level), color) | ||
dt = self.add_color(self.stamp_to_string(msg.stamp), color) | ||
name = self.add_color(msg.name, color) | ||
mmsg = self.add_color(msg.msg, color) | ||
text = f"[{dt}] [{lvl}] [{name}]: {mmsg}" | ||
if self.args_.function_detail: | ||
file = self.add_color(msg.file, self.BLUE_TEXT) | ||
line = self.add_color(msg.line, self.BLUE_TEXT) | ||
function = self.add_color(msg.function, self.CYAN_TEXT) | ||
text += f" [{file}:{line}({function})]" | ||
print(f"{text}") | ||
|
||
def main(self, *, args): | ||
self.args_ = args | ||
|
||
with NodeStrategy(args) as node: | ||
self.rosout_ = node.node.create_subscription(Log, '/rosout', self.rosout_cb, 10) | ||
rclpy.spin(node) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from setuptools import find_packages | ||
from setuptools import setup | ||
|
||
package_name = 'ros2rosout' | ||
|
||
setup( | ||
name=package_name, | ||
version='0.0.0', | ||
packages=find_packages(exclude=['test']), | ||
data_files=[ | ||
('share/' + package_name, ['package.xml']), | ||
], | ||
install_requires=['ros2cli'], | ||
zip_safe=True, | ||
author='Guillaume Autran', | ||
author_email='[email protected]', | ||
maintainer='Guillaume Autran', | ||
maintainer_email='[email protected]', | ||
url='', | ||
download_url='', | ||
keywords=[], | ||
classifiers=[ | ||
'Environment :: Console', | ||
'Intended Audience :: Developers', | ||
'License :: OSI Approved :: Apache Software License', | ||
'Programming Language :: Python', | ||
], | ||
description='A convenient command to display the /rosout logs for ROS 2 command line tools', | ||
long_description="""\ | ||
The package provides a cli tool to print the `/rosout` logs in a ROS 2 system""", | ||
license='Apache License, Version 2.0', | ||
tests_require=['pytest'], | ||
entry_points={ | ||
'ros2cli.command': [ | ||
'rosout = ros2rosout.command.rosout:RosoutCommand', | ||
], | ||
'ros2cli.extension_point': [ | ||
'ros2rosout.verb = ros2rosout.verb:VerbExtension', | ||
], | ||
'ros2rosout.verb': [ | ||
'print = ros2rosout.verb.print:PrintVerb' | ||
] | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_copyright.main import main | ||
import pytest | ||
|
||
|
||
@pytest.mark.copyright | ||
@pytest.mark.linter | ||
def test_copyright(): | ||
rc = main(argv=['.', 'test']) | ||
assert rc == 0, 'Found errors' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_flake8.main import main_with_errors | ||
import pytest | ||
|
||
|
||
@pytest.mark.flake8 | ||
@pytest.mark.linter | ||
def test_flake8(): | ||
rc, errors = main_with_errors(argv=[]) | ||
assert rc == 0, \ | ||
'Found %d code style errors / warnings:\n' % len(errors) + \ | ||
'\n'.join(errors) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_pep257.main import main | ||
import pytest | ||
|
||
|
||
@pytest.mark.linter | ||
@pytest.mark.pep257 | ||
def test_pep257(): | ||
rc = main(argv=[]) | ||
assert rc == 0, 'Found code style errors / warnings' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2019 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_xmllint.main import main | ||
import pytest | ||
|
||
|
||
@pytest.mark.linter | ||
@pytest.mark.xmllint | ||
def test_xmllint(): | ||
rc = main(argv=[]) | ||
assert rc == 0, 'Found errors' |