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