From aa843bafff863aa3b986d7d1cdbb973454b860f6 Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Thu, 14 Dec 2023 15:16:02 +0100 Subject: [PATCH 1/7] allow parsing of esc seq in log format Signed-off-by: Marc Bestmann --- src/logging.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/logging.c b/src/logging.c index 666a5a55..936fdfab 100644 --- a/src/logging.c +++ b/src/logging.c @@ -440,14 +440,25 @@ static void create_format_string( break; } else { const char * expected_char = NULL; - switch (logging_output_format_string[i + back_slash_index + 1]) { - case 'a': expected_char = "\a"; break; // alert - case 'b': expected_char = "\b"; break; // backspace - case 'n': expected_char = "\n"; break; // new line - case 'r': expected_char = "\r"; break; // carriage return - case 't': expected_char = "\t"; break; // horizontal tab - default: - break; + int skip_chars = 0; + + if (logging_output_format_string[i + back_slash_index + 1] == 'x' && + logging_output_format_string[i + back_slash_index + 2] == '1' && + logging_output_format_string[i + back_slash_index + 3] == 'b') + { + // detect escape sequence + expected_char = "\x1b"; + skip_chars = 2; + } else { + switch (logging_output_format_string[i + back_slash_index + 1]) { + case 'a': expected_char = "\a"; break; // alert + case 'b': expected_char = "\b"; break; // backspace + case 'n': expected_char = "\n"; break; // new line + case 'r': expected_char = "\r"; break; // carriage return + case 't': expected_char = "\t"; break; // horizontal tab + default: + break; + } } if (expected_char) { @@ -466,12 +477,12 @@ static void create_format_string( // copy the decoded character g_rcutils_logging_output_format_string[dest_buffer_index] = expected_char[0]; dest_buffer_index += 1; - start_offset += 2; + start_offset += 2 + skip_chars; } else { start_offset_previous_not_copy += (back_slash_index + 2); } - i += (back_slash_index + 2); + i += (back_slash_index + 2 + skip_chars); } } } From 7aa9d0b2181486463c23d33d0d32b7fc616e52d8 Mon Sep 17 00:00:00 2001 From: Bestmann Date: Fri, 19 Jan 2024 12:54:19 +0100 Subject: [PATCH 2/7] enable escape sequence on windows Signed-off-by: Marc Bestmann --- src/logging.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/logging.c b/src/logging.c index 936fdfab..b728bd4b 100644 --- a/src/logging.c +++ b/src/logging.c @@ -87,6 +87,8 @@ bool g_rcutils_logging_initialized = false; static char g_rcutils_logging_output_format_string[RCUTILS_LOGGING_MAX_OUTPUT_FORMAT_LEN]; static const char * g_rcutils_logging_default_output_format = "[{severity}] [{time}] [{name}]: {message}"; +static DWORD g_original_console_mode = 0; +static bool g_consol_mode_modified = false; static rcutils_allocator_t g_rcutils_logging_allocator; @@ -415,6 +417,33 @@ static const char * copy_from_orig( return logging_output->buffer; } +#ifdef _WIN32 +#define ACTIVATE_VIRTUAL_TERMINAL_PROCESSING() \ + { \ + HANDLE std_error_handle = GetStdHandle(STD_ERROR_HANDLE); \ + if (std_error_handle == INVALID_HANDLE_VALUE) \ + { \ + RCUTILS_SET_ERROR_MSG("Could not get error handle to activating virtual terminal."); \ + return; \ + } \ + if (! GetConsoleMode(std_error_handle, &g_original_console_mode)) \ + { \ + RCUTILS_SET_ERROR_MSG("Could not get consol mode to activating virtual terminal."); \ + return; \ + } \ + DWORD newDwMode = g_original_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING; \ + if (! SetConsoleMode(std_error_handle, newDwMode)) \ + { \ + RCUTILS_SET_ERROR_MSG("Could not set consol mode to activating virtual terminal."); \ + return; \ + } \ + g_consol_mode_modified = true; \ + } +#else +// nothing todo for non-windows platform +#define ACTIVATE_VIRTUAL_TERMINAL_PROCESSING() +#endif + // copy buffers and decode escape characters if they exist static void create_format_string( const char * logging_output_format_string) @@ -447,7 +476,10 @@ static void create_format_string( logging_output_format_string[i + back_slash_index + 3] == 'b') { // detect escape sequence + ACTIVATE_VIRTUAL_TERMINAL_PROCESSING(); expected_char = "\x1b"; + // the 4 char long "\x1b" string literal will become a 2 char long \x1b escape sequence + // therefore we need to skip forward in parsing the output format string skip_chars = 2; } else { switch (logging_output_format_string[i + back_slash_index + 1]) { @@ -760,6 +792,10 @@ rcutils_ret_t rcutils_logging_shutdown(void) } g_num_log_msg_handlers = 0; g_rcutils_logging_initialized = false; + + if (g_consol_mode_modified){ + SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), g_original_console_mode); + } return ret; } From b4350546823e6f4c8af49315b4794ea90012cb05 Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Fri, 19 Jan 2024 12:56:06 +0100 Subject: [PATCH 3/7] WIP add not working test Signed-off-by: Marc Bestmann --- test/test_logging_output_format.py | 10 ++++++++++ test/test_logging_output_format_escape_sequence.regex | 2 ++ 2 files changed, 12 insertions(+) create mode 100644 test/test_logging_output_format_escape_sequence.regex diff --git a/test/test_logging_output_format.py b/test/test_logging_output_format.py index f6f7122f..2b4e15e5 100644 --- a/test/test_logging_output_format.py +++ b/test/test_logging_output_format.py @@ -91,6 +91,16 @@ def generate_test_description(): )) processes_to_test.append(name) + env_escape_sequence = dict(os.environ) + # This custom output is to check that escape characters work correctly. + env_escape_sequence['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = \ + r'{name} \x1b[0m {message}' + name = 'test_logging_output_format_escape_sequence' + launch_description.add_action(ExecuteProcess( + cmd=[executable], env=env_escape_sequence, name=name, output='screen' + )) + processes_to_test.append(name) + launch_description.add_action( launch_testing.actions.ReadyToTest() ) diff --git a/test/test_logging_output_format_escape_sequence.regex b/test/test_logging_output_format_escape_sequence.regex new file mode 100644 index 00000000..6f5f62bc --- /dev/null +++ b/test/test_logging_output_format_escape_sequence.regex @@ -0,0 +1,2 @@ +name1 \x1b\[0m Xx{2045}X +name2 \x1b\[0m X42x{2043}X From 8cde181960f34aeac5c6b3a135754760f298a2ea Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Mon, 22 Jan 2024 08:44:16 +0100 Subject: [PATCH 4/7] fix build on linux Signed-off-by: Marc Bestmann --- src/logging.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logging.c b/src/logging.c index b728bd4b..deae42d6 100644 --- a/src/logging.c +++ b/src/logging.c @@ -87,8 +87,10 @@ bool g_rcutils_logging_initialized = false; static char g_rcutils_logging_output_format_string[RCUTILS_LOGGING_MAX_OUTPUT_FORMAT_LEN]; static const char * g_rcutils_logging_default_output_format = "[{severity}] [{time}] [{name}]: {message}"; +#ifdef _WIN32 static DWORD g_original_console_mode = 0; static bool g_consol_mode_modified = false; +#endif static rcutils_allocator_t g_rcutils_logging_allocator; @@ -793,9 +795,11 @@ rcutils_ret_t rcutils_logging_shutdown(void) g_num_log_msg_handlers = 0; g_rcutils_logging_initialized = false; + #ifdef _WIN32 if (g_consol_mode_modified){ SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), g_original_console_mode); } + #endif return ret; } From 3d47f66e1c12bfd57aca1548d935cce2a5bfcb66 Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Mon, 22 Jan 2024 09:13:46 +0100 Subject: [PATCH 5/7] fix codestyle Signed-off-by: Marc Bestmann --- src/logging.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/logging.c b/src/logging.c index deae42d6..a8cc40c5 100644 --- a/src/logging.c +++ b/src/logging.c @@ -90,7 +90,7 @@ static const char * g_rcutils_logging_default_output_format = #ifdef _WIN32 static DWORD g_original_console_mode = 0; static bool g_consol_mode_modified = false; -#endif +#endif static rcutils_allocator_t g_rcutils_logging_allocator; @@ -423,19 +423,16 @@ static const char * copy_from_orig( #define ACTIVATE_VIRTUAL_TERMINAL_PROCESSING() \ { \ HANDLE std_error_handle = GetStdHandle(STD_ERROR_HANDLE); \ - if (std_error_handle == INVALID_HANDLE_VALUE) \ - { \ - RCUTILS_SET_ERROR_MSG("Could not get error handle to activating virtual terminal."); \ - return; \ + if (std_error_handle == INVALID_HANDLE_VALUE) { \ + RCUTILS_SET_ERROR_MSG("Could not get error handle to activating virtual terminal."); \ + return; \ } \ - if (! GetConsoleMode(std_error_handle, &g_original_console_mode)) \ - { \ + if (!GetConsoleMode(std_error_handle, &g_original_console_mode)) { \ RCUTILS_SET_ERROR_MSG("Could not get consol mode to activating virtual terminal."); \ return; \ } \ DWORD newDwMode = g_original_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING; \ - if (! SetConsoleMode(std_error_handle, newDwMode)) \ - { \ + if (!SetConsoleMode(std_error_handle, newDwMode)) { \ RCUTILS_SET_ERROR_MSG("Could not set consol mode to activating virtual terminal."); \ return; \ } \ @@ -796,7 +793,7 @@ rcutils_ret_t rcutils_logging_shutdown(void) g_rcutils_logging_initialized = false; #ifdef _WIN32 - if (g_consol_mode_modified){ + if (g_consol_mode_modified) { SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), g_original_console_mode); } #endif From e92e58f681778b67e01b886ed72023f40f559d0a Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Tue, 23 Jan 2024 10:03:17 +0100 Subject: [PATCH 6/7] keep ansi escape sequences to make test work Signed-off-by: Marc Bestmann --- test/test_logging_output_format.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_logging_output_format.py b/test/test_logging_output_format.py index 2b4e15e5..ef9a2ae6 100644 --- a/test/test_logging_output_format.py +++ b/test/test_logging_output_format.py @@ -127,7 +127,8 @@ def test_logging_output(self, proc_output, processes_to_test): path=os.path.join(os.path.dirname(__file__), process_name), encoding='unicode_escape' ), - process=process_name + process=process_name, + strip_ansi_escape_sequences=False ) def test_processes_exit_codes(self, proc_info): From e0196e60208ad88c8a726e91cdbe1d8ea96b1a7e Mon Sep 17 00:00:00 2001 From: Marc Bestmann Date: Tue, 13 Feb 2024 14:53:37 +0100 Subject: [PATCH 7/7] use normal string to enable testing on windows Signed-off-by: Marc Bestmann --- test/test_logging_output_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_logging_output_format.py b/test/test_logging_output_format.py index ef9a2ae6..c7519f06 100644 --- a/test/test_logging_output_format.py +++ b/test/test_logging_output_format.py @@ -94,7 +94,7 @@ def generate_test_description(): env_escape_sequence = dict(os.environ) # This custom output is to check that escape characters work correctly. env_escape_sequence['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = \ - r'{name} \x1b[0m {message}' + '{name} \x1b[0m {message}' name = 'test_logging_output_format_escape_sequence' launch_description.add_action(ExecuteProcess( cmd=[executable], env=env_escape_sequence, name=name, output='screen'