9 #include "quill/backend/ThreadUtilities.h" 11 #include "quill/Logger.h" 12 #include "quill/core/Attributes.h" 13 #include "quill/core/LogLevel.h" 14 #include "quill/core/LoggerBase.h" 15 #include "quill/core/LoggerManager.h" 16 #include "quill/core/MacroMetadata.h" 17 #include "quill/core/QuillError.h" 29 #if !defined(WIN32_LEAN_AND_MEAN) 30 #define WIN32_LEAN_AND_MEAN 33 #if !defined(NOMINMAX) 107 QUILL_NODISCARD
static LoggerBase* get_logger() noexcept
113 logger_base = LoggerManager::instance().get_logger(instance().
logger_name);
117 if (!logger_base || !logger_base->is_valid_logger())
127 std::atomic<int32_t> signal_number{0};
128 std::atomic<uint32_t> lock{0};
129 std::atomic<uint32_t> backend_thread_id{0};
130 std::atomic<uint32_t> signal_handler_timeout_seconds{20};
131 std::atomic<bool> should_reraise_signal{
true};
132 std::mutex signal_handlers_mutex;
133 std::vector<int> registered_signal_handlers{};
140 #define QUILL_SIGNAL_HANDLER_LOG(logger, log_level, fmt, ...) \ 143 if (logger->template should_log_statement<log_level>()) \ 145 static constexpr quill::MacroMetadata macro_metadata{ \ 146 "SignalHandler:~", "", fmt, nullptr, log_level, quill::MacroMetadata::Event::Log}; \ 148 logger->template log_statement<false>(¯o_metadata, ##__VA_ARGS__); \ 153 template <
typename TFrontendOptions>
154 void on_signal(int32_t signal_number)
157 uint32_t
const lock = SignalHandlerContext::instance().lock.fetch_add(1);
167 std::this_thread::sleep_for(std::chrono::hours{24000});
177 SignalHandlerContext::instance().signal_number.store(signal_number);
181 alarm(SignalHandlerContext::instance().signal_handler_timeout_seconds.load());
185 uint32_t
const backend_thread_id = SignalHandlerContext::instance().backend_thread_id.load();
187 bool const should_reraise_signal = SignalHandlerContext::instance().should_reraise_signal.load();
189 if ((backend_thread_id == 0) || (current_thread_id == backend_thread_id))
192 if (signal_number == SIGINT || signal_number == SIGTERM)
194 std::exit(EXIT_SUCCESS);
197 if (should_reraise_signal)
200 std::signal(signal_number, SIG_DFL);
201 std::raise(signal_number);
207 LoggerBase* logger_base = SignalHandlerContext::instance().get_logger();
212 int32_t
const signal_desc = signal_number;
214 char const*
const signal_desc = ::strsignal(signal_number);
218 QUILL_SIGNAL_HANDLER_LOG(logger, LogLevel::Info,
"Received signal: {} (signum: {})",
219 signal_desc, signal_number);
221 if (signal_number == SIGINT || signal_number == SIGTERM)
225 logger->flush_log(0);
226 std::exit(EXIT_SUCCESS);
229 if (should_reraise_signal)
231 QUILL_SIGNAL_HANDLER_LOG(logger, LogLevel::Critical,
232 "Program terminated unexpectedly due to signal: {} (signum: {})",
233 signal_desc, signal_number);
236 logger->flush_log(0);
239 std::signal(signal_number, SIG_DFL);
240 std::raise(signal_number);
244 logger->flush_log(0);
258 inline char const* get_error_message(DWORD ex_code)
262 case EXCEPTION_ACCESS_VIOLATION:
263 return "EXCEPTION_ACCESS_VIOLATION";
264 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
265 return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
266 case EXCEPTION_BREAKPOINT:
267 return "EXCEPTION_BREAKPOINT";
268 case EXCEPTION_DATATYPE_MISALIGNMENT:
269 return "EXCEPTION_DATATYPE_MISALIGNMENT";
270 case EXCEPTION_FLT_DENORMAL_OPERAND:
271 return "EXCEPTION_FLT_DENORMAL_OPERAND";
272 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
273 return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
274 case EXCEPTION_FLT_INEXACT_RESULT:
275 return "EXCEPTION_FLT_INEXACT_RESULT";
276 case EXCEPTION_FLT_INVALID_OPERATION:
277 return "EXCEPTION_FLT_INVALID_OPERATION";
278 case EXCEPTION_FLT_OVERFLOW:
279 return "EXCEPTION_FLT_OVERFLOW";
280 case EXCEPTION_FLT_STACK_CHECK:
281 return "EXCEPTION_FLT_STACK_CHECK";
282 case EXCEPTION_FLT_UNDERFLOW:
283 return "EXCEPTION_FLT_UNDERFLOW";
284 case EXCEPTION_ILLEGAL_INSTRUCTION:
285 return "EXCEPTION_ILLEGAL_INSTRUCTION";
286 case EXCEPTION_IN_PAGE_ERROR:
287 return "EXCEPTION_IN_PAGE_ERROR";
288 case EXCEPTION_INT_DIVIDE_BY_ZERO:
289 return "EXCEPTION_INT_DIVIDE_BY_ZERO";
290 case EXCEPTION_INT_OVERFLOW:
291 return "EXCEPTION_INT_OVERFLOW";
292 case EXCEPTION_INVALID_DISPOSITION:
293 return "EXCEPTION_INVALID_DISPOSITION";
294 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
295 return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
296 case EXCEPTION_PRIV_INSTRUCTION:
297 return "EXCEPTION_PRIV_INSTRUCTION";
298 case EXCEPTION_SINGLE_STEP:
299 return "EXCEPTION_SINGLE_STEP";
300 case EXCEPTION_STACK_OVERFLOW:
301 return "EXCEPTION_STACK_OVERFLOW";
303 return "Unrecognized Exception";
308 template <
typename TFrontendOptions>
309 BOOL WINAPI on_console_signal(DWORD signal)
311 uint32_t
const backend_thread_id = SignalHandlerContext::instance().backend_thread_id.load();
315 if ((backend_thread_id != 0) && (current_thread_id != backend_thread_id) &&
316 (signal == CTRL_C_EVENT || signal == CTRL_BREAK_EVENT))
319 LoggerBase* logger_base = SignalHandlerContext::instance().get_logger();
324 QUILL_SIGNAL_HANDLER_LOG(logger, LogLevel::Info,
325 "Program interrupted by Ctrl+C or Ctrl+Break signal");
328 logger->flush_log(0);
329 std::exit(EXIT_SUCCESS);
337 template <
typename TFrontendOptions>
338 LONG WINAPI on_exception(EXCEPTION_POINTERS* exception_p)
340 uint32_t
const backend_thread_id = SignalHandlerContext::instance().backend_thread_id.load();
344 if ((backend_thread_id != 0) && (current_thread_id != backend_thread_id))
347 LoggerBase* logger_base = SignalHandlerContext::instance().get_logger();
353 QUILL_SIGNAL_HANDLER_LOG(logger, LogLevel::Info,
"Received exception: {} (Code: {})",
354 get_error_message(exception_p->ExceptionRecord->ExceptionCode),
355 exception_p->ExceptionRecord->ExceptionCode);
357 QUILL_SIGNAL_HANDLER_LOG(logger, LogLevel::Critical,
358 "Program terminated unexpectedly due to exception: {} (Code: {})",
359 get_error_message(exception_p->ExceptionRecord->ExceptionCode),
360 exception_p->ExceptionRecord->ExceptionCode);
363 logger->flush_log(0);
371 return EXCEPTION_CONTINUE_SEARCH;
375 template <
typename TFrontendOptions>
376 void init_exception_handler()
378 SetUnhandledExceptionFilter(on_exception<TFrontendOptions>);
380 if (!SetConsoleCtrlHandler(on_console_signal<TFrontendOptions>, TRUE))
382 QUILL_THROW(
QuillError{
"Failed to call SetConsoleCtrlHandler"});
391 template <
typename TFrontendOptions>
392 void init_signal_handler(std::vector<int>
const&
catchable_signals = std::vector<int>{
393 SIGTERM, SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV})
395 auto& ctx = detail::SignalHandlerContext::instance();
396 std::lock_guard<std::mutex>
const lock{ctx.signal_handlers_mutex};
403 if (std::signal(catchable_signal, detail::on_signal<TFrontendOptions>) == SIG_ERR)
405 QUILL_THROW(
QuillError{
"Failed to setup signal handler for signal: " + std::to_string(catchable_signal)});
412 inline void deinit_signal_handler()
414 auto& ctx = SignalHandlerContext::instance();
415 std::lock_guard<std::mutex>
const lock{ctx.signal_handlers_mutex};
417 for (
auto const& signal_number : ctx.registered_signal_handlers)
419 std::signal(signal_number, SIG_DFL);
422 ctx.registered_signal_handlers.clear();
429 inline void on_alarm(int32_t signal_number)
431 if (SignalHandlerContext::instance().signal_number.load() == 0)
434 SignalHandlerContext::instance().signal_number = signal_number;
438 std::signal(SignalHandlerContext::instance().signal_number, SIG_DFL);
439 std::raise(SignalHandlerContext::instance().signal_number);
442 template <
typename TFrontendOptions>
445 auto& ctx = SignalHandlerContext::instance();
446 std::lock_guard<std::mutex>
const lock{ctx.signal_handlers_mutex};
450 for (
auto const& catchable_signal : catchable_signals)
452 if (catchable_signal == SIGALRM)
454 QUILL_THROW(
QuillError{
"SIGALRM can not be part of catchable_signals."});
458 if (std::signal(catchable_signal, on_signal<TFrontendOptions>) == SIG_ERR)
460 QUILL_THROW(
QuillError{
"Failed to setup signal handler for signal: " + std::to_string(catchable_signal)});
465 if (std::signal(SIGALRM, on_alarm) == SIG_ERR)
467 QUILL_THROW(
QuillError{
"Failed to setup signal handler for signal: SIGALRM"});
470 ctx.registered_signal_handlers.push_back(SIGALRM);
473 inline void deinit_signal_handler()
475 auto& ctx = SignalHandlerContext::instance();
476 std::lock_guard<std::mutex>
const lock{ctx.signal_handlers_mutex};
478 for (
auto const& signal_number : ctx.registered_signal_handlers)
480 std::signal(signal_number, SIG_DFL);
483 ctx.registered_signal_handlers.clear();
uint32_t timeout_seconds
Defines the timeout duration in seconds for the signal handler alarm.
Definition: SignalHandler.h:65
std::vector< std::string > excluded_logger_substrings
List of substrings used to exclude loggers during automatic logger selection.
Definition: SignalHandler.h:87
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
Thread safe logger.
Definition: Logger.h:48
Definition: SignalHandler.h:93
Definition: LoggerBase.h:35
custom exception
Definition: QuillError.h:45
std::vector< int > catchable_signals
List of signals that the backend should catch if with_signal_handler is enabled.
Definition: SignalHandler.h:56
Struct to hold options for the signal handler.
Definition: SignalHandler.h:50
std::string logger_name
The name of the logger instance that the signal handler will use to log errors when the application c...
Definition: SignalHandler.h:77
QUILL_NODISCARD QUILL_EXPORT QUILL_ATTRIBUTE_USED uint32_t get_thread_id() noexcept
Returns the os assigned ID of the thread.
Definition: ThreadUtilities.h:198