[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: error/info reporting, exception handling, etc.
HI,
Attached is an exception class I wrote many moons ago.
Mark M. Ito wrote:
> Offliners,
>
> While I am in an epistolary mood let me ask about another few software
> items. These are issues that I think have to be addressed on a global,
> cooperative level (and I think they have been raised before). They are
> related:
>
> 1. debug level
> Shouldn't we have a convention for setting the level of informational
> messages a given package reports and an external way to set it? How
> about debug level 0 (silent), 1 (normal information), 2 (some details
> about execution), 3 (all the details) or some such?
>
> 2. message logging
> Should we have some sort of custom stream to capture all of the "print
> statements" from the various packages? That would allow a more or less
> standard log file to be created from jobs.
>
> 3. exception handling
> Shouldn't we define a convention for C++ exception throwing and
> catching, including a standard DException class?
>
> I remember that some work was done on these things. Does anyone remember
> that and if any of that work could serve as a starting point, at least
> for discussion?
>
> -- Mark
>
--
Sincerely,
Elliott
================================================================================
Those raised in a morally relative or neutral environment will hold
no truths to be self-evident.
Elliott Wolin
Staff Physicist, Jefferson Lab
12000 Jefferson Ave
Suite 8 MS 12A1
Newport News, VA 23606
757-269-7365
================================================================================
// JException.hxx
// Base exception class for JANA package
// EJW, JLab, 19-apr-2007
#ifndef _JException_hxx
#define _JException_hxx
#include <exception>
#include <string>
#include <sstream>
// for stack trace
#ifdef SunOS
#else
#include <execinfo.h>
#include <cxxabi.h>
#endif
// not sure if this is needed...also, what about __FUNCTION__
/**
* How to use SOURCEINFO macro in JException constructor:
*
* throw(JException("This is a devilish error", 666, SOURCEINFO));
*/
#define SOURCEINFO __FILE__,__LINE__
/** JANA packages lives in the jana namespace. */
namespace jana {
using namespace std;
/**
* JANA exception class contains text, code, source file info, and trace info.
* Note that trace does not work on all architectures.
*
* Trace is automatically generated. On linux must link with -rdynamic to get useful trace.
*/
class JException : public exception {
public:
JException(const string &txt);
JException(const string &txt, const char *file, int line);
JException(const string &txt, int c);
JException(const string &txt, int c, const char *file, int line);
virtual ~JException(void) throw() {} /**<Destructor does nothing.*/
virtual string toString(void) const throw();
virtual string toString(bool includeTrace) const throw();
virtual const char* what(void) const throw();
static string getStackTrace(void);
public:
string text; /**<Exception text.*/
int code; /**<Exception code.*/
string source; /**<Exception source file info.*/
string trace; /**<Stack trace generated automatically. Does not work on all architectures.*/
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/**
* Constructor given text field.
*
* @param txt Exception text
*/
JException::JException(const string &txt) : text(txt), code(0), source(""), trace(getStackTrace()) {}
//-----------------------------------------------------------------------------
/**
* Constructor given text field and source file info.
*
* @param txt Exception text
* @param file Name of file where exception raised
* @param line Line in file where exception raised
*/
JException::JException(const string &txt, const char *file, int line) : text(txt), code(0), trace(getStackTrace()) {
stringstream ss;
ss << "File: " << file << ", Line: " << line << ends;
source=ss.str();
}
//-----------------------------------------------------------------------------
/**
* Constructor given text field and code.
*
* @param txt Exception text
* @param c Exception code
*/
JException::JException(const string &txt, int c) : text(txt), code(c), source(""), trace(getStackTrace()) {}
//-----------------------------------------------------------------------------
/**
* Constructor given text field, code, and source file info.
*
* @param txt Exception text
* @param c Exception code
* @param file Name of file where exception raised
* @param line Line in file where exception raised
*/
JException::JException(const string &txt, int c, const char *file, int line) : text(txt), code(c), trace(getStackTrace()) {
stringstream ss;
ss << "File: " << file << ", Line: " << line << ends;
source=ss.str();
}
//-----------------------------------------------------------------------------
/**
* Returns string representation of exception including trace.
*
* @return String representation of exception
*/
string JException::toString(void) const throw() {
return(toString(true));
}
//-----------------------------------------------------------------------------
/**
* Returns string representation of exception.
*
* @param includeTrace true to include trace info
*
* @return String representation of exception
*/
string JException::toString(bool includeTrace) const throw() {
ostringstream oss;
oss << endl << "?JException: code = " << code << " text = " << text << endl << endl;
if(source.size()>0) oss << source << endl << endl;
if(includeTrace&&(trace.size()>0)) oss << "Stack trace:" << endl << endl << trace << endl;
oss << ends;
return(oss.str());
}
//-----------------------------------------------------------------------------
/**
* Returns char* representation of exception.
*
* @return char* representation of exception
*/
const char *JException::what(void) const throw() {
return(toString().c_str());
}
//-----------------------------------------------------------------------------
/**
* Generates stack trace using Linux system calls, doesn't work on solaris.
*
* @return String containing stack trace
*/
string JException::getStackTrace(void) {
#ifdef SunOS
return("");
#else
size_t dlen;
char dname[1024];
void *trace[1024];
int status;
// get trace messages
int trace_size = backtrace(trace,1024);
if(trace_size>1024)trace_size=1024;
char **messages = backtrace_symbols(trace, trace_size);
// de-mangle and create string
stringstream ss;
for(int i=0; i<trace_size; ++i) {
// find first '(' and '+'
char *ppar = strchr(messages[i],'(');
char *pplus = strchr(messages[i],'+');
if((ppar!=NULL)&&(pplus!=NULL)) {
// replace '+' with nul, then get de-mangled name
*pplus='\0';
abi::__cxa_demangle(ppar+1,dname,&dlen,&status);
// add to stringstream
*(ppar+1)='\0';
*pplus='+';
ss << " " << messages[i] << dname << pplus << endl;
} else {
ss << " " << messages[i] << endl;
}
}
ss << ends;
free(messages);
return(ss.str());
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
} // namespace jana
#endif /* _JException_hxx */