Skip to content

Commit d12083d

Browse files
committed
Ensure filtered fatal logs abort
1 parent e09c5b8 commit d12083d

4 files changed

Lines changed: 59 additions & 9 deletions

File tree

‎include/stdcorelib/support/logging.h‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ namespace stdc {
128128
/// Each category registers itself on construction and picks up whatever filter rules are
129129
/// already in effect.
130130
///
131+
/// Disabling the fatal level suppresses its record but does not suppress process termination.
132+
///
131133
/// \sa setFilterRules()
132134
class STDC_EXPORT LogCategory {
133135
public:
@@ -187,11 +189,10 @@ namespace stdc {
187189
template <int Level, class... Args>
188190
void log(const char *fileName, int lineNumber, const char *functionName,
189191
const std::string_view &format, Args &&...args) const {
190-
if (!isLevelEnabled(Level)) {
191-
return;
192+
if (isLevelEnabled(Level)) {
193+
Logger(fileName, lineNumber, functionName, _name)
194+
.log(Level, format, std::forward<Args>(args)...);
192195
}
193-
Logger(fileName, lineNumber, functionName, _name)
194-
.log(Level, format, std::forward<Args>(args)...);
195196
if constexpr (Level == stdc::Logger::Fatal) {
196197
Logger::abort();
197198
}
@@ -200,11 +201,10 @@ namespace stdc {
200201
template <int Level, class... Args>
201202
void logf(const char *fileName, int lineNumber, const char *functionName, const char *fmt,
202203
Args &&...args) const {
203-
if (!isLevelEnabled(Level)) {
204-
return;
204+
if (isLevelEnabled(Level)) {
205+
Logger(fileName, lineNumber, functionName, _name)
206+
.printf(Level, fmt, std::forward<Args>(args)...);
205207
}
206-
Logger(fileName, lineNumber, functionName, _name)
207-
.printf(Level, fmt, std::forward<Args>(args)...);
208208
if constexpr (Level == stdc::Logger::Fatal) {
209209
Logger::abort();
210210
}

‎tests/auto/CMakeLists.txt‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,18 @@ set_target_properties(test_popen_child PROPERTIES
141141
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
142142
)
143143

144+
# Fatal logging has to run in a child because the behavior under test terminates its process.
145+
add_executable(test_logging_fatal helpers/test_logging_fatal.cpp)
146+
target_link_libraries(test_logging_fatal PRIVATE stdcorelib)
147+
set_target_properties(test_logging_fatal PROPERTIES
148+
CXX_EXTENSIONS OFF
149+
CXX_STANDARD 17
150+
CXX_STANDARD_REQUIRED ON
151+
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
152+
)
153+
144154
add_dependencies(${PROJECT_NAME}
145-
test_any_plugin test_dynamicregistry_plugin test_sharedlibrary_unloadable test_sharedlibrary_pinned test_popen_child
155+
test_any_plugin test_dynamicregistry_plugin test_sharedlibrary_unloadable test_sharedlibrary_pinned test_popen_child test_logging_fatal
146156
test_sharedlibrary_dependency test_sharedlibrary_needs_dependency)
147157
target_compile_definitions(${PROJECT_NAME} PRIVATE
148158
TEST_ANY_PLUGIN_PATH="$<TARGET_FILE:test_any_plugin>"
@@ -151,6 +161,7 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
151161
TEST_SHAREDLIBRARY_PINNED_PATH="$<TARGET_FILE:test_sharedlibrary_pinned>"
152162
TEST_SHAREDLIBRARY_NEEDS_DEPENDENCY_PATH="$<TARGET_FILE:test_sharedlibrary_needs_dependency>"
153163
TEST_POPEN_CHILD_PATH="$<TARGET_FILE:test_popen_child>"
164+
TEST_LOGGING_FATAL_PATH="$<TARGET_FILE:test_logging_fatal>"
154165
)
155166

156167
# One entry rather than one per suite. The whole binary is a second, and twenty five process
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
#include <cstring>
4+
5+
#include <stdcorelib/support/logging.h>
6+
7+
using namespace stdc;
8+
9+
int main(int argc, char *argv[]) {
10+
if (argc != 2) {
11+
return 2;
12+
}
13+
14+
LogCategory category("stdc.fatal.child");
15+
category.setFilterRules("stdc.fatal.child.fatal=false");
16+
17+
if (std::strcmp(argv[1], "log") == 0) {
18+
category.log<Logger::Fatal>(__FILE__, __LINE__, __FUNCTION__, "filtered fatal");
19+
}
20+
if (std::strcmp(argv[1], "logf") == 0) {
21+
category.logf<Logger::Fatal>(__FILE__, __LINE__, __FUNCTION__, "filtered %s", "fatal");
22+
}
23+
return 0;
24+
}

‎tests/auto/support/test_logging.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77

88
#include <stdcorelib/support/logging.h>
9+
#include <stdcorelib/support/popen.h>
910

1011
#include <boost/test/unit_test.hpp>
1112

@@ -79,6 +80,15 @@ namespace {
7980
g_lastContext = context;
8081
}
8182

83+
bool filteredFatalTerminates(const char *mode) {
84+
Popen process;
85+
process.args({TEST_LOGGING_FATAL_PATH, mode})
86+
.standardOutput(Popen::DeviceNull)
87+
.standardError(Popen::DeviceNull);
88+
return process.start() && process.wait(5000) && process.returnCode() &&
89+
*process.returnCode() != 0;
90+
}
91+
8292
// Redirects stdout and stderr into a scratch file for as long as it lives, and hands back
8393
// what was written. The default sink writes to them directly, so this is the only way to see
8494
// what it produced.
@@ -350,6 +360,11 @@ BOOST_AUTO_TEST_CASE(test_disabled_level_never_reaches_the_callback) {
350360
BOOST_CHECK_EQUAL(lastLevel, int(Logger::Warning));
351361
}
352362

363+
BOOST_AUTO_TEST_CASE(test_filtered_fatal_still_terminates) {
364+
BOOST_CHECK(filteredFatalTerminates("log"));
365+
BOOST_CHECK(filteredFatalTerminates("logf"));
366+
}
367+
353368
// The macros resolve an in-scope category through stdcGetLogCategory(), and fall back to the
354369
// default one when there is none.
355370
BOOST_AUTO_TEST_CASE(test_macros) {

0 commit comments

Comments
 (0)