MayaFlux 0.5.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 "JournalEntry.hpp"
4
5#include <format>
6
7namespace MayaFlux::Journal {
8
9template <typename... Args>
10inline std::string format_runtime(std::string_view fmt_str, Args&&... args)
11{
12 return std::vformat(fmt_str, std::make_format_args(args...));
13}
14
15class Sink;
16
17/**
18 * @class Archivist
19 * @brief Singleton class responsible for managing log entries.
20 *
21 * The Archivist class provides methods to log messages with various severity levels,
22 * components, and contexts. It supports both standard and real-time logging.
23 */
24class MAYAFLUX_API Archivist {
25
26public:
27 /**
28 * @brief Get the singleton instance of the Archivist.
29 * @return Reference to the Archivist instance.
30 */
31 static Archivist& instance();
32
33 /**
34 * @brief Shutdown the logging system.
35 * This should be called once at the end of the application.
36 */
37 static void shutdown();
38
39 /**
40 * @brief Log a message with the specified severity, component, and context.
41 *
42 * This method captures the source location automatically.
43 *
44 * @param severity The severity level of the log message.
45 * @param component The component generating the log message.
46 * @param context The execution context of the log message.
47 * @param message The log message content.
48 * @param location The source location (file, line, function) of the log call.
49 */
50 void scribe(Severity severity, Component component, Context context,
51 std::string_view message,
52 std::source_location location = std::source_location::current());
53
54 /**
55 * @brief Log a message from a real-time context with the specified severity, component, and context.
56 * This method is optimized for real-time contexts and captures the source location automatically.
57 * @param severity The severity level of the log message.
58 * @param component The component generating the log message.
59 * @param context The execution context of the log message.
60 * @param message The log message content.
61 * @param location The source location (file, line, function) of the log call.
62 */
63 void scribe_rt(Severity severity, Component component, Context context,
64 std::string_view message,
65 std::source_location location = std::source_location::current());
66
67 /**
68 * @brief Log a simple message without source location information.
69 * This method is intended for use in contexts where source location is not available or needed.
70 * It is not effected by severity filters, so use sparingly.
71 *
72 * @param component The component generating the log message.
73 * @param context The execution context of the log message.
74 * @param message The log message content.
75 */
76 void scribe_simple(Component component, Context context,
77 std::string_view message);
78
79 /**
80 * @brief Add a log sink for output
81 * @param sink Unique pointer to a LogSink implementation
82 */
83 void add_sink(std::unique_ptr<Sink> sink);
84
85 /**
86 * @brief Remove all sinks
87 */
88 void clear_sinks();
89
90 /**
91 * @brief Synchronously drain all pending ring buffer entries to sinks.
92 *
93 * Blocks until the ring buffer is empty. Called automatically by error(),
94 * error_rethrow(), and fatal() before propagating. Available for any
95 * non-RT caller that needs a guaranteed visibility point.
96 */
97 void flush();
98
99 /**
100 * @brief Set the minimum severity level for logging.
101 * Messages with a severity lower than this level will be ignored.
102 * @param min_sev The minimum severity level to log.
103 */
104 void set_min_severity(Severity min_sev);
105
106 /**
107 * @brief Enable or disable logging for a specific component.
108 * @param comp The component to enable or disable.
109 * @param enabled True to enable logging for the component, false to disable.
110 */
111 void set_component_filter(Component comp, bool enabled);
112
113 /**
114 * @brief Enable or disable logging for a specific context.
115 * @param ctx The context to enable or disable.
116 * @param enabled True to enable logging for the context, false to disable.
117 */
118 void set_context_filter(Context ctx, bool enabled);
119
120 Archivist(const Archivist&) = delete;
121 Archivist& operator=(const Archivist&) = delete;
122 Archivist(Archivist&&) = delete;
124
125private:
126 Archivist();
128
129 class Impl;
130 std::unique_ptr<Impl> m_impl;
131};
132
133/**
134 * @brief Log a message with the specified severity, component, and context.
135 *
136 * Captures the source location automatically.
137 *
138 * @param severity The severity level of the log message.
139 * @param component The component generating the log message.
140 * @param context The execution context of the log message.
141 * @param location Source location (file, line, function) of the log call.
142 * @param message The log message content.
143 */
144inline void scribe(Severity severity, Component component, Context context,
145 std::source_location location, std::string_view message)
146{
147 Archivist::instance().scribe(severity, component, context, message, location);
148}
149
150/**
151 * @brief printf-style overload of scribe().
152 *
153 * @copydoc scribe(Severity,Component,Context,std::string_view,std::source_location)
154 *
155 * @param msg_or_fmt The format string.
156 * @param args The format arguments.
157 */
158template <typename... Args>
159void scribe(Severity severity, Component component, Context context,
160 std::source_location location, const char* msg_or_fmt, Args&&... args)
161{
162 if constexpr (sizeof...(Args) == 0) {
163 Archivist::instance().scribe(severity, component, context,
164 std::string_view(msg_or_fmt), location);
165 } else {
166 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
167 Archivist::instance().scribe(severity, component, context, msg, location);
168 }
169}
170
171/**
172 * @brief Log a message in a real-time context with automatic source location.
173 *
174 * Optimized for real-time usage and captures the source location automatically.
175 *
176 * @param severity The severity level of the log message.
177 * @param component The component generating the log message.
178 * @param context The execution context of the log message.
179 * @param location Source location (file, line, function) of the log call.
180 * @param message The log message content.
181 */
182inline void scribe_rt(Severity severity, Component component, Context context,
183 std::source_location location, std::string_view message)
184{
185 Archivist::instance().scribe_rt(severity, component, context, message, location);
186}
187
188/**
189 * @brief printf-style overload of scribe_rt().
190 *
191 * @copydoc scribe_rt(Severity,Component,Context,std::string_view,std::source_location)
192 *
193 * @param msg_or_fmt The format string.
194 * @param args The format arguments.
195 */
196template <typename... Args>
197void scribe_rt(Severity severity, Component component, Context context,
198 std::source_location location,
199 const char* msg_or_fmt, Args&&... args)
200{
201 if constexpr (sizeof...(Args) == 0) {
202 Archivist::instance().scribe_rt(severity, component, context,
203 std::string_view(msg_or_fmt), location);
204 } else {
205 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
206 Archivist::instance().scribe_rt(severity, component, context, msg, location);
207 }
208}
209
210/**
211 * @brief Log a simple message without source-location.
212 *
213 * Intended for contexts where source location is unavailable or unnecessary.
214 * It is not effected by severity filters, so use sparingly.
215 *
216 * @param component The component generating the log message.
217 * @param context The execution context of the log message.
218 * @param message The log message content.
219 */
220inline void log(Component component, Context context,
221 std::string_view message)
222{
223 Archivist::instance().scribe_simple(component, context, message);
224}
225
226/**
227 * @brief printf-style overload of log().
228 *
229 * @copydoc log(Component,Context,std::string_view)
230 *
231 * @param msg_or_fmt The format string.
232 * @param args The format arguments.
233 */
234template <typename... Args>
235void log(Component component, Context context,
236 const char* msg_or_fmt, Args&&... args)
237{
238 if constexpr (sizeof...(Args) == 0) {
239 Archivist::instance().scribe_simple(component, context,
240 std::string_view(msg_or_fmt));
241 } else {
242 auto msg = format_runtime(msg_or_fmt, std::forward<Args>(args)...);
243 Archivist::instance().scribe_simple(component, context, msg);
244 }
245}
246
247/**
248 * @brief Print formatted output directly to stdout with MayaFlux prefix.
249 *
250 * Intended for immediate, unfiltered output without journal infrastructure.
251 * No component/context tagging, no severity filtering, no source location.
252 * Output includes [MayaFlux] prefix to identify framework origin.
253 *
254 * @param message The message or format string.
255 */
256inline void format_print(std::string_view message)
257{
258 std::cout << "[MayaFlux] " << message << '\n';
259}
260
261/**
262 * @brief Printf-style overload of format_print().
263 *
264 * @copydoc format_print(std::string_view)
265 *
266 * @param msg_or_fmt The format string.
267 * @param args The format arguments.
268 */
269template <typename... Args>
270inline void format_print(std::format_string<std::remove_cvref_t<Args>...> fmt_str, Args&&... args)
271{
272 std::cout << "[MayaFlux] " << format(fmt_str, std::forward<Args>(args)...) << '\n';
273}
274
275/**
276 * @brief Printf-style overload for runtime format strings.
277 *
278 * @copydoc format_print(std::string_view)
279 *
280 * @param fmt_str The runtime format string.
281 * @param args The format arguments.
282 */
283template <typename... Args>
284inline void format_print(const char* fmt_str, Args&&... args)
285{
286 std::cout << "[MayaFlux] " << format_runtime(fmt_str, std::forward<Args>(args)...) << '\n';
287}
288
289/**
290 * @brief Log a fatal message and abort the program.
291 *
292 * @param component The component generating the log message.
293 * @param context The execution context of the log message.
294 * @param location Source location (file, line, function) of the log call.
295 * @param message The fatal message content.
296 */
297[[noreturn]] inline void fatal(Component component, Context context,
298 std::source_location location, std::string_view message)
299{
300 Archivist::instance().scribe(Severity::FATAL, component, context, message, location);
302 std::abort();
303}
304
305/**
306 * @brief fmt-style overload of fatal().
307 *
308 * @copydoc fatal(Component,Context,std::string_view,std::source_location)
309 *
310 * @tparam Args Types of the format arguments.
311 * @param fmt_str The format string.
312 * @param args The format arguments.
313 */
314template <typename... Args>
315[[noreturn]] void fatal(Component component, Context context,
316 std::source_location location, std::format_string<Args...> fmt_str, Args&&... args)
317{
318 auto msg = format(fmt_str, std::forward<Args>(args)...);
319 Archivist::instance().scribe(Severity::FATAL, component, context, msg, location);
321 std::abort();
322}
323
324/**
325 * @brief Log an error message and optionally throw an exception.
326 *
327 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
328 * @param context The execution context of the log message.
329 * @param location Source location (file, line, function) of the log call.
330 * @param message The error message content.
331 */
332template <typename ExceptionType = std::runtime_error>
333[[noreturn]] void error(Component component, Context context,
334 std::source_location location,
335 std::string_view message)
336{
337 Archivist::instance().scribe(Severity::ERROR, component, context, message, location);
339 throw ExceptionType(std::string(message));
340}
341
342/**
343 * @brief fmt-style overload of error().
344 *
345 * @copydoc error(Component,Context,ExceptionBehavior,std::string_view,std::source_location)
346 *
347 * @tparam ExceptionType The exception type to throw when behavior == LogAndThrow.
348 * @tparam Args Types of the format arguments.
349 * @param fmt_str The format string.
350 * @param args The format arguments.
351 */
352template <typename ExceptionType = std::runtime_error, typename... Args>
353[[noreturn]] void error(Component component, Context context,
354 std::source_location location, const char* fmt_str, Args&&... args)
355{
356 if constexpr (sizeof...(Args) == 0) {
357 Archivist::instance().scribe(Severity::ERROR, component, context,
358 std::string_view(fmt_str), location);
360 throw ExceptionType(std::string(fmt_str));
361 } else {
362 auto msg = format_runtime(fmt_str, std::forward<Args>(args)...);
363 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
365 throw ExceptionType(msg);
366 }
367}
368
369/**
370 * @brief Catch and log an exception, then rethrow it.
371 * This function is intended to be called within a catch block.
372 * @param Component The component generating the log message.
373 * @param Context The execution context of the log message.
374 * @param location The source location (file, line, function) of the log call.
375 * @param additional_context Optional additional context to prepend to the exception message.
376 */
377[[noreturn]] inline void error_rethrow(Component component, Context context,
378 std::source_location location = std::source_location::current(),
379 std::string_view additional_context = "")
380{
381 auto ep = std::current_exception();
382 if (!ep) {
383 Archivist::instance().scribe(Severity::ERROR, component, context,
384 "error_rethrow called outside of a catch", location);
386 std::terminate();
387 }
388
389 try {
390 std::rethrow_exception(ep);
391 } catch (const std::exception& e) {
392 std::string msg = std::string(e.what());
393 if (!additional_context.empty()) {
394 msg = std::string(additional_context) + ": " + msg;
395 }
396 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
398 std::rethrow_exception(ep);
399 } catch (...) {
400 std::string msg = "Unknown exception";
401 if (!additional_context.empty()) {
402 msg = std::string(additional_context) + ": " + msg;
403 }
404 Archivist::instance().scribe(Severity::ERROR, component, context, msg, location);
406 std::rethrow_exception(ep);
407 }
408}
409
410/**
411 * @brief fmt-style overload of error_rethrow().
412 *
413 * @copydoc error_rethrow(Component,Context,std::source_location,std::string_view)
414 *
415 * @tparam Args Types of the format arguments.
416 * @param fmt_str The format string.
417 * @param args The format arguments.
418 */
419template <typename... Args>
420[[noreturn]] inline void error_rethrow(Component component, Context context,
421 std::source_location location, const char* fmt_str, Args&&... args)
422{
423 auto msg = format_runtime(fmt_str, std::forward<Args>(args)...);
424 error_rethrow(component, context, location, std::string_view(msg));
425}
426
427} // namespace MayaFlux::Journal
428
429// ============================================================================
430// CONVENIENCE MACROS (for regular logging only)
431// ============================================================================
432
433#define MF_TRACE(comp, ctx, ...) \
434 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
435 std::source_location::current(), __VA_ARGS__)
436
437#define MF_DEBUG(comp, ctx, ...) \
438 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
439 std::source_location::current(), __VA_ARGS__)
440
441#define MF_INFO(comp, ctx, ...) \
442 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::INFO, comp, ctx, \
443 std::source_location::current(), __VA_ARGS__)
444
445#define MF_WARN(comp, ctx, ...) \
446 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::WARN, comp, ctx, \
447 std::source_location::current(), __VA_ARGS__)
448
449#define MF_ERROR(comp, ctx, ...) \
450 MayaFlux::Journal::scribe(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
451 std::source_location::current(), __VA_ARGS__)
452
453#define MF_ASSERT(comp, ctx, condition, ...) \
454 do { \
455 if (!(condition)) [[unlikely]] { \
456 MayaFlux::Journal::scribe( \
457 MayaFlux::Journal::Severity::ERROR, comp, ctx, \
458 std::source_location::current(), \
459 "Assertion failed: " #condition ". " __VA_ARGS__); \
460 MayaFlux::Journal::Archivist::instance().shutdown(); \
461 std::abort(); \
462 } \
463 } while (false)
464
465// ============================================================================
466// CONVENIENCE MACROS for REAL-TIME LOGGING ONLY
467// ============================================================================
468
469#define MF_RT_TRACE(comp, ctx, ...) \
470 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::TRACE, comp, ctx, \
471 std::source_location::current(), __VA_ARGS__)
472
473#define MF_RT_WARN(comp, ctx, ...) \
474 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::WARN, comp, ctx, \
475 std::source_location::current(), __VA_ARGS__)
476
477#define MF_RT_ERROR(comp, ctx, ...) \
478 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::ERROR, comp, ctx, \
479 std::source_location::current(), __VA_ARGS__)
480
481#define MF_RT_DEBUG(comp, ctx, ...) \
482 MayaFlux::Journal::scribe_rt(MayaFlux::Journal::Severity::DEBUG, comp, ctx, \
483 std::source_location::current(), __VA_ARGS__)
484
485// ============================================================================
486// CONVENIENCE MACROS for SIMPLE LOGGING (no source-location)
487// ============================================================================
488#define MF_LOG(comp, ctx, ...) MayaFlux::Journal::log(comp, ctx, __VA_ARGS__)
489
490// ============================================================================
491// CONVENIENCE MACROS for QUICK OUTPUT (no journal system)
492// ============================================================================
493#define MF_PRINT(...) MayaFlux::Journal::format_print(__VA_ARGS__)
std::string severity
Definition Config.cpp:18
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.
void flush()
Synchronously drain all pending ring buffer entries to sinks.
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:24
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.
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 Archivist.hpp:10
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.
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.