quill
Backend.h
1 
7 #pragma once
8 
9 #include "quill/backend/BackendManager.h"
10 #include "quill/backend/BackendOptions.h"
11 #include "quill/backend/SignalHandler.h"
12 #include "quill/core/Attributes.h"
13 #include "quill/core/QuillError.h"
14 
15 #include <atomic>
16 #include <csignal>
17 #include <cstdint>
18 #include <cstdlib>
19 #include <mutex>
20 
21 QUILL_BEGIN_NAMESPACE
22 
24 constexpr uint32_t VersionMajor{10};
25 constexpr uint32_t VersionMinor{0};
26 constexpr uint32_t VersionPatch{1};
27 constexpr uint32_t Version{VersionMajor * 10000 + VersionMinor * 100 + VersionPatch};
28 
29 class Backend
30 {
31 public:
36  QUILL_ATTRIBUTE_COLD static void start(BackendOptions const& options = BackendOptions{})
37  {
38  std::call_once(detail::BackendManager::instance().get_start_once_flag(),
39  [options]()
40  {
41  // Run the backend worker thread, we wait here until the thread enters the main loop
42  detail::BackendManager::instance().start_backend_thread(options);
43 
44  // Set up an exit handler to call stop when the main application exits.
45  // always call stop on destruction to log everything. std::atexit seems to be
46  // working better with dll on windows compared to using ~LogManagerSingleton().
47  std::atexit([]() { detail::BackendManager::instance().stop_backend_thread(); });
48  });
49  }
70  template <typename TFrontendOptions>
71  QUILL_ATTRIBUTE_COLD static void start(BackendOptions const& backend_options,
72  SignalHandlerOptions const& signal_handler_options)
73  {
74  std::call_once(detail::BackendManager::instance().get_start_once_flag(),
75  [backend_options, signal_handler_options]()
76  {
77 #if defined(_WIN32)
78  detail::init_exception_handler<TFrontendOptions>();
79 #else
80  // We do not want signal handler to run in the backend worker thread
81  // Block signals in the main thread so when we spawn the backend worker thread it inherits
82  // the master
83  sigset_t set, oldset;
84  sigfillset(&set);
85  sigprocmask(SIG_SETMASK, &set, &oldset);
86  detail::init_signal_handler<TFrontendOptions>(signal_handler_options.catchable_signals);
87 #endif
88 
89  // Run the backend worker thread, we wait here until the thread enters the main loop
90  detail::BackendManager::instance().start_backend_thread(backend_options);
91 
92  detail::SignalHandlerContext::instance().logger_name = signal_handler_options.logger;
93 
94  detail::SignalHandlerContext::instance().signal_handler_timeout_seconds.store(
95  signal_handler_options.timeout_seconds);
96 
97  // We need to update the signal handler with some backend thread details
98  detail::SignalHandlerContext::instance().backend_thread_id.store(
99  detail::BackendManager::instance().get_backend_thread_id());
100 
101 #if defined(_WIN32)
102  // nothing to do
103 #else
104  // Unblock signals in the main thread so subsequent threads do not inherit the blocked mask
105  sigprocmask(SIG_SETMASK, &oldset, nullptr);
106 #endif
107 
108  // Set up an exit handler to call stop when the main application exits.
109  // always call stop on destruction to log everything. std::atexit seems to be
110  // working better with dll on windows compared to using ~LogManagerSingleton().
111  std::atexit([]() { detail::BackendManager::instance().stop_backend_thread(); });
112  });
113  }
114 
119  QUILL_ATTRIBUTE_COLD static void stop() noexcept
120  {
121  detail::BackendManager::instance().stop_backend_thread();
122  }
123 
131  static void notify() noexcept { detail::BackendManager::instance().notify_backend_thread(); }
132 
137  QUILL_NODISCARD static bool is_running() noexcept
138  {
139  return detail::BackendManager::instance().is_backend_thread_running();
140  }
141 
146  QUILL_NODISCARD static uint32_t get_thread_id() noexcept
147  {
148  return detail::BackendManager::instance().get_backend_thread_id();
149  }
150 
161  QUILL_NODISCARD static uint64_t convert_rdtsc_to_epoch_time(uint64_t rdtsc_value) noexcept
162  {
163  return detail::BackendManager::instance().convert_rdtsc_to_epoch_time(rdtsc_value);
164  }
165 
204  QUILL_ATTRIBUTE_COLD static ManualBackendWorker* acquire_manual_backend_worker()
205  {
206  ManualBackendWorker* manual_backend_worker{nullptr};
207 
208  std::call_once(
209  detail::BackendManager::instance().get_start_once_flag(), [&manual_backend_worker]() mutable
210  { manual_backend_worker = detail::BackendManager::instance().get_manual_backend_worker(); });
211 
212  if (!manual_backend_worker)
213  {
214  QUILL_THROW(
215  QuillError{"acquire_manual_backend_worker() can only be called once per process. "
216  "Additionally, it should not be "
217  "called when start() has already been invoked"});
218  }
219 
220  return manual_backend_worker;
221  }
222 };
223 
224 QUILL_END_NAMESPACE
static QUILL_NODISCARD uint32_t get_thread_id() noexcept
Retrieves the ID of the backend thread.
Definition: Backend.h:146
static QUILL_NODISCARD bool is_running() noexcept
Checks if the backend is currently running.
Definition: Backend.h:137
static QUILL_ATTRIBUTE_COLD void start(BackendOptions const &backend_options, SignalHandlerOptions const &signal_handler_options)
Starts the backend thread and initialises a signal handler.
Definition: Backend.h:71
uint32_t timeout_seconds
Defines the timeout duration in seconds for the signal handler alarm.
Definition: SignalHandler.h:62
static void notify() noexcept
Notifies the backend thread to wake up.
Definition: Backend.h:131
static QUILL_NODISCARD uint64_t convert_rdtsc_to_epoch_time(uint64_t rdtsc_value) noexcept
Converts an rdtsc value to epoch time.
Definition: Backend.h:161
std::string logger
The logger instance that the signal handler will use to log errors when the application crashes...
Definition: SignalHandler.h:71
static QUILL_ATTRIBUTE_COLD ManualBackendWorker * acquire_manual_backend_worker()
This feature is designed for advanced users who need to run the backend worker on their own thread...
Definition: Backend.h:204
Definition: Backend.h:29
This class can be used when you want to run the backend worker on your own thread.
Definition: ManualBackendWorker.h:20
static QUILL_ATTRIBUTE_COLD void start(BackendOptions const &options=BackendOptions{})
Starts the backend thread.
Definition: Backend.h:36
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:53
Struct to hold options for the signal handler.
Definition: SignalHandler.h:48
static QUILL_ATTRIBUTE_COLD void stop() noexcept
Stops the backend thread.
Definition: Backend.h:119
Configuration options for the backend.
Definition: BackendOptions.h:30