MayaFlux 0.4.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 /**
98 * @brief Enable or disable logging for a specific context.
99 * @param ctx The context to enable or disable.
100 * @param enabled True to enable logging for the context, false to disable.
101 */
102 void set_context_filter(Context ctx, bool enabled);
103
104 Archivist(const Archivist&) = delete;
105 Archivist& operator=(const Archivist&) = delete;
106 Archivist(Archivist&&) = delete;
108
109private:
110 Archivist();
112
113 class Impl;
114 std::unique_ptr<Impl> m_impl;
115};
116
117/**
118 * @brief Log a message with the specified severity, component, and context.
119 *
120 * Captures the source location automatically.
121 *
122 * @param severity The severity level of the log message.
123 * @param component The component generating the log message.
124 * @param context The execution context of the log message.
125 * @param location Source location (file, line, function) of the log call.
126 * @param message The log message content.
127 */
128inline void scribe(Severity severity, Component component, Context context,
129 std::source_location location, std::string_view message)
130{
131 Archivist::instance().scribe(severity, component, context, message, location);
132}
133
134/**
135 * @brief printf-style overload of scribe().
136 *
137 * @copydoc scribe(Severity,Component,Context,std::string_view,std::source_location)
138 *
139 * @param msg_or_fmt The format string.
140 * @param args The format arguments.
141 */
142template <typename... Args>
143void scribe(Severity severity, Component component, Context context,
144 std::source_location location, const char* msg_or_fmt, Args&&... args)
145{
146 if constexpr (sizeof...(Args) == 0) {
147 Archivist::instance().scribe(severity, component, context,
148 std::string_view(msg_or_fmt), location);
149 } else {
150 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
151 Archivist::instance().scribe(severity, component, context, msg, location);
152 }
153}
154
155/**
156 * @brief Log a message in a real-time context with automatic source location.
157 *
158 * Optimized for real-time usage and captures the source location automatically.
159 *
160 * @param severity The severity level of the log message.
161 * @param component The component generating the log message.
162 * @param context The execution context of the log message.
163 * @param location Source location (file, line, function) of the log call.
164 * @param message The log message content.
165 */
166inline void scribe_rt(Severity severity, Component component, Context context,
167 std::source_location location, std::string_view message)
168{
169 Archivist::instance().scribe_rt(severity, component, context, message, location);
170}
171
172/**
173 * @brief printf-style overload of scribe_rt().
174 *
175 * @copydoc scribe_rt(Severity,Component,Context,std::string_view,std::source_location)
176 *
177 * @param msg_or_fmt The format string.
178 * @param args The format arguments.
179 */
180template <typename... Args>
181void scribe_rt(Severity severity, Component component, Context context,
182 std::source_location location,
183 const char* msg_or_fmt, Args&&... args)
184{
185 if constexpr (sizeof...(Args) == 0) {
186 Archivist::instance().scribe_rt(severity, component, context,
187 std::string_view(msg_or_fmt), location);
188 } else {
189 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
190 Archivist::instance().scribe_rt(severity, component, context, msg, location);
191 }
192}
193
194/**
195 * @brief Log a simple message without source-location.
196 *
197 * Intended for contexts where source location is unavailable or unnecessary.
198 * It is not effected by severity filters, so use sparingly.
199 *
200 * @param component The component generating the log message.
201 * @param context The execution context of the log message.
202 * @param message The log message content.
203 */
204inline void log(Component component, Context context,
205 std::string_view message)
206{
207 Archivist::instance().scribe_simple(component, context, message);
208}
209
210/**
211 * @brief printf-style overload of log().
212 *
213 * @copydoc log(Component,Context,std::string_view)
214 *
215 * @param msg_or_fmt The format string.
216 * @param args The format arguments.
217 */
218template <typename... Args>
219void log(Component component, Context context,
220 const char* msg_or_fmt, Args&&... args)
221{
222 if constexpr (sizeof...(Args) == 0) {
223 Archivist::instance().scribe_simple(component, context,
224 std::string_view(msg_or_fmt));
225 } else {
226 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
227 Archivist::instance().scribe_simple(component, context, msg);
228 }
229}
230
231/**
232 * @brief Print formatted output directly to stdout with MayaFlux prefix.
233 *
234 * Intended for immediate, unfiltered output without journal infrastructure.
235 * No component/context tagging, no severity filtering, no source location.
236 * Output includes [MayaFlux] prefix to identify framework origin.
237 *
238 * @param message The message or format string.
239 */
240inline void format_print(std::string_view message)
241{
242 std::cout << "[MayaFlux] " << message << '\n';
243}
244
245/**
246 * @brief Printf-style overload of format_print().
247 *
248 * @copydoc format_print(std::string_view)
249 *
250 * @param msg_or_fmt The format string.
251 * @param args The format arguments.
252 */
253template <typename... Args>
254inline void format_print(format_string<std::remove_cvref_t<Args>...> fmt_str, Args&&... args)
255{
256 std::cout << "[MayaFlux] " << format(fmt_str, std::forward<Args>(args)...) << '\n';
257}
258
259/**
260 * @brief Printf-style overload for runtime format strings.
261 *
262 * @copydoc format_print(std::string_view)
263 *
264 * @param fmt_str The runtime format string.
265 * @param args The format arguments.
266 */
267template <typename... Args>
268inline void format_print(const char* fmt_str, Args&&... args)
269{
270 std::cout << "[MayaFlux] " << format_runtime(fmt_str, std::forward<Args>(args)...) << '\n';
271}
272
273/**
274 * @brief Log a fatal message and abort the program.
275 *
276 * @param component The component generating the log message.
277 * @param context The execution context of the log message.
278 * @param location Source location (file, line, function) of the log call.
279 * @param message The fatal message content.
280 */
281[[noreturn]] inline void fatal(Component component, Context context,
282 std::source_location location, std::string_view message)
283{
284 Archivist::instance().scribe(Severity::FATAL, component, context, message, location);
285 std::abort();
286}
287
288/**
289 * @brief fmt-style overload of fatal().
290 *
291 * @copydoc fatal(Component,Context,std::string_view,std::source_location)
292 *
293 * @tparam Args Types of the format arguments.
294 * @param fmt_str The format string.
295 * @param args The format arguments.
296 */
297template <typename... Args>
298[[noreturn]] void fatal(Component component, Context context,
299 std::source_location location, format_string<Args...> fmt_str, Args&&... args)
300{
301 auto msg = format(fmt_str, std::forward<Args>(args)...);
302 Archivist::instance().scribe(Severity::FATAL, component, context, msg, location);
303 std::abort();
304}
305
306/**
307 * @brief Log an error message and optionally throw an exception.
308 *
309 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
310 * @param context The execution context of the log message.
311 * @param location Source location (file, line, function) of the log call.
312 * @param message The error message content.
313 */
314template <typename ExceptionType = std::runtime_error>
315[[noreturn]] void error(Component component, Context context,
316 std::source_location location,
317 std::string_view message)
318{
319 Archivist::instance().scribe(Severity::ERROR, component, context, message, location);
320
321 throw ExceptionType(std::string(message));
322}
323
324/**
325 * @brief fmt-style overload of error().
326 *
327 * @copydoc error(Component,Context,ExceptionBehavior,std::string_view,std::source_location)
328 *
329 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
330 * @tparam Args Types of the format arguments.
331 * @param fmt_str The format string.
332 * @param args The format arguments.
333 */
334template <typename ExceptionType = std::runtime_error, typename... Args>
335[[noreturn]] void error(Component component, Context context,
336 std::source_location location, const char* fmt_str, Args&&... args)
337{
338 if constexpr (sizeof...(Args) == 0) {
339 Archivist::instance().scribe(Severity::ERROR, component, context,
340 std::string_view(fmt_str), location);
341 throw ExceptionType(std::string(fmt_str));
342 } else {
343 auto msg = format_runtime(fmt_str, std::forward<Args>(args)...);
344 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
345 throw ExceptionType(msg);
346 }
347}
348
349/**
350 * @brief Catch and log an exception, then rethrow it.
351 * This function is intended to be called within a catch block.
352 * @param Component The component generating the log message.
353 * @param Context The execution context of the log message.
354 * @param location The source location (file, line, function) of the log call.
355 * @param additional_context Optional additional context to prepend to the exception message.
356 */
357[[noreturn]] inline void error_rethrow(Component component, Context context,
358 std::source_location location = std::source_location::current(),
359 std::string_view additional_context = "")
360{
361 auto ep = std::current_exception();
362 if (!ep) {
363 Archivist::instance().scribe(Severity::ERROR, component, context,
364 "error_rethrow called outside of a catch", location);
365 std::terminate();
366 }
367
368 try {
369 std::rethrow_exception(ep);
370 } catch (const std::exception& e) {
371 std::string msg = std::string(e.what());
372 if (!additional_context.empty()) {
373 msg = std::string(additional_context) + ": " + msg;
374 }
375 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
376 std::rethrow_exception(ep);
377 } catch (...) {
378 std::string msg = "Unknown exception";
379 if (!additional_context.empty()) {
380 msg = std::string(additional_context) + ": " + msg;
381 }
382 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
383 std::rethrow_exception(ep);
384 }
385}
386
387/**
388 * @brief fmt-style overload of error_rethrow().
389 *
390 * @copydoc error_rethrow(Component,Context,std::source_location,std::string_view)
391 *
392 * @tparam Args Types of the format arguments.
393 * @param fmt_str The format string.
394 * @param args The format arguments.
395 */
396template <typename... Args>
397[[noreturn]] inline void error_rethrow(Component component, Context context,
398 std::source_location location, const char* fmt_str, Args&&... args)
399{
400 if constexpr (sizeof...(Args) == 0) {
401 error_rethrow(component, context, location,
402 std::string_view(fmt_str));
403 }
404 auto additional_context = format_runtime(fmt_str, std::forward<Args>(args)...);
405 error_rethrow(component, context, location, additional_context);
406}
407
408} // namespace MayaFlux::Journal
409
410// ============================================================================
411// CONVENIENCE MACROS (for regular logging only)
412// ============================================================================
413
414#define MF_TRACE(comp, ctx, ...) \
415 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
416 std::source_location::current(), __VA_ARGS__)
417
418#define MF_DEBUG(comp, ctx, ...) \
419 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
420 std::source_location::current(), __VA_ARGS__)
421
422#define MF_INFO(comp, ctx, ...) \
423 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::INFO, comp, ctx, \
424 std::source_location::current(), __VA_ARGS__)
425
426#define MF_WARN(comp, ctx, ...) \
427 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::WARN, comp, ctx, \
428 std::source_location::current(), __VA_ARGS__)
429
430#define MF_ERROR(comp, ctx, ...) \
431 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
432 std::source_location::current(), __VA_ARGS__)
433
434#define MF_ASSERT(comp, ctx, condition, ...) \
435 do { \
436 if (!(condition)) [[unlikely]] { \
437 MayaFlux::Journal::scribe( \
438 MayaFlux::Journal::Severity::ERROR, comp, ctx, \
439 std::source_location::current(), \
440 "Assertion failed: " #condition ". " __VA_ARGS__); \
441 MayaFlux::Journal::Archivist::instance().shutdown(); \
442 std::abort(); \
443 } \
444 } while (false)
445
446// ============================================================================
447// CONVENIENCE MACROS for REAL-TIME LOGGING ONLY
448// ============================================================================
449
450#define MF_RT_TRACE(comp, ctx, ...) \
451 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
452 std::source_location::current(), __VA_ARGS__)
453
454#define MF_RT_WARN(comp, ctx, ...) \
455 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::WARN, comp, ctx, \
456 std::source_location::current(), __VA_ARGS__)
457
458#define MF_RT_ERROR(comp, ctx, ...) \
459 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
460 std::source_location::current(), __VA_ARGS__)
461
462#define MF_RT_DEBUG(comp, ctx, ...) \
463 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
464 std::source_location::current(), __VA_ARGS__)
465
466// ============================================================================
467// CONVENIENCE MACROS for SIMPLE LOGGING (no source-location)
468// ============================================================================
469#define MF_LOG(comp, ctx, ...) MayaFlux::Journal::log(comp, ctx, __VA_ARGS__)
470
471// ============================================================================
472// CONVENIENCE MACROS for QUICK OUTPUT (no journal system)
473// ============================================================================
474#define MF_PRINT(...) MayaFlux::Journal::format_print(__VA_ARGS__)
std::string severity
Definition Config.cpp:16
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.
void format_print(std::string_view message)
Print formatted output directly to stdout with MayaFlux prefix.
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 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 log(Component component, Context context, std::string_view message)
Log a simple message without source-location.
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.