ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
report.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_basecamp of the \aliblong.
4///
5/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#ifndef HPP_ALIB_CAMP_MESSAGE_REPORT
9#define HPP_ALIB_CAMP_MESSAGE_REPORT 1
10#pragma once
13#include <stack>
14
16
17#if ALIB_THREADS
19#endif
20
21namespace alib {
22
23// forward declarations
24IF_ALIB_THREADS( namespace threads { class RecursiveLock; } )
25
26namespace lang { class ReportWriter;
27
28//==================================================================================================
29/// Exception codes of class \alib{lang;Report}.
30//==================================================================================================
32{
33 /// Error when writing a report. This typically indicates an erroneous format string in an
34 /// \ref ALIB_ASSERT_ERROR or related macro.
36};
37
38
39//==================================================================================================
40/// This class provides a simple facility to collect what is called a \e 'report'.
41/// Reports are maintenance messages, mostly error and warning messages, but is not aiming to replace
42/// any sort of error handling.
43/// (In \alib itself, sending a \e 'report' usually precedes raising an error.)
44///
45/// While a process can create different objects of this class, usually, the default instance
46/// available by inheriting from class \alib{singletons;Singleton}.
47/// is sufficient and all \alib internal warnings and errors will be directed to this one.
48/// Software built on \alib should do the same with internal warnings and errors. An own
49/// instance might be created to collect other types of reports.
50///
51/// This class uses a member of type * \alib{lang;ReportWriter} to actually write the reports.
52/// By default, an object of type \alib{lang;ReportWriterStdIO} is attached.
53///
54/// The reporting method, \alib{lang::Report;DoReport} will check the flags provided with
55/// \alib{lang::Report;PushHaltFlags} for message types \c 0 (errors) and \c 1 (warnings), and may
56/// invoke \e assert(). Such assertions are effective only in the debug-builds of the
57/// library/executable. Custom \e 'ReportWriters' might take action (e.g., for security reasons)
58/// and e.g., terminate the application also in release compilations.
59///
60/// To simplify things, a set of macros is defined which are pruned in release
61/// versions of the compilation unit. These are:
62///
63/// - #ALIB_MESSAGE
64/// - #ALIB_ERROR
65/// - #ALIB_WARNING
66/// - #ALIB_ASSERT
67/// - #ALIB_ASSERT_ERROR
68/// - #ALIB_ASSERT_WARNING
69///
70/// In fact, these macros exist in \alibheader{alib.hpp} already, but with the inclusion of
71/// header \alibheader{lang/message/report.hpp}, these macros become redefined to use
72/// this class.
73///
74/// For convenience, with debug-builds of the library, these macros provide the file name,
75/// line number and method name of the invocation source, which can be used by more sophisticated
76/// versions of currently attached \alib{lang;ReportWriter}.
77///
78/// \note
79/// For debug output statements, it is advised to rather use the module \alib_alox
80/// instead of \alib reports and corresponding macros.<br>
81/// In addition, \alox itself replaces the standard report writer given with this class
82/// by an instance of type \alib{lox;ALoxReportWriter}, which uses the \alox standard debug logger.
83//==================================================================================================
84class Report
85{
86 #if !DOXYGEN
87 friend class basecamp::BaseCamp;
88 #endif
89
90 public:
91 /// Types of reports
92 enum class Types
93 {
94 Error, ///< An assertion.
95 Warning, ///< A warning.
96 Message, ///< A report message.
97 };
98
99 // #############################################################################################
100 // protected fields
101 // #############################################################################################
102 protected:
103 /// The default Report used internally by \alib and usually by processes that rely on \alib.
105
106 /// A stack of writers. The topmost one is the actual.
107 /// Can be set at run-time using methods #PushWriter and #PopWriter.
108 std::stack<ReportWriter*> writers;
109
110
111 /// This is a flag that avoids recursion. Recursion might occur when a more sophisticated
112 /// report writer sends a report (e.g., an ALIB Error or Warning). Recursive calls are
113 /// rejected without further notice.
114 bool recursionBlocker = false;
115
116 #if ALIB_THREADS
117 /// A Lock to protect against multithreaded calls.
119 #endif
120
121 /// A stack of integers. The topmost value is used to decide, whether program execution is
122 /// halted on message of type 'error' (type \c 0, bit \c 0) or of type 'warning'
123 /// (type \c 1, bit \c 1).
124 /// Can be set at run-time using methods #PushHaltFlags and #PopHaltFlags.
125 std::stack<int> haltAfterReport;
126
127 // #############################################################################################
128 // constructor/destructor
129 // #############################################################################################
130 public:
131 /// Constructor.
133
134 /// Destructor.
136
137 // #############################################################################################
138 // Interface
139 // #############################################################################################
140 public:
141 //==========================================================================================
142 /// Receives the default report object used by \alib and processes that rely on \alib.
143 /// @returns The default \b Report.
144 //==========================================================================================
145 static
147 {
148 if ( defaultReport == nullptr )
149 defaultReport= new Report();
150 return *defaultReport;
151 }
152
153 //==========================================================================================
154 /// Reports the given message to the current \alib{lang;ReportWriter} in place.
155 /// The default \b ReportWriter will print the message on the process console.
156 /// Furthermore, in debug execution the flags provided with #PushHaltFlags is checked.
157 /// If this is set in respect to type of message (field \alib{lang;Message::Type}),
158 /// the program halts or suspends into the debugger (platform and language specific).
159 ///
160 /// @param message The message to report.
161 //==========================================================================================
163 void DoReport( Message& message );
164
165 //==========================================================================================
166 /// Overloaded method that fetches all arguments needed to construct a
167 /// \alib{lang;Message} object to pass to #DoReport.
168 ///
169 /// @param ci Information about the scope of invocation.
170 /// @param type The report type.
171 /// @param msgs Variadic list of boxes.
172 //==========================================================================================
173 template <typename... Boxes>
174 void DoReport( const CallerInfo& ci,
175 const Enum& type, Boxes&&... msgs )
176 {
177 LocalAllocator1K allocator;
178 Message message( ci, allocator, type, std::forward<Boxes>(msgs)...);
179 DoReport( message );
180 }
181
182 //==========================================================================================
183 /// Writes new values to the internal flags that decide if calls to #DoReport with
184 /// report type \e '0' (errors), respectively report type '>0' (warnings) cause
185 /// to halt program execution by calling <em>assert(false)</em>.
186 /// The previous values can be restored using #PopHaltFlags.
187 /// @param haltOnErrors Specifies if halting on errors is wanted.
188 /// @param haltOnWarnings Specifies if halting on warnings is wanted.
189 //==========================================================================================
191 void PushHaltFlags( bool haltOnErrors, bool haltOnWarnings );
192
193 //==========================================================================================
194 /// Restores the previous values after an invocation to #PushHaltFlags.
195 //==========================================================================================
197 void PopHaltFlags();
198
199 //==========================================================================================
200 /// Sets a new writer. The actual writer is implemented as a stack. It is important to
201 /// keep the right order when pushing and popping writers, as there lifetime is externally
202 /// managed. (In standard use-cases, only one, app-specific writer should be pushed anyhow).
203 /// To give a little assurance, method #PopWriter takes the same parameter as this method
204 /// does, to verify if if the one to be removed is really the topmost.
205 /// @param newWriter The writer to use.
206 //==========================================================================================
208 void PushWriter( ReportWriter* newWriter );
209
210 //==========================================================================================
211 /// Retrieves the actual report writer.
212 ///
213 /// \note This method should not be used to retrieve the writer and use it. It should be used
214 /// only to test the installation.
215 /// @return The actual report writer in place.
216 //==========================================================================================
218 ReportWriter* PeekWriter();
219
220 //==========================================================================================
221 /// Restores the previous writer after setting a new one using #PushWriter.
222 /// It is important to keep the right order when pushing and popping writers, as there
223 /// lifetime is externally managed.
224 /// (In standard use-cases, only one, app-specific writer should be pushed anyhow).
225 /// To give a little assurance, this method #PopWriter takes the same parameter as
226 /// #PushWriter does, to verify if the one to be removed is really the topmost.
227 ///
228 /// @param checkWriter The previously pushed writer (for checking of call order).
229 //==========================================================================================
231 void PopWriter( ReportWriter* checkWriter );
232};// class Report
233
234
235//==================================================================================================
236/// Interface that defines a writer for for %ALib \ref alib::lang::Report "Report".
237/// By default, an instance of \ref alib::lang::ReportWriterStdIO "ReportWriterStdIO"
238/// is installed.
239/// Applications may implement their own ReportWriter.
240//==================================================================================================
242{
243 public:
244 //==========================================================================================
245 /// Virtual destructor
246 //==========================================================================================
247 virtual ~ReportWriter () {}
248
249 //==========================================================================================
250 /// Notify activation/deactivation
251 /// @param phase Information if activated or deactivated.
252 //==========================================================================================
253 virtual void NotifyActivation( lang::Phase phase ) =0;
254
255 //==========================================================================================
256 /// Report a message. Pure virtual abstract interface method.
257 /// @param msg The message to report.
258 //==========================================================================================
259 virtual void Report ( Message& msg ) =0;
260};
261
262//==================================================================================================
263/// The standard \b %ReportWriter writing the message to \c std::cout and \c std::cerr.
264/// The global formatter singleton is used is used to process the objects in the report message.
265/// This is by default of type \alib{lang::format;FormatterPythonStyle;FormatterPythonStyle}.
266/// See static field * \alib{lang::format;Formatter::Default} for more information.
267///
268/// ## Friends ##
269/// class \alib{singletons;Singleton;Singleton<ReportWriterStdIO>}
270/// class \alib{lang;Report}
271//==================================================================================================
272class ReportWriterStdIO : public ReportWriter, public Singleton<ReportWriterStdIO>
273{
274 #if !DOXYGEN
276 friend class Report;
277 friend class basecamp::BaseCamp;
278 #endif
279
280 private:
281 /// Private constructor, while parent class \b %Singleton is friend. Therefore, only one
282 /// instance may exist.
283 ReportWriterStdIO() = default;
284
285 /// Private destructor.
286 virtual ~ReportWriterStdIO() override = default;
287
288 public:
289 //==========================================================================================
290 /// Notify activation/deactivation
291 //==========================================================================================
292 virtual void NotifyActivation ( lang::Phase ) override {}
293
294 //==========================================================================================
295 /// Writes the prefix \"ALib Report (Error):\" (respectively \"ALib Report (Warning):\"
296 /// and the error message to the cout.
297 /// On Windows platform, if a debugger is present, the message is also written using
298 /// <em>OutputDebugStringA</em>.
299 ///
300 /// If the first member of \p msg is of type string and it's contents follow the
301 /// rules given with (higher level) module \alib in respect to
302 /// \alib{lox;Lox::EntryDetectDomain;valid domain path detection}
303 /// then this string is followed by a colon and a space (<c>": "</c>) to separate this
304 /// "topic" from the rest of the message.
305 ///
306 /// @param msg The message to report.
307 //==========================================================================================
309 virtual void Report ( Message& msg ) override;
310};
311
312}} // namespace [alib::lang]
313
315
319
320// #################################################################################################
321// Redefine ALIB Debug macros
322// #################################################################################################
323#if ALIB_DEBUG && !DOXYGEN
324
325 #undef ALIB_ERROR
326 #undef ALIB_WARNING
327 #undef ALIB_MESSAGE
328 #undef ALIB_ASSERT
329 #undef ALIB_ASSERT_ERROR
330 #undef ALIB_ASSERT_WARNING
331 #undef ALIB_ASSERT_MESSAGE
332
333 #define ALIB_ERROR( ... ) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Error , __VA_ARGS__ ); }
334 #define ALIB_WARNING( ... ) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Warning, __VA_ARGS__ ); }
335 #define ALIB_MESSAGE( ... ) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Message, __VA_ARGS__ ); }
336
337 #define ALIB_ASSERT( cond ) { if (!(cond)) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Error , "Internal Error." ); } }
338 #define ALIB_ASSERT_ERROR( cond, ... ) { if (!(cond)) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Error , __VA_ARGS__ ); } }
339 #define ALIB_ASSERT_WARNING( cond, ... ) { if (!(cond)) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Warning, __VA_ARGS__ ); } }
340 #define ALIB_ASSERT_MESSAGE( cond, ... ) { if (!(cond)) { alib::lang::Report::GetDefault().DoReport( ALIB_CALLER_PRUNED, alib::lang::Report::Types::Message, __VA_ARGS__ ); } }
341
342#endif
343
344
345#endif // HPP_ALIB_CAMP_MESSAGE_REPORT
346
virtual ~ReportWriterStdIO() override=default
Private destructor.
virtual void NotifyActivation(lang::Phase) override
Notify activation/deactivation.
Definition report.hpp:292
virtual ~ReportWriter()
Virtual destructor.
Definition report.hpp:247
virtual void Report(Message &msg)=0
virtual void NotifyActivation(lang::Phase phase)=0
void DoReport(const CallerInfo &ci, const Enum &type, Boxes &&... msgs)
Definition report.hpp:174
std::stack< ReportWriter * > writers
Definition report.hpp:108
threads::RecursiveLock lock
A Lock to protect against multithreaded calls.
Definition report.hpp:118
static ALIB_API Report * defaultReport
The default Report used internally by ALib and usually by processes that rely on ALib.
Definition report.hpp:104
Types
Types of reports.
Definition report.hpp:93
static Report & GetDefault()
Definition report.hpp:146
std::stack< int > haltAfterReport
Definition report.hpp:125
#define IF_ALIB_THREADS(...)
Definition alib.hpp:352
#define ALIB_ASSERT_GLOBAL_NAMESPACE
Definition alib.hpp:1002
#define ALIB_ENUMS_ASSIGN_RECORD(TEnum, TRecord)
Definition records.hpp:712
#define ALIB_API
Definition alib.hpp:639
#define ALIB_BOXING_VTABLE_DECLARE(TMapped, Identifier)
Definition vtable.inl:460
#define ALIB_RESOURCED_IN_MODULE(T, Camp, ResName)
ReportExceptions
Exception codes of class Report.
Definition report.hpp:32
Phase
Denotes a phase, e.g.,of a transaction.
Definition alib.cpp:69
lang::basecamp::BaseCamp BASECAMP
The singleton instance of ALib Camp class BaseCamp.
Definition basecamp.cpp:70
threads::RecursiveLock RecursiveLock
Type alias in namespace alib.