Skip to content

Commit b17f596

Browse files
authored
Fix ANSI escape code pollution in log output (backport #2741) (#2784)
1 parent 563d40a commit b17f596

File tree

5 files changed

+50
-17
lines changed

5 files changed

+50
-17
lines changed

controller_manager/controller_manager/controller_manager_services.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,30 @@
3838
from ros2param.api import call_set_parameters
3939

4040

41-
# from https://stackoverflow.com/a/287944
41+
import os
42+
import sys
43+
44+
45+
def _color_enabled():
46+
"""Respect RCUTILS_COLORIZED_OUTPUT: 0=off, 1=on, unset=auto-detect TTY."""
47+
env = os.getenv("RCUTILS_COLORIZED_OUTPUT")
48+
if env == "0":
49+
return False
50+
if env == "1":
51+
return True
52+
return sys.stdout.isatty()
53+
54+
4255
class bcolors:
43-
MAGENTA = "\033[95m"
44-
OKBLUE = "\033[94m"
45-
OKCYAN = "\033[96m"
46-
OKGREEN = "\033[92m"
47-
WARNING = "\033[93m"
48-
FAIL = "\033[91m"
49-
ENDC = "\033[0m"
50-
BOLD = "\033[1m"
51-
UNDERLINE = "\033[4m"
56+
MAGENTA = "\033[95m" if _color_enabled() else ""
57+
OKBLUE = "\033[94m" if _color_enabled() else ""
58+
OKCYAN = "\033[96m" if _color_enabled() else ""
59+
OKGREEN = "\033[92m" if _color_enabled() else ""
60+
WARNING = "\033[93m" if _color_enabled() else ""
61+
FAIL = "\033[91m" if _color_enabled() else ""
62+
ENDC = "\033[0m" if _color_enabled() else ""
63+
BOLD = "\033[1m" if _color_enabled() else ""
64+
UNDERLINE = "\033[4m" if _color_enabled() else ""
5265

5366

5467
class ServiceNotFoundError(Exception):

controller_manager/controller_manager/hardware_spawner.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@
1919
from controller_manager import (
2020
list_hardware_components,
2121
set_hardware_component_state,
22-
bcolors,
2322
)
24-
from controller_manager.controller_manager_services import ServiceNotFoundError
23+
from controller_manager.controller_manager_services import ServiceNotFoundError, bcolors
2524

2625
from lifecycle_msgs.msg import State
2726
import rclpy
@@ -93,7 +92,11 @@ def configure_component(node, controller_manager_name, component_to_configure):
9392
inactive_state.id = State.PRIMARY_STATE_INACTIVE
9493
inactive_state.label = "inactive"
9594
handle_set_component_state_service_call(
96-
node, controller_manager_name, component_to_configure, inactive_state, "configured"
95+
node,
96+
controller_manager_name,
97+
component_to_configure,
98+
inactive_state,
99+
"configured",
97100
)
98101

99102

@@ -154,7 +157,10 @@ def main(args=None):
154157
try:
155158
for hardware_component in hardware_components:
156159
if not is_hardware_component_loaded(
157-
node, controller_manager_name, hardware_component, controller_manager_timeout
160+
node,
161+
controller_manager_name,
162+
hardware_component,
163+
controller_manager_timeout,
158164
):
159165
node.get_logger().warning(
160166
f"{bcolors.WARNING}Hardware Component is not loaded - state can not be changed.{bcolors.ENDC}"

controller_manager/controller_manager/spawner.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@
2828
unload_controller,
2929
set_controller_parameters,
3030
set_controller_parameters_from_param_files,
31-
bcolors,
3231
)
3332
from controller_manager_msgs.srv import SwitchController
34-
from controller_manager.controller_manager_services import ServiceNotFoundError
33+
from controller_manager.controller_manager_services import ServiceNotFoundError, bcolors
3534

3635
from filelock import Timeout, FileLock
3736
import rclpy
@@ -51,7 +50,8 @@ def combine_name_and_namespace(name_and_namespace):
5150
def find_node_and_namespace(node, full_node_name):
5251
node_names_and_namespaces = node.get_node_names_and_namespaces()
5352
return first_match(
54-
node_names_and_namespaces, lambda n: combine_name_and_namespace(n) == full_node_name
53+
node_names_and_namespaces,
54+
lambda n: combine_name_and_namespace(n) == full_node_name,
5555
)
5656

5757

controller_manager/doc/userdoc.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,3 +494,14 @@ The ``time`` argument in the ``read`` and ``write`` methods of the hardware comp
494494
The ``period`` argument in the ``read``, ``update`` and ``write`` methods is calculated using the trigger clock of type ``RCL_STEADY_TIME`` so it is always monotonic.
495495

496496
The reason behind using different clocks is to avoid the issues related to the affect of system time changes in the realtime loops. The ``ros2_control_node`` now also detects the overruns caused by the system time changes and longer execution times of the controllers and hardware components. The controller manager will print a warning message if the controller or hardware component misses the update cycle due to the system time changes or longer execution times.
497+
498+
Color Output Handling
499+
^^^^^^^^^^^^^^^^^^^^^
500+
501+
The helper scripts (``spawner`` and ``hardware_spawner``) now use an environment-aware ``bcolors`` class.
502+
The color output automatically adapts to the environment:
503+
504+
* ``RCUTILS_COLORIZED_OUTPUT=0`` -> disables color output
505+
* ``RCUTILS_COLORIZED_OUTPUT=1`` -> forces color output
506+
* Unset -> automatically detects TTY and enables color only in interactive
507+
terminals

doc/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ controller_manager
1818
* The controller manager now supports switching (activating and deactivating) controllers in both realtime and non-realtime modes. This is controlled by the parameter ``activate_asap`` of the ``switch_controllers`` service (`#2452 <https://github.com/ros-controls/ros2_control/pull/2453>`_).
1919
* The spawner now supports two new arguments ``--switch-asap`` and ``--no-switch-asap`` to control the behaviour of the spawner when switching controllers to be in realtime loop (or) non-realtime loop. By default, it is set to ``--no-switch-asap`` because when activating multiple controllers at same time might affect the realtime loop performance (`#2452 <https://github.com/ros-controls/ros2_control/pull/2453>`_).
2020
* New parameters ``overruns.manage`` and ``overruns.print_warnings`` were added to control the behavior of the controller manager/ros2_control_node when overruns occur (`#2546 <https://github.com/ros-controls/ros2_control/pull/2546/files>`_).
21+
* The ``bcolors`` class now respects the ``RCUTILS_COLORIZED_OUTPUT`` environment
22+
variable to automatically disable colors in non-TTY and CI environments.
2123

2224

2325
hardware_interface
@@ -32,6 +34,7 @@ ros2controlcli
3234
**************
3335
* The CLI verbs ``list_hardware_components`` and ``list_hardware_interfaces`` will now show the data type used by the internal Command and State interfaces (`#2204 <https://github.com/ros-controls/ros2_control/pull/2204>`_).
3436

37+
3538
transmission_interface
3639
**********************
3740
* The ``simple_transmission`` and ``differential_transmission`` now also support the ``force`` interface (`#2588 <https://github.com/ros-controls/ros2_control/pull/2588>`_).

0 commit comments

Comments
 (0)