AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
exception.hh
Go to the documentation of this file.
1#ifndef _DRAMA2_EXCEPT_H
2#define _DRAMA2_EXCEPT_H
3
17/*
18 * History:
19 08-Jan-2014 - TJF - Original version.
20 30-Sep-2016 - TJF - There were many changes before now.
21 Fix some formatting in Print() and ErsRep().
22 20-Jan-2019 - TJF - Resolve with with the results of what() being
23 rubbish. This required I added the _whatString
24 item and update it each time the value of toString
25 would be changed. This is likely due to what in
26 effect return a c_str() result from a temp.
27 25-May-2021 - TJF - Have now created exception.cpp and the implementation
28 of all methods with and complexity which are not
29 templates or others required as inline have been
30 moved to it.
31
32 */
33
34#include "drama.h"
35#include "status.h"
36#include "mess.h"
37#include "drama2_err.h"
38#include <string>
39#include <stdio.h>
40#include <stdarg.h>
41#include <string.h>
42#include <execinfo.h> // For backtrace and backtrace_symbols
43#include <sstream> // For ostringstream
44#include <cxxabi.h>
45#include <iostream>
46#include "Ers.h"
47#include <iomanip> // To allow std::hex() to be used.
48#include <vector>
49#include "drama/util.hh"
50
51
60#define DramaTHROW(status_,message_) throw drama::Exception(__func__, __FILE__,__LINE__,(message_), (status_))
61
62// From C++20, we could use std::source_location instead of
63// the macros for these calls. But we want to support back to C++11
64// at this time.
65
66
67
81#define DramaTHROW_S(status_,format_,...) drama::ExceptionThrowSafe(__func__, __FILE__,__LINE__,(status_), (format_), __VA_ARGS__)
82
83
84
85namespace drama
86{
135 class Exception : public std::exception {
136
137 private :
138 // Note line and file are not currently used
139 // through the values are set correctly. It may be appropriate
140 // for methods to be added to access them later.
141 int _lineNum; // Line number exception was thrown from
142 std::string _sourceFile; // Source file exception was thrown from
143 std::string _sourceFunc; // Function exception was thrown from.
144 std::string _origMessage; // Original contextual message
145 StatusType _dramaStatus; // DRAMA Error code.
146 std::ostringstream _message; // Message to be output.
147 std::ostringstream _stackTrace; // Stack trace recorded here.
148 static const unsigned _stackTraceMax = 25; // Max elements in stack trace.
149 std::string _whatString; //Used for result of what() to avoid temp going out of scope.
150
151 static bool _firstReportDone; // We report about the environment variable
152 // that causes more details to be output
153 // on the first report only.
154 bool _alwaysStacktrace = false; // Does we always output the stack trace.
155 /*
156 * Generate the stack track.
157 *
158 * array size is _stackTraceMax, and has been field out
159 * by a call to backtrace(). nSize elements are valid.
160 */
161 void GenerateStackTrace(const int nSize, void *array[]);
162 /*
163 * Support method for GenerateStackTrace.
164 */
165 void AddStackTraceLine(char *stackString);
166
167 public:
174 Exception() : _lineNum(0), _sourceFile("none"),
175 _sourceFunc("none"), _origMessage("none"),
176 _dramaStatus(STATUS__OK) { }
177
178
197 Exception(const std::string func,
198 const std::string &file,
199 const int lineNum,
200 const std::string &message = "",
202 const bool alwaysStacktrace = false);
203
204
220 D2DEPRECATED Exception(
221 bool makeUnique DUNUSED,
222 const std::string func, // Set to __func__
223 const std::string &file, // Set to __FILE__
224 const int lineNum, // Set to __LINE__
225 const StatusType status,
226 const char *format, ...) :
227 Exception(func, file, lineNum, "<<C-Format>", status)
228 {
229 va_list ap;
231 char buffer[200];
232 vsnprintf(buffer, sizeof(buffer), format, ap);
233 _message.str(""); // Clear result of primary constructor.
234 _origMessage = buffer;
235 _message << buffer; // Add the real message required.
236 _whatString = toString();
237 }
238
243 // Needed as _message can't be copied directly.
244 Exception(const Exception &source) :
245 _lineNum(source._lineNum),
246 _sourceFile(source._sourceFile),
247 _sourceFunc(source._sourceFunc),
248 _origMessage(source._origMessage),
249 _dramaStatus(source._dramaStatus),
250 _whatString(source._whatString),
251 _alwaysStacktrace(source._alwaysStacktrace) {
252 _message.str(source._message.str());
253 }
254
260 _lineNum(std::move(source._lineNum)),
261 _sourceFile(std::move(source._sourceFile)),
262 _sourceFunc(std::move(source._sourceFunc)),
263 _origMessage(std::move(source._origMessage)),
264 _dramaStatus(std::move(source._dramaStatus)),
265 _whatString(std::move(source._whatString)),
266 _alwaysStacktrace(source._alwaysStacktrace) {
267
268 // I thought I should have been able to initialize _message above()
269 // using _message(std::move(source._message)) as streams are
270 // are supposed to support move, but this didn't work when tried
271 // with GCC 4.7. So we still use this expensive operation.
272
273 _message.str(source._message.str());
274 _stackTrace.str(source._stackTrace.str());
275 }
276
282 // Needed as _message can't be copied directly.
284
285 if (this == &rhs)
286 return *this;
287
288 this->_sourceFile = rhs._sourceFile;
289 this->_sourceFunc = rhs._sourceFunc;
290 this->_lineNum = rhs._lineNum;
291 this->_origMessage = rhs._origMessage;
292 this->_dramaStatus = rhs._dramaStatus;
293 this->_whatString = rhs._whatString;
294
295 this->_message.str(rhs._message.str()); // Copy in message string.
296 this->_stackTrace.str(rhs._stackTrace.str());
297 this->_alwaysStacktrace = rhs._alwaysStacktrace;
298 return *this;
299 }
305 Exception& operator=(Exception &&rhs) noexcept {
306
307 if (this == &rhs)
308 return *this;
309
310 this->_sourceFile = std::move(rhs._sourceFile);
311 this->_sourceFunc = std::move(rhs._sourceFunc);
312 this->_lineNum = std::move(rhs._lineNum);
313 this->_origMessage = std::move(rhs._origMessage);
314 this->_dramaStatus = std::move(rhs._dramaStatus);
315 this->_whatString = std::move(rhs._whatString);
316
317 // I Think Should be possible, but didn't work in GCC 4.7.1, 4.8.2
318 // this->_message = std::move(rhs._message);
319
320 this->_message.str(rhs._message.str()); // Copy in message string.
321 this->_stackTrace.str(rhs._stackTrace.str());
322
323 this->_alwaysStacktrace = rhs._alwaysStacktrace;
324
325 return *this;
326 }
327
328
329
330
339 virtual std::string toString(bool details=false) const;
340
345 virtual const std::string & getOrigMessage() const {
346 return _origMessage;
347 }
352 virtual int lineNumber() const {
353 return _lineNum;
354 }
360 virtual const std::string & fileName() const {
361 return _sourceFile;
362 }
368 virtual const std::string & function() const {
369 return _sourceFunc;
370 }
378 virtual StatusType dramaStatus() const {
379 return _dramaStatus;
380 }
387 virtual std::string dramaStatusStr() const;
388
398 virtual int statusAsSysExitCode() const {
399 return MessStatusToSysExit(_dramaStatus);
400 }
401
407 void AddErs();
408
409
418 template<class T>
419 Exception & operator << (const T &t) {
420 _message << t;
421 //_message << std::endl << t;
422 _whatString = toString(); // Ensure what string updated.
423 return *this;
424 }
430 virtual std::string getStackTrace() const {
431 return _stackTrace.str();
432 }
433
444 virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const;
445
457 virtual void ErsRep() const;
458
459
465 virtual void ErsOut() const;
466
482 const char* what() const noexcept override {
483 return _whatString.c_str();
485
486
491 void FmtWrite(const char *str);
504 template<typename T, typename... Types>
505 void FmtWrite(const char * format,
506 T value,
507 Types... args) {
508 while (*format)
510 if (*format == '%')
511 {
512 if (*(format + 1) == '%')
513 {
514 ++format;
515 }
516 else
517 {
518 *this << value;
519 FmtWrite(format + 1, args...); // call even when *s == 0 to detect extra arguments
520 return;
521 }
522 }
523 *this << *format++;
524 }
526 "extra arguments provided to drama::ExceptionThrowSafe");
527 }
528
531 virtual ~Exception() {};
533 }; // Class Exception
534
535
536
555 template<typename... Types>
556 void ExceptionThrowSafe[[ noreturn ]] (const std::string func,
557 const std::string &file,
558 const int lineNum,
560 const char * format,
561 Types... args)
562 {
564
565 e.FmtWrite(format, args...);
566
567 throw e;
568
569 }
570
571
572
573
574} // namespace drama
575
576
577
578
587inline std::ostream& operator << (std::ostream &strm, const drama::Exception & e)
588{
589 strm << e.toString(true);
590 return strm;
591}
592
593
594#endif /* _DRAMA2_EXCEPT_H */
D2DEPRECATED Exception(bool makeUnique, const std::string func, const std::string &file, const int lineNum, const StatusType status, const char *format,...)
Create an exception using C printf() style string formatting.
Definition exception.hh:247
virtual std::string getStackTrace() const
Return the stack trace created when the exception was created.
Definition exception.hh:457
virtual int lineNumber() const
Returns the source file line number at which the exception occurred.
Definition exception.hh:379
virtual int statusAsSysExitCode() const
Return a system exit code based on the DRAMA Status.
Definition exception.hh:425
virtual void ErsRep() const
Report details of this exception using ERS.
virtual void ErsOut() const
Output a DRAMA ERS report about this exception.
Exception(const std::string func, const std::string &file, const int lineNum, const std::string &message="", const StatusType status=DRAMA2__CPP_ERROR, const bool alwaysStacktrace=false)
Create an Exception.
virtual const std::string & fileName() const
Returns the name of the C++ source file in which the exception occurred.
Definition exception.hh:387
virtual const std::string & getOrigMessage() const
Returns the exception original message.
Definition exception.hh:372
const char * what() const noexcept override
Get string identifying exception.
Definition exception.hh:509
virtual void Print(FILE *file=stderr, bool include_stacktrace=false) const
Print exception details to a file.
Exception(const Exception &source)
Copy constructor.
Definition exception.hh:271
Exception & operator=(const Exception &rhs)
Assignment operator.
Definition exception.hh:310
void FmtWrite(const char *format, T value, Types... args)
Safe formated write to an exception message string.
Definition exception.hh:532
void FmtWrite(const char *str)
Safe formatted write to an exception message string.
virtual const std::string & function() const
Returns the name of the function in which the exception occurred.
Definition exception.hh:395
void AddErs()
Add the any errors from the current ERS context to the exception.
virtual std::string dramaStatusStr() const
Return the DRAMA Status code converted to a DRAMA.
virtual std::string toString(bool details=false) const
Return the exception string.
Exception & operator<<(const T &t)
Add extra information to an exception message.
Definition exception.hh:446
Exception(Exception &&source) noexcept
Move constructor.
Definition exception.hh:286
Exception()
Create an Exception, details empty.
Definition exception.hh:201
virtual StatusType dramaStatus() const
Return the DRAMA Status code associated with the exception.
Definition exception.hh:405
virtual ~Exception()
Virtual Destructor - since we will be inherited.
Definition exception.hh:558
Exception & operator=(Exception &&rhs) noexcept
Move assignment operator.
Definition exception.hh:332
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:162
std::ostream & operator<<(std::ostream &strm, const drama::Exception &e)
drama::Exception stream output operator
Definition exception.hh:614
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:87
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1322
void ExceptionThrowSafe(const std::string func, const std::string &file, const int lineNum, StatusType status, const char *format, Types... args)
Create and throw an exception, variable argument list, Safe formatting of arguments.
Definition exception.hh:583
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:93
DRAMA 2 include file - Utility macros, types etc.