MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Archivist.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Format.hpp"
4#include "JournalEntry.hpp"
5
6namespace MayaFlux::Journal {
7
8class Sink;
9
10/**
11 * @class Archivist
12 * @brief Singleton class responsible for managing log entries.
13 *
14 * The Archivist class provides methods to log messages with various severity levels,
15 * components, and contexts. It supports both standard and real-time logging.
16 */
17class MAYAFLUX_API Archivist {
18
19public:
20 /**
21 * @brief Get the singleton instance of the Archivist.
22 * @return Reference to the Archivist instance.
23 */
24 static Archivist& instance();
25
26 /**
27 * @brief Shutdown the logging system.
28 * This should be called once at the end of the application.
29 */
30 static void shutdown();
31
32 /**
33 * @brief Log a message with the specified severity, component, and context.
34 *
35 * This method captures the source location automatically.
36 *
37 * @param severity The severity level of the log message.
38 * @param component The component generating the log message.
39 * @param context The execution context of the log message.
40 * @param message The log message content.
41 * @param location The source location (file, line, function) of the log call.
42 */
43 void scribe(Severity severity, Component component, Context context,
44 std::string_view message,
45 std::source_location location = std::source_location::current());
46
47 /**
48 * @brief Log a message from a real-time context with the specified severity, component, and context.
49 * This method is optimized for real-time contexts and captures the source location automatically.
50 * @param severity The severity level of the log message.
51 * @param component The component generating the log message.
52 * @param context The execution context of the log message.
53 * @param message The log message content.
54 * @param location The source location (file, line, function) of the log call.
55 */
56 void scribe_rt(Severity severity, Component component, Context context,
57 std::string_view message,
58 std::source_location location = std::source_location::current());
59
60 /**
61 * @brief Log a simple message without source location information.
62 * This method is intended for use in contexts where source location is not available or needed.
63 * It is not effected by severity filters, so use sparingly.
64 *
65 * @param component The component generating the log message.
66 * @param context The execution context of the log message.
67 * @param message The log message content.
68 */
69 void scribe_simple(Component component, Context context,
70 std::string_view message);
71
72 /**
73 * @brief Add a log sink for output
74 * @param sink Unique pointer to a LogSink implementation
75 */
76 void add_sink(std::unique_ptr<Sink> sink);
77
78 /**
79 * @brief Remove all sinks
80 */
81 void clear_sinks();
82
83 /**
84 * @brief Set the minimum severity level for logging.
85 * Messages with a severity lower than this level will be ignored.
86 * @param min_sev The minimum severity level to log.
87 */
88 void set_min_severity(Severity min_sev);
89
90 /**
91 * @brief Enable or disable logging for a specific component.
92 * @param comp The component to enable or disable.
93 * @param enabled True to enable logging for the component, false to disable.
94 */
95 void set_component_filter(Component comp, bool enabled);
96
97 Archivist(const Archivist&) = delete;
98 Archivist& operator=(const Archivist&) = delete;
99 Archivist(Archivist&&) = delete;
101
102private:
103 Archivist();
105
106 class Impl;
107 std::unique_ptr<Impl> m_impl;
108};
109
110/**
111 * @brief Log a message with the specified severity, component, and context.
112 *
113 * Captures the source location automatically.
114 *
115 * @param severity The severity level of the log message.
116 * @param component The component generating the log message.
117 * @param context The execution context of the log message.
118 * @param location Source location (file, line, function) of the log call.
119 * @param message The log message content.
120 */
121inline void scribe(Severity severity, Component component, Context context,
122 std::source_location location, std::string_view message)
123{
124 Archivist::instance().scribe(severity, component, context, message, location);
125}
126
127/**
128 * @brief printf-style overload of scribe().
129 *
130 * @copydoc scribe(Severity,Component,Context,std::string_view,std::source_location)
131 *
132 * @param msg_or_fmt The format string.
133 * @param args The format arguments.
134 */
135template <typename... Args>
136void scribe(Severity severity, Component component, Context context,
137 std::source_location location, const char* msg_or_fmt, Args&&... args)
138{
139 if constexpr (sizeof...(Args) == 0) {
140 Archivist::instance().scribe(severity, component, context,
141 std::string_view(msg_or_fmt), location);
142 } else {
143 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
144 Archivist::instance().scribe(severity, component, context, msg, location);
145 }
146}
147
148/**
149 * @brief Log a message in a real-time context with automatic source location.
150 *
151 * Optimized for real-time usage and captures the source location automatically.
152 *
153 * @param severity The severity level of the log message.
154 * @param component The component generating the log message.
155 * @param context The execution context of the log message.
156 * @param location Source location (file, line, function) of the log call.
157 * @param message The log message content.
158 */
159inline void scribe_rt(Severity severity, Component component, Context context,
160 std::source_location location, std::string_view message)
161{
162 Archivist::instance().scribe_rt(severity, component, context, message, location);
163}
164
165/**
166 * @brief printf-style overload of scribe_rt().
167 *
168 * @copydoc scribe_rt(Severity,Component,Context,std::string_view,std::source_location)
169 *
170 * @param msg_or_fmt The format string.
171 * @param args The format arguments.
172 */
173template <typename... Args>
174void scribe_rt(Severity severity, Component component, Context context,
175 std::source_location location,
176 const char* msg_or_fmt, Args&&... args)
177{
178 if constexpr (sizeof...(Args) == 0) {
179 Archivist::instance().scribe_rt(severity, component, context,
180 std::string_view(msg_or_fmt), location);
181 } else {
182 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
183 Archivist::instance().scribe_rt(severity, component, context, msg, location);
184 }
185}
186
187/**
188 * @brief Log a simple message without source-location.
189 *
190 * Intended for contexts where source location is unavailable or unnecessary.
191 * It is not effected by severity filters, so use sparingly.
192 *
193 * @param component The component generating the log message.
194 * @param context The execution context of the log message.
195 * @param message The log message content.
196 */
197inline void print(Component component, Context context,
198 std::string_view message)
199{
200 Archivist::instance().scribe_simple(component, context, message);
201}
202
203/**
204 * @brief printf-style overload of print().
205 *
206 * @copydoc print(Component,Context,std::string_view)
207 *
208 * @param msg_or_fmt The format string.
209 * @param args The format arguments.
210 */
211template <typename... Args>
212void print(Component component, Context context,
213 const char* msg_or_fmt, Args&&... args)
214{
215 if constexpr (sizeof...(Args) == 0) {
216 Archivist::instance().scribe_simple(component, context,
217 std::string_view(msg_or_fmt));
218 } else {
219 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
220 Archivist::instance().scribe_simple(component, context, msg);
221 }
222}
223
224/**
225 * @brief Log a fatal message and abort the program.
226 *
227 * @param component The component generating the log message.
228 * @param context The execution context of the log message.
229 * @param location Source location (file, line, function) of the log call.
230 * @param message The fatal message content.
231 */
232[[noreturn]] inline void fatal(Component component, Context context,
233 std::source_location location, std::string_view message)
234{
235 Archivist::instance().scribe(Severity::FATAL, component, context, message, location);
236 std::abort();
237}
238
239/**
240 * @brief fmt-style overload of fatal().
241 *
242 * @copydoc fatal(Component,Context,std::string_view,std::source_location)
243 *
244 * @tparam Args Types of the format arguments.
245 * @param fmt_str The format string.
246 * @param args The format arguments.
247 */
248template <typename... Args>
249[[noreturn]] void fatal(Component component, Context context,
250 std::source_location location, format_string<Args...> fmt_str, Args&&... args)
251{
252 auto msg = format(fmt_str, std::forward<Args>(args)...);
253 Archivist::instance().scribe(Severity::FATAL, component, context, msg, location);
254 std::abort();
255}
256
257/**
258 * @brief Log an error message and optionally throw an exception.
259 *
260 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
261 * @param context The execution context of the log message.
262 * @param location Source location (file, line, function) of the log call.
263 * @param message The error message content.
264 */
265template <typename ExceptionType = std::runtime_error>
266[[noreturn]] void error(Component component, Context context,
267 std::source_location location,
268 std::string_view message)
269{
270 Archivist::instance().scribe(Severity::ERROR, component, context, message, location);
271
272 throw ExceptionType(std::string(message));
273}
274
275/**
276 * @brief fmt-style overload of error().
277 *
278 * @copydoc error(Component,Context,ExceptionBehavior,std::string_view,std::source_location)
279 *
280 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
281 * @tparam Args Types of the format arguments.
282 * @param fmt_str The format string.
283 * @param args The format arguments.
284 */
285template <typename ExceptionType = std::runtime_error, typename... Args>
286[[noreturn]] void error(Component component, Context context,
287 std::source_location location, const char* fmt_str, Args&&... args)
288{
289 if constexpr (sizeof...(Args) == 0) {
290 Archivist::instance().scribe(Severity::ERROR, component, context,
291 std::string_view(fmt_str), location);
292 throw ExceptionType(std::string(fmt_str));
293 } else {
294 auto msg = format_runtime(fmt_str, std::forward<Args>(args)...);
295 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
296 throw ExceptionType(msg);
297 }
298}
299
300/**
301 * @brief Catch and log an exception, then rethrow it.
302 * This function is intended to be called within a catch block.
303 * @param Component The component generating the log message.
304 * @param Context The execution context of the log message.
305 * @param location The source location (file, line, function) of the log call.
306 * @param additional_context Optional additional context to prepend to the exception message.
307 */
308inline void error_rethrow(Component component, Context context,
309 std::source_location location = std::source_location::current(),
310 std::string_view additional_context = "")
311{
312 auto ep = std::current_exception();
313 if (!ep) {
314 Archivist::instance().scribe(Severity::ERROR, component, context,
315 "error_rethrow called outside of a catch", location);
316 std::terminate();
317 }
318
319 try {
320 std::rethrow_exception(ep);
321 } catch (const std::exception& e) {
322 std::string msg = std::string(e.what());
323 if (!additional_context.empty()) {
324 msg = std::string(additional_context) + ": " + msg;
325 }
326 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
327 std::rethrow_exception(ep);
328 } catch (...) {
329 std::string msg = "Unknown exception";
330 if (!additional_context.empty()) {
331 msg = std::string(additional_context) + ": " + msg;
332 }
333 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
334 std::rethrow_exception(ep);
335 }
336}
337
338/**
339 * @brief fmt-style overload of error_rethrow().
340 *
341 * @copydoc error_rethrow(Component,Context,std::source_location,std::string_view)
342 *
343 * @tparam Args Types of the format arguments.
344 * @param fmt_str The format string.
345 * @param args The format arguments.
346 */
347template <typename... Args>
348inline void error_rethrow(Component component, Context context,
349 std::source_location location, const char* fmt_str, Args&&... args)
350{
351 if constexpr (sizeof...(Args) == 0) {
352 error_rethrow(component, context, location,
353 std::string_view(fmt_str));
354 return;
355 }
356 auto additional_context = format_runtime(fmt_str, std::forward<Args>(args)...);
357 error_rethrow(component, context, location, additional_context);
358}
359
360} // namespace MayaFlux::Journal
361
362// ============================================================================
363// CONVENIENCE MACROS (for regular logging only)
364// ============================================================================
365
366#define MF_TRACE(comp, ctx, ...) \
367 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
368 std::source_location::current(), __VA_ARGS__)
369
370#define MF_DEBUG(comp, ctx, ...) \
371 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
372 std::source_location::current(), __VA_ARGS__)
373
374#define MF_INFO(comp, ctx, ...) \
375 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::INFO, comp, ctx, \
376 std::source_location::current(), __VA_ARGS__)
377
378#define MF_WARN(comp, ctx, ...) \
379 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::WARN, comp, ctx, \
380 std::source_location::current(), __VA_ARGS__)
381
382#define MF_ERROR(comp, ctx, ...) \
383 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
384 std::source_location::current(), __VA_ARGS__)
385
386// ============================================================================
387// CONVENIENCE MACROS for REAL-TIME LOGGING ONLY
388// ============================================================================
389
390#define MF_RT_TRACE(comp, ctx, ...) \
391 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
392 std::source_location::current(), __VA_ARGS__)
393
394#define MF_RT_WARN(comp, ctx, ...) \
395 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::WARN, comp, ctx, \
396 std::source_location::current(), __VA_ARGS__)
397
398#define MF_RT_ERROR(comp, ctx, ...) \
399 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
400 std::source_location::current(), __VA_ARGS__)
401
402#define MF_RT_DEBUG(comp, ctx, ...) \
403 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
404 std::source_location::current(), __VA_ARGS__)
405
406// ============================================================================
407// CONVENIENCE MACROS for SIMPLE PRINTING (no source-location)
408// ============================================================================
409#define MF_PRINT(comp, ctx, ...) MayaFlux::Journal::print(comp, ctx, __VA_ARGS__)
void scribe_simple(Component component, Context context, std::string_view message)
Log a simple message without source location information.
void scribe_rt(Severity severity, Component component, Context context, std::string_view message, std::source_location location=std::source_location::current())
Log a message from a real-time context with the specified severity, component, and context.
Archivist(const Archivist &)=delete
static Archivist & instance()
Get the singleton instance of the Archivist.
Archivist & operator=(Archivist &&)=delete
Archivist & operator=(const Archivist &)=delete
void scribe(Severity severity, Component component, Context context, std::string_view message, std::source_location location=std::source_location::current())
Log a message with the specified severity, component, and context.
Archivist(Archivist &&)=delete
std::unique_ptr< Impl > m_impl
Singleton class responsible for managing log entries.
Definition Archivist.hpp:17
Context
Execution contexts for log messages.
void error_rethrow(Component component, Context context, std::source_location location=std::source_location::current(), std::string_view additional_context="")
Catch and log an exception, then rethrow it.
void error(Component component, Context context, std::source_location location, std::string_view message)
Log an error message and optionally throw an exception.
fmt::format_string< Args... > format_string
Definition Format.hpp:27
void fatal(Component component, Context context, std::source_location location, std::string_view message)
Log a fatal message and abort the program.
std::string format_runtime(std::string_view fmt_str, Args &&... args)
Definition Format.hpp:36
void print(Component component, Context context, std::string_view message)
Log a simple message without source-location.
void scribe(Severity severity, Component component, Context context, std::source_location location, std::string_view message)
Log a message with the specified severity, component, and context.
std::string format(format_string< std::remove_cvref_t< Args >... > fmt_str, Args &&... args)
Definition Format.hpp:30
void scribe_rt(Severity severity, Component component, Context context, std::source_location location, std::string_view message)
Log a message in a real-time context with automatic source location.