[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 */