From 0d797324d1fb9684809c60d2c9c5ec7a962c65ee Mon Sep 17 00:00:00 2001 From: DRR Date: Sun, 16 Jun 2024 16:02:03 +0200 Subject: [PATCH 01/22] Added array for escape codes in stream_target struct, added entry argument to sendto_stream_target function so severity of message can be accessed from inside function, and fixed headers so compliant with script --- include/private/target/stream.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/private/target/stream.h b/include/private/target/stream.h index 1c9f7f7f8..dc068e534 100644 --- a/include/private/target/stream.h +++ b/include/private/target/stream.h @@ -22,6 +22,7 @@ # include # include # include +# include # include "private/config/wrapper/thread_safety.h" /** @@ -30,6 +31,8 @@ struct stream_target { /** The stream this target writes to. */ FILE *stream; +/** ANSI colors for different severities (when using ansi terminal) */ + char escape_codes[8][32]; # ifdef STUMPLESS_THREAD_SAFETY_SUPPORTED /** * Protects stream. This mutex must be locked by a thread before it can write @@ -61,6 +64,7 @@ new_stream_target( FILE *stream ); int sendto_stream_target( struct stream_target *target, const char *msg, - size_t msg_length ); + size_t msg_length, + const struct stumpless_entry *entry ); #endif /* __STUMPLESS_PRIVATE_TARGET_STREAM_H */ From 4e848614a4b46f84099f501cf2251c5b7cac0a01 Mon Sep 17 00:00:00 2001 From: DRR Date: Sun, 16 Jun 2024 16:03:10 +0200 Subject: [PATCH 02/22] Added defines for the default severity escape codes used --- include/stumpless/severity.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/stumpless/severity.h b/include/stumpless/severity.h index a3d1693f4..eb1517ebe 100644 --- a/include/stumpless/severity.h +++ b/include/stumpless/severity.h @@ -190,6 +190,20 @@ enum stumpless_severity { STUMPLESS_FOREACH_SEVERITY( STUMPLESS_GENERATE_ENUM ) }; +/** + * The default stumpless ansi terminal color values + */ +#define STUMPLESS_SEVERITY_EMERG_DEFAULT_COLOR "\33[31;1m" +#define STUMPLESS_SEVERITY_ALERT_DEFAULT_COLOR "\33[31;1m" +#define STUMPLESS_SEVERITY_CRIT_DEFAULT_COLOR "\33[31m" +#define STUMPLESS_SEVERITY_ERR_DEFAULT_COLOR "\33[31m" +#define STUMPLESS_SEVERITY_WARNING_DEFAULT_COLOR "\33[33m" +#define STUMPLESS_SEVERITY_NOTICE_DEFAULT_COLOR "\33[32m" +#define STUMPLESS_SEVERITY_INFO_DEFAULT_COLOR "\33[37m" +#define STUMPLESS_SEVERITY_DEBUG_DEFAULT_COLOR "\33[0m" + + + /** * Equivalent to the DEBUG severity. Trace level messages include extra * information, but do not have a distinct severity value in log entries. From 0e1cf3d2fbe9511c8fdd2c52016127703b576479 Mon Sep 17 00:00:00 2001 From: DRR Date: Sun, 16 Jun 2024 16:05:11 +0200 Subject: [PATCH 03/22] Added definition for the stumpless_set_severity_color and attempted to add documentation following the style of other comments in the same file. Fixed the headers so enum stumpless_severity is visible in this file. --- include/stumpless/target/stream.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/stumpless/target/stream.h b/include/stumpless/target/stream.h index ef14320b1..759599fbe 100644 --- a/include/stumpless/target/stream.h +++ b/include/stumpless/target/stream.h @@ -38,6 +38,7 @@ # include # include # include +# include # ifdef __cplusplus extern "C" { @@ -154,6 +155,32 @@ STUMPLESS_PUBLIC_FUNCTION struct stumpless_target * stumpless_open_stream_target( const char *name, FILE *stream ); +/** + * Sets the ANSI code to be printed in a specific target when a log is made at some severity + * + * It should be used with stdout or stderr as targets, since it is only for aesthetic purposes. + * + * **Thread Safety: MT-Safe race:name** + * This function is thread safe, of course assuming that escape_code is not modified by + * any other threads during execution. + * + * **Async Signal Safety: AS-Unsafe heap** + * This function is safe to call from signal handlers. + * + * **Async Cancel Safety: AC-Unsafe heap** + * This function is safe to call from threads that may be asynchronously + * cancelled. + * + * @param target The name of the target for which to set the colors. + * + * @param severity The severity code (LOG_ERR etc.) to which we set the specific color. + * + * @param escape_code The ANSI escape code representing the color. + */ +STUMPLESS_PUBLIC_FUNCTION +void +stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_severity severity, const char *escape_code ); + # ifdef __cplusplus } /* extern "C" */ # endif From 337661a96230252ec5bc9a237bdf1cb652f84bf9 Mon Sep 17 00:00:00 2001 From: DRR Date: Sun, 16 Jun 2024 16:05:52 +0200 Subject: [PATCH 04/22] Added entry parameter in sendto_stream_target call so the severity is visible within the function --- src/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target.c b/src/target.c index d06c76791..3cf78a023 100644 --- a/src/target.c +++ b/src/target.c @@ -267,7 +267,7 @@ stumpless_add_entry( struct stumpless_target *target, break; case STUMPLESS_STREAM_TARGET: - result = sendto_stream_target( target->id, buffer, builder_length ); + result = sendto_stream_target( target->id, buffer, builder_length, entry ); break; case STUMPLESS_WINDOWS_EVENT_LOG_TARGET: From a9dc6ffa3ef6b2cbc6e154a882961f647c9d7a3a Mon Sep 17 00:00:00 2001 From: DRR Date: Sun, 16 Jun 2024 16:11:01 +0200 Subject: [PATCH 05/22] Used set_severity_color to set the default severity colors inside the stumpless_open_stdout_target and stumpless_open_stderr_target functions (this may be replaced by something cleaner using a macro). Initialised the severity color codes to be a zero-length c-string in the open_stream_target function. Wrote implementation (thread and memory safe, checking for out of bounds errors and using the n variant of string functions to prevent buffer overflow) for stumpless_set_severity_color. Fixed headers so compliant with script. --- src/target/stream.c | 62 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/target/stream.c b/src/target/stream.c index 0fe23a77d..8ed56ebea 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -18,7 +18,10 @@ #include #include +#include #include +#include +#include #include #include "private/config/wrapper/locale.h" #include "private/config/wrapper/thread_safety.h" @@ -48,12 +51,35 @@ stumpless_close_stream_target( const struct stumpless_target *target ) { struct stumpless_target * stumpless_open_stderr_target( const char *name ) { - return stumpless_open_stream_target( name, stderr ); + struct stumpless_target *target = stumpless_open_stream_target( name, stderr ); + + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_EMERG_VALUE , STUMPLESS_SEVERITY_EMERG_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT_VALUE , STUMPLESS_SEVERITY_ALERT_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_CRIT_VALUE , STUMPLESS_SEVERITY_CRIT_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ERR_VALUE , STUMPLESS_SEVERITY_ERR_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_WARNING_VALUE, STUMPLESS_SEVERITY_WARNING_DEFAULT_COLOR); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_NOTICE_VALUE , STUMPLESS_SEVERITY_NOTICE_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_INFO_VALUE , STUMPLESS_SEVERITY_INFO_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_DEBUG_VALUE , STUMPLESS_SEVERITY_DEBUG_DEFAULT_COLOR ); + + return target; } struct stumpless_target * stumpless_open_stdout_target( const char *name ) { - return stumpless_open_stream_target( name, stdout ); + struct stumpless_target *target = stumpless_open_stream_target( name, stdout ); + + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_EMERG_VALUE , STUMPLESS_SEVERITY_EMERG_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT_VALUE , STUMPLESS_SEVERITY_ALERT_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_CRIT_VALUE , STUMPLESS_SEVERITY_CRIT_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ERR_VALUE , STUMPLESS_SEVERITY_ERR_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_WARNING_VALUE, STUMPLESS_SEVERITY_WARNING_DEFAULT_COLOR); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_NOTICE_VALUE , STUMPLESS_SEVERITY_NOTICE_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_INFO_VALUE , STUMPLESS_SEVERITY_INFO_DEFAULT_COLOR ); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_DEBUG_VALUE , STUMPLESS_SEVERITY_DEBUG_DEFAULT_COLOR ); + + + return target; } struct stumpless_target * @@ -76,6 +102,9 @@ stumpless_open_stream_target( const char *name, FILE *stream ) { goto fail_id; } + for (unsigned short i = 0; i < 8; i++) + ((struct stream_target *)(target->id))->escape_codes[i][0] = 0; + stumpless_set_current_target( target ); return target; @@ -85,6 +114,25 @@ stumpless_open_stream_target( const char *name, FILE *stream ) { return NULL; } +void +stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_severity severity, const char *escape_code ) +{ + if (severity > 7) + raise_index_out_of_bounds("Severity value must be part of 'stumpless_severity' enum (0-7)", severity); + + if (target->type != STUMPLESS_STREAM_TARGET) + raise_target_unsupported("This function is only supported for stream targets"); + + struct stream_target *starget = (struct stream_target *)target->id; + lock_target(target); + + strncpy(starget->escape_codes[severity], escape_code, 32); + starget->escape_codes[severity][31] = 0; + + unlock_target(target); +} + + /* private definitions */ void @@ -111,11 +159,17 @@ new_stream_target( FILE *stream ) { int sendto_stream_target( struct stream_target *target, const char *msg, - size_t msg_length ) { + size_t msg_length, + const struct stumpless_entry *entry ) { size_t fwrite_result; - + enum stumpless_severity severity = stumpless_get_entry_severity(entry); + const char *sev_code = target->escape_codes[severity]; + const char *reset_code = "\33[0m"; + config_lock_mutex( &target->stream_mutex ); + fwrite_result = fwrite( sev_code, sizeof( char ), strlen( sev_code ), target->stream ); fwrite_result = fwrite( msg, sizeof( char ), msg_length, target->stream ); + fwrite_result = fwrite( reset_code, sizeof( char ), strlen( reset_code ), target->stream ); config_unlock_mutex( &target->stream_mutex ); if( fwrite_result != msg_length ) { From ab2f945e3d23d28a8de65a8e24916d68507bb63e Mon Sep 17 00:00:00 2001 From: DRR Date: Mon, 17 Jun 2024 00:03:22 +0200 Subject: [PATCH 06/22] Broke down fwrite in sendto_stream_target so that we can check the result each time we send in case there is an error --- src/target/stream.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/target/stream.c b/src/target/stream.c index 8ed56ebea..c9f234d53 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -164,18 +164,39 @@ sendto_stream_target( struct stream_target *target, size_t fwrite_result; enum stumpless_severity severity = stumpless_get_entry_severity(entry); const char *sev_code = target->escape_codes[severity]; + unsigned short sev_code_len = strlen(sev_code); const char *reset_code = "\33[0m"; + unsigned short reset_code_len = strlen(sev_code); + if (sev_code_len != 0) + { + config_lock_mutex( &target->stream_mutex ); + fwrite_result = fwrite( sev_code, sizeof( char ), sev_code_len, target->stream ); + config_unlock_mutex( &target->stream_mutex ); + + if( fwrite_result != sev_code_len ) { + goto write_failure; + } + } + config_lock_mutex( &target->stream_mutex ); - fwrite_result = fwrite( sev_code, sizeof( char ), strlen( sev_code ), target->stream ); fwrite_result = fwrite( msg, sizeof( char ), msg_length, target->stream ); - fwrite_result = fwrite( reset_code, sizeof( char ), strlen( reset_code ), target->stream ); config_unlock_mutex( &target->stream_mutex ); - if( fwrite_result != msg_length ) { goto write_failure; } + if (sev_code_len != 0) + { + config_lock_mutex( &target->stream_mutex ); + fwrite_result = fwrite( reset_code, sizeof( char ), reset_code_len, target->stream ); + config_unlock_mutex( &target->stream_mutex ); + + if( fwrite_result != reset_code_len ) { + goto write_failure; + } + } + return cap_size_t_to_int( fwrite_result + 1 ); write_failure: From c43e5c967a99e6cb0e18d6d6eae4c125ba07672e Mon Sep 17 00:00:00 2001 From: DRR Date: Mon, 17 Jun 2024 00:07:59 +0200 Subject: [PATCH 07/22] Fixed so that it passes StreamTargetStderr.NullName (and similar for stdout) --- src/target/stream.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/target/stream.c b/src/target/stream.c index c9f234d53..f3340d584 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -52,6 +52,8 @@ stumpless_close_stream_target( const struct stumpless_target *target ) { struct stumpless_target * stumpless_open_stderr_target( const char *name ) { struct stumpless_target *target = stumpless_open_stream_target( name, stderr ); + + if (target == NULL) return NULL; stumpless_set_severity_color(target, STUMPLESS_SEVERITY_EMERG_VALUE , STUMPLESS_SEVERITY_EMERG_DEFAULT_COLOR ); stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT_VALUE , STUMPLESS_SEVERITY_ALERT_DEFAULT_COLOR ); @@ -69,6 +71,8 @@ struct stumpless_target * stumpless_open_stdout_target( const char *name ) { struct stumpless_target *target = stumpless_open_stream_target( name, stdout ); + if (target == NULL) return NULL; + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_EMERG_VALUE , STUMPLESS_SEVERITY_EMERG_DEFAULT_COLOR ); stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT_VALUE , STUMPLESS_SEVERITY_ALERT_DEFAULT_COLOR ); stumpless_set_severity_color(target, STUMPLESS_SEVERITY_CRIT_VALUE , STUMPLESS_SEVERITY_CRIT_DEFAULT_COLOR ); From f5a08db350629addfa0e4d66aefbc96d254b7333 Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:16:17 +0200 Subject: [PATCH 08/22] Fixed documentation comments in include/stumpless/target/stream.h --- include/stumpless/target/stream.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/stumpless/target/stream.h b/include/stumpless/target/stream.h index 759599fbe..4a4b32b28 100644 --- a/include/stumpless/target/stream.h +++ b/include/stumpless/target/stream.h @@ -156,20 +156,22 @@ struct stumpless_target * stumpless_open_stream_target( const char *name, FILE *stream ); /** - * Sets the ANSI code to be printed in a specific target when a log is made at some severity + * Sets the ANSI escape code (https://en.wikipedia.org/wiki/ANSI_escape_code) to + * be printed in a specific target when a log is made at some severity. * * It should be used with stdout or stderr as targets, since it is only for aesthetic purposes. * - * **Thread Safety: MT-Safe race:name** + * **Thread Safety: MT-Safe race:escape_code** * This function is thread safe, of course assuming that escape_code is not modified by * any other threads during execution. * - * **Async Signal Safety: AS-Unsafe heap** - * This function is safe to call from signal handlers. + * **Async Signal Safety: AS-Unsafe lock** + * This function is not safe to call from signal handlers due to the destruction + * of a lock that may be in use. * - * **Async Cancel Safety: AC-Unsafe heap** - * This function is safe to call from threads that may be asynchronously - * cancelled. + * **Async Cancel Safety: AC-Unsafe lock** + * This function is not safe to call from threads that may be asynchronously + * cancelled, as the cleanup of the lock may not be completed. * * @param target The name of the target for which to set the colors. * From e1f09494b9e7f006c25842ad87b34140a3f52e3d Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:21:10 +0200 Subject: [PATCH 09/22] Changed severity error checking to use severity_is_invalid and raise_invalid_severity instead --- src/target/stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/stream.c b/src/target/stream.c index f3340d584..f0f74fe91 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -121,8 +121,8 @@ stumpless_open_stream_target( const char *name, FILE *stream ) { void stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_severity severity, const char *escape_code ) { - if (severity > 7) - raise_index_out_of_bounds("Severity value must be part of 'stumpless_severity' enum (0-7)", severity); + if (severity_is_invalid(severity)) + raise_invalid_severity(severity); if (target->type != STUMPLESS_STREAM_TARGET) raise_target_unsupported("This function is only supported for stream targets"); From ef0f06847eeb5d7029bc89ec4968ef7be75f6252 Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:23:44 +0200 Subject: [PATCH 10/22] Moved lock_target up in stumpless_set_severity_color so the target is locked for the duration of the code that uses it. --- src/target/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/stream.c b/src/target/stream.c index f0f74fe91..2b0e562e0 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -124,11 +124,11 @@ stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_se if (severity_is_invalid(severity)) raise_invalid_severity(severity); + lock_target(target); if (target->type != STUMPLESS_STREAM_TARGET) raise_target_unsupported("This function is only supported for stream targets"); struct stream_target *starget = (struct stream_target *)target->id; - lock_target(target); strncpy(starget->escape_codes[severity], escape_code, 32); starget->escape_codes[severity][31] = 0; From 0c5c8d83eb54ffdb72b7425d6b30761be13757a3 Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:26:22 +0200 Subject: [PATCH 11/22] Moved from 3 individual critical sections in sendto_stream_target to 1 big one to prevent interleaving of messages --- src/target/stream.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/target/stream.c b/src/target/stream.c index 2b0e562e0..39e9de073 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -172,38 +172,35 @@ sendto_stream_target( struct stream_target *target, const char *reset_code = "\33[0m"; unsigned short reset_code_len = strlen(sev_code); + config_lock_mutex( &target->stream_mutex ); if (sev_code_len != 0) { - config_lock_mutex( &target->stream_mutex ); fwrite_result = fwrite( sev_code, sizeof( char ), sev_code_len, target->stream ); - config_unlock_mutex( &target->stream_mutex ); if( fwrite_result != sev_code_len ) { goto write_failure; } } - config_lock_mutex( &target->stream_mutex ); fwrite_result = fwrite( msg, sizeof( char ), msg_length, target->stream ); - config_unlock_mutex( &target->stream_mutex ); if( fwrite_result != msg_length ) { goto write_failure; } if (sev_code_len != 0) { - config_lock_mutex( &target->stream_mutex ); fwrite_result = fwrite( reset_code, sizeof( char ), reset_code_len, target->stream ); - config_unlock_mutex( &target->stream_mutex ); if( fwrite_result != reset_code_len ) { goto write_failure; } } + config_unlock_mutex( &target->stream_mutex ); return cap_size_t_to_int( fwrite_result + 1 ); write_failure: + config_unlock_mutex( &target->stream_mutex ); raise_stream_write_failure( ); return -1; } From 052375724ac97929cf0786d5bc567b160032376c Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:27:47 +0200 Subject: [PATCH 12/22] Fixed small typo where strlen of sev_code instead of reset_code was taken in sendto_stream_target --- src/target/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/stream.c b/src/target/stream.c index 39e9de073..1459ae466 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -170,7 +170,7 @@ sendto_stream_target( struct stream_target *target, const char *sev_code = target->escape_codes[severity]; unsigned short sev_code_len = strlen(sev_code); const char *reset_code = "\33[0m"; - unsigned short reset_code_len = strlen(sev_code); + unsigned short reset_code_len = strlen(reset_code); config_lock_mutex( &target->stream_mutex ); if (sev_code_len != 0) From fa9092453f90ca3fee577fca6daa1e091a027e8a Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 16:29:03 +0200 Subject: [PATCH 13/22] Added clear_error in stumpless_set_severity_color so error code is clean in event of success --- src/target/stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/stream.c b/src/target/stream.c index 1459ae466..293757133 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -134,6 +134,7 @@ stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_se starget->escape_codes[severity][31] = 0; unlock_target(target); + clear_error(); } From 1a03b8ef20fbe2a010ed24f73a115185c0154598 Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 21:09:52 +0200 Subject: [PATCH 14/22] Added tests for colored output when streaming to stdout and stderr --- test/function/target/stream.cpp | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index 37b12d765..d4e70322e 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -23,6 +23,8 @@ #include #include #include +#include + #include "test/helper/assert.hpp" #include "test/helper/fixture.hpp" #include "test/helper/rfc5424.hpp" @@ -248,6 +250,66 @@ namespace { EXPECT_ERROR_ID_EQ( STUMPLESS_ARGUMENT_EMPTY ); } + TEST( StreamTargetStderrTest, ColoredStream ) { + struct stumpless_target *target; + size_t i; + const char *filename = "streamtargetcoloredstderrtest.log"; + + target = stumpless_open_stderr_target( "stderr-target" ); + ASSERT_NOT_NULL( target ); + + int save_stderr = dup(STDERR_FILENO); + for (i = 0; i < 8; i++) + { + save_stderr = dup(save_stderr); + freopen(filename, "a+", stderr); + + stumpless_add_log_str(target, i, stumpless_get_severity_string((enum stumpless_severity)i)); + + fclose(stderr); + stderr = fdopen(save_stderr, "w"); + } + + stumpless_close_stream_target(target); + + std::ifstream infile( filename ); + std::stringstream buf; + buf << infile.rdbuf(); + std::string src = buf.str(); + + EXPECT_THAT(src, testing::MatchesRegex("(\33\\[(0|3[0-7]);?1?m.*\n\33\\[0m)*")); + } + + TEST( StreamTargetStdoutTest, ColoredStream ) { + struct stumpless_target *target; + size_t i; + const char *filename = "streamtargetcoloredstdouttest.log"; + + target = stumpless_open_stdout_target( "stdout-target" ); + ASSERT_NOT_NULL( target ); + + int save_stdout = dup(STDOUT_FILENO); + for (i = 0; i < 8; i++) + { + save_stdout = dup(save_stdout); + freopen(filename, "a+", stdout); + + stumpless_add_log_str(target, i, stumpless_get_severity_string((enum stumpless_severity)i)); + + fclose(stdout); + stdout = fdopen(save_stdout, "w"); + } + + stumpless_close_stream_target(target); + + std::ifstream infile( filename ); + std::stringstream buf; + buf << infile.rdbuf(); + std::string src = buf.str(); + + EXPECT_THAT(src, testing::MatchesRegex("(\33\\[(0|3[0-7]);?1?m.*\n\33\\[0m)*")); + } + TEST( StreamTargetWriteTest, ReadOnlyStream ) { struct stumpless_target *target; struct stumpless_entry *basic_entry; From 0fc108eae6002f61f038ded98f1a996a810089f6 Mon Sep 17 00:00:00 2001 From: DRR Date: Tue, 2 Jul 2024 21:10:09 +0200 Subject: [PATCH 15/22] Fixed small error to do with unincluded header file --- src/target/stream.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/stream.c b/src/target/stream.c index 293757133..195de42e0 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -31,6 +31,7 @@ #include "private/target.h" #include "private/target/stream.h" #include "private/validate.h" +#include "private/severity.h" void stumpless_close_stream_target( const struct stumpless_target *target ) { From b7ec39cb93de2a99cc53c6170e0edfadf00bbab5 Mon Sep 17 00:00:00 2001 From: DR-Reg Date: Wed, 3 Jul 2024 09:08:55 -0700 Subject: [PATCH 16/22] Added preprocessor directives to test/function/target/stream.cpp so that the test compiles on windows --- test/function/target/stream.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index d4e70322e..042a1d3ba 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -257,17 +257,29 @@ namespace { target = stumpless_open_stderr_target( "stderr-target" ); ASSERT_NOT_NULL( target ); - +#ifndef STDERR_FILENO + int save_stderr = _dup(_fileno(stderr)); +#else int save_stderr = dup(STDERR_FILENO); +#endif for (i = 0; i < 8; i++) { +#ifndef STDERR_FILENO + save_stderr = _dup(save_stderr); +#else save_stderr = dup(save_stderr); +#endif freopen(filename, "a+", stderr); stumpless_add_log_str(target, i, stumpless_get_severity_string((enum stumpless_severity)i)); - + + +#ifndef STDERR_FILENO + _dup2(save_stderr, _fileno(stderr)); +#else fclose(stderr); stderr = fdopen(save_stderr, "w"); +#endif } stumpless_close_stream_target(target); @@ -287,17 +299,28 @@ namespace { target = stumpless_open_stdout_target( "stdout-target" ); ASSERT_NOT_NULL( target ); - +#ifndef STDOUT_FILENO + int save_stdout = _dup(_fileno(stdout)); +#else int save_stdout = dup(STDOUT_FILENO); +#endif for (i = 0; i < 8; i++) { +#ifndef STDOUT_FILENO + save_stdout = _dup(save_stdout); +#else save_stdout = dup(save_stdout); +#endif freopen(filename, "a+", stdout); stumpless_add_log_str(target, i, stumpless_get_severity_string((enum stumpless_severity)i)); +#ifndef STDOUT_FILENO + _dup2(save_stdout, _fileno(stdout)); +#else fclose(stdout); stdout = fdopen(save_stdout, "w"); +#endif } stumpless_close_stream_target(target); From a9cc2cc00ce9b47a565cf64698358c807c10b076 Mon Sep 17 00:00:00 2001 From: DR-Reg Date: Wed, 3 Jul 2024 13:13:10 -0700 Subject: [PATCH 17/22] Implemented a fix for tests on windows due to gtest's lack of reasonably complex regex expressions on windows --- test/function/target/stream.cpp | 50 ++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index 042a1d3ba..947aaf127 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -284,12 +284,33 @@ namespace { stumpless_close_stream_target(target); - std::ifstream infile( filename ); + std::ifstream infile(filename); +#ifdef GTEST_USES_SIMPLE_RE + std::string line; + bool first = true; + + while (std::getline(infile, line)) + { + EXPECT_THAT(line, testing::Conditional( + first, + testing::AnyOf( + testing::MatchesRegex("\33\\[3\\d;?1?m.*"), + testing::MatchesRegex("\33\\[0m.*") + ), + testing::AnyOf( + testing::MatchesRegex("\33\\[0m\33\\[3\\d;?1?m.*"), + testing::MatchesRegex("\33\\[0m\33\\[0m.*"), + testing::MatchesRegex("\33\\[0m.*") + ) + )); + if (first) first = false; + } +#else std::stringstream buf; buf << infile.rdbuf(); std::string src = buf.str(); - EXPECT_THAT(src, testing::MatchesRegex("(\33\\[(0|3[0-7]);?1?m.*\n\33\\[0m)*")); +#endif } TEST( StreamTargetStdoutTest, ColoredStream ) { @@ -325,12 +346,33 @@ namespace { stumpless_close_stream_target(target); - std::ifstream infile( filename ); + std::ifstream infile(filename); +#ifdef GTEST_USES_SIMPLE_RE + std::string line; + bool first = true; + + while (std::getline(infile, line)) + { + EXPECT_THAT(line, testing::Conditional( + first, + testing::AnyOf( + testing::MatchesRegex("\33\\[3\\d;?1?m.*"), + testing::MatchesRegex("\33\\[0m.*") + ), + testing::AnyOf( + testing::MatchesRegex("\33\\[0m\33\\[3\\d;?1?m.*"), + testing::MatchesRegex("\33\\[0m\33\\[0m.*"), + testing::MatchesRegex("\33\\[0m.*") + ) + )); + if (first) first = false; + } +#else std::stringstream buf; buf << infile.rdbuf(); std::string src = buf.str(); - EXPECT_THAT(src, testing::MatchesRegex("(\33\\[(0|3[0-7]);?1?m.*\n\33\\[0m)*")); +#endif } TEST( StreamTargetWriteTest, ReadOnlyStream ) { From f6a7e1e51e8b00e06883a2297bf97019bf229e86 Mon Sep 17 00:00:00 2001 From: DRR Date: Wed, 3 Jul 2024 22:49:47 +0200 Subject: [PATCH 18/22] Fixed small bug where the function was not returning after raising an error --- src/target/stream.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/target/stream.c b/src/target/stream.c index 195de42e0..97a1e48f4 100644 --- a/src/target/stream.c +++ b/src/target/stream.c @@ -122,12 +122,16 @@ stumpless_open_stream_target( const char *name, FILE *stream ) { void stumpless_set_severity_color( struct stumpless_target *target, enum stumpless_severity severity, const char *escape_code ) { - if (severity_is_invalid(severity)) + if (severity_is_invalid(severity)) { raise_invalid_severity(severity); + return; + } lock_target(target); - if (target->type != STUMPLESS_STREAM_TARGET) + if (target->type != STUMPLESS_STREAM_TARGET) { raise_target_unsupported("This function is only supported for stream targets"); + return; + } struct stream_target *starget = (struct stream_target *)target->id; From 0f0fb56d6e6132543a13969c2a9d2c97ecf935d2 Mon Sep 17 00:00:00 2001 From: DRR Date: Wed, 3 Jul 2024 22:50:37 +0200 Subject: [PATCH 19/22] Added test for stumpless_set_severity_color --- test/function/target/stream.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index 947aaf127..bc03a4d7a 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -404,4 +404,17 @@ namespace { remove( filename ); } + + TEST(StreamSetSeverityColorTest, InvalidSeverity) { + struct stumpless_target *target = stumpless_open_stdout_target("stdout"); + stumpless_set_severity_color(target, (enum stumpless_severity) 15, "\33[0m"); + EXPECT_ERROR_ID_EQ(STUMPLESS_INVALID_SEVERITY); + } + + TEST(StreamSetSeverityColorTest, WrongTargetType) { + char buf; + struct stumpless_target *target = stumpless_open_buffer_target("buffer", &buf, 1); + stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT, "\33[0m"); + EXPECT_ERROR_ID_EQ(STUMPLESS_TARGET_UNSUPPORTED); + } } From 1fa15f5dd43100c60a04aaf01be5a7bcd2b0d7ce Mon Sep 17 00:00:00 2001 From: DRR Date: Thu, 4 Jul 2024 10:26:29 +0200 Subject: [PATCH 20/22] Added explanatory comments in ColoredStream tests in test/function/target/stream.cpp --- test/function/target/stream.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index bc03a4d7a..b0d582ab1 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -285,6 +285,15 @@ namespace { stumpless_close_stream_target(target); std::ifstream infile(filename); +/* + * Google Test uses a more simplified regex engine for windows + * (see here: https://google.github.io/googletest/advanced.html#regular-expression-syntax) + * which does not support things like conditionals, grouping or brackets. + * Hence we use the following preprocessor statement to use a different + * test when this is run on platforms with the simple regex, and hopefully + * once a reasonably complex regex engine is implemented in all the major + * platforms this is not needed. + **/ #ifdef GTEST_USES_SIMPLE_RE std::string line; bool first = true; @@ -347,6 +356,7 @@ namespace { stumpless_close_stream_target(target); std::ifstream infile(filename); +/* See comment in StreamTargetStderrTest.ColoredStream */ #ifdef GTEST_USES_SIMPLE_RE std::string line; bool first = true; From fa01e86fd97e87c2fda612386de234941dc30542 Mon Sep 17 00:00:00 2001 From: DRR Date: Thu, 4 Jul 2024 10:28:22 +0200 Subject: [PATCH 21/22] Added stumpless_set_severity_color to src/windows/stumpless.def --- src/windows/stumpless.def | 1 + 1 file changed, 1 insertion(+) diff --git a/src/windows/stumpless.def b/src/windows/stumpless.def index b47062f1d..3a1c10c37 100644 --- a/src/windows/stumpless.def +++ b/src/windows/stumpless.def @@ -246,3 +246,4 @@ EXPORTS stumpless_set_entry_message_str_w @229 stumpless_get_prival_string @230 + stumpless_set_severity_color @231 From 20553d05d49d4d41c97aae00c67ca9d386f4d792 Mon Sep 17 00:00:00 2001 From: DRR Date: Thu, 4 Jul 2024 10:40:29 +0200 Subject: [PATCH 22/22] Fixed leaks in test/function/target/stream.cpp by ensuring any heap memory is freed by stumpless_free_all --- test/function/target/stream.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/function/target/stream.cpp b/test/function/target/stream.cpp index b0d582ab1..986cfc64e 100644 --- a/test/function/target/stream.cpp +++ b/test/function/target/stream.cpp @@ -282,7 +282,8 @@ namespace { #endif } - stumpless_close_stream_target(target); + stumpless_close_target(target); + stumpless_free_all(); std::ifstream infile(filename); /* @@ -353,7 +354,8 @@ namespace { #endif } - stumpless_close_stream_target(target); + stumpless_close_target(target); + stumpless_free_all(); std::ifstream infile(filename); /* See comment in StreamTargetStderrTest.ColoredStream */ @@ -418,13 +420,21 @@ namespace { TEST(StreamSetSeverityColorTest, InvalidSeverity) { struct stumpless_target *target = stumpless_open_stdout_target("stdout"); stumpless_set_severity_color(target, (enum stumpless_severity) 15, "\33[0m"); + EXPECT_ERROR_ID_EQ(STUMPLESS_INVALID_SEVERITY); + + stumpless_close_target(target); + stumpless_free_all(); } TEST(StreamSetSeverityColorTest, WrongTargetType) { char buf; struct stumpless_target *target = stumpless_open_buffer_target("buffer", &buf, 1); stumpless_set_severity_color(target, STUMPLESS_SEVERITY_ALERT, "\33[0m"); + EXPECT_ERROR_ID_EQ(STUMPLESS_TARGET_UNSUPPORTED); + + stumpless_close_target(target); + stumpless_free_all(); } }