| 1 |
/********************************************************************** |
| 2 |
oberror.cpp - Handle error messages. |
| 3 |
|
| 4 |
Copyright (C) 2002 by Stefan Kebekus |
| 5 |
Some portions Copyright (C) 2002-2005 by Geoffrey R. Hutchison |
| 6 |
|
| 7 |
This file is part of the Open Babel project. |
| 8 |
For more information, see <http://openbabel.sourceforge.net/> |
| 9 |
|
| 10 |
This program is free software; you can redistribute it and/or modify |
| 11 |
it under the terms of the GNU General Public License as published by |
| 12 |
the Free Software Foundation version 2 of the License. |
| 13 |
|
| 14 |
This program is distributed in the hope that it will be useful, but |
| 15 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 |
General Public License for more details. |
| 18 |
***********************************************************************/ |
| 19 |
|
| 20 |
#include "config.h" |
| 21 |
|
| 22 |
#if HAVE_IOSTREAM |
| 23 |
#include <iostream> |
| 24 |
#elif HAVE_IOSTREAM_H |
| 25 |
#include <iostream.h> |
| 26 |
#endif |
| 27 |
#include <string> |
| 28 |
|
| 29 |
#include "oberror.hpp" |
| 30 |
|
| 31 |
using namespace std; |
| 32 |
|
| 33 |
namespace OpenBabel |
| 34 |
{ |
| 35 |
|
| 36 |
OBMessageHandler obErrorLog; |
| 37 |
|
| 38 |
OBError::OBError( const string &method, |
| 39 |
const string &errorMsg, |
| 40 |
const string &explanation, |
| 41 |
const string &possibleCause, |
| 42 |
const string &suggestedRemedy, |
| 43 |
const obMessageLevel level) : |
| 44 |
_method(method), _errorMsg(errorMsg), _explanation(explanation), |
| 45 |
_possibleCause(possibleCause), _suggestedRemedy(suggestedRemedy), |
| 46 |
_level(level) |
| 47 |
{ } |
| 48 |
|
| 49 |
string OBError::message() const |
| 50 |
{ |
| 51 |
string tmp = "==============================\n"; |
| 52 |
|
| 53 |
if (_level == obError) |
| 54 |
tmp += "*** Open Babel Error "; |
| 55 |
else if (_level == obWarning) |
| 56 |
tmp += "*** Open Babel Warning "; |
| 57 |
else if (_level == obInfo) |
| 58 |
tmp += "*** Open Babel Information "; |
| 59 |
else if (_level == obAuditMsg) |
| 60 |
tmp += "*** Open Babel Audit Log "; |
| 61 |
else |
| 62 |
tmp += "*** Open Babel Debugging Message "; |
| 63 |
|
| 64 |
if (_method.length() != 0) |
| 65 |
{ |
| 66 |
tmp += " in " + _method + string("\n "); |
| 67 |
} |
| 68 |
tmp += _errorMsg + "\n"; |
| 69 |
if (_explanation.size() != 0) |
| 70 |
tmp += " " + _explanation + "\n"; |
| 71 |
if (_possibleCause.size() != 0) |
| 72 |
tmp += " Possible reason: " + _possibleCause + "\n"; |
| 73 |
if (_suggestedRemedy.size() != 0) |
| 74 |
tmp += " Suggestion: " + _suggestedRemedy + "\n"; |
| 75 |
return tmp; |
| 76 |
} |
| 77 |
|
| 78 |
|
| 79 |
/** \class OBMessageHandler |
| 80 |
|
| 81 |
OBMessageHandler represents a configurable error system for Open Babel. |
| 82 |
|
| 83 |
A global error log is defined by the Open Babel library for use of |
| 84 |
internal code as well as code built on top of Open Babel. This class |
| 85 |
allows flexible filtering based on urgency (defined by the |
| 86 |
obMessageLevel type), an "audit log" of molecular changes, including |
| 87 |
recall using the GetMessagesOfLevel method, etc. |
| 88 |
|
| 89 |
The default is to only log and output errors of priority |
| 90 |
obMessageLevel::obError or obMessageLevel::obWarning. |
| 91 |
|
| 92 |
Long-running code may wish to set the size of the in-memory error log |
| 93 |
using the StartLogging / StopLogging methods and |
| 94 |
SetMaxLogEntries. Otherwise, the error log may easily fill up, |
| 95 |
requiring large amounts of memory. |
| 96 |
|
| 97 |
If you wish to divert error output to a different std::ostream (i.e., |
| 98 |
for graphical display, or a file log), use the SetOutputStream method |
| 99 |
-- the default goes to the std::clog stream. Furthermore, some older |
| 100 |
code uses std::cerr for direct error output, rather than the |
| 101 |
ThrowError() methods in this class. To prevent this, you can turn on |
| 102 |
"error wrapping" using the StartErrorWrap method -- this behavior is |
| 103 |
turned off by default. |
| 104 |
|
| 105 |
To make it easy to use the OBMessageHandler class and error logging |
| 106 |
facilities, a global log is defined: |
| 107 |
|
| 108 |
\code |
| 109 |
EXTERN OBMessageHandler obErrorLog; |
| 110 |
\endcode |
| 111 |
|
| 112 |
Therefore, it is very easy to log errors: |
| 113 |
|
| 114 |
\code |
| 115 |
if (atomIndex < 1 || atomIndex > mol.NumAtoms() ) |
| 116 |
obErrorLog.ThrowError(__func__, "Requested Atom Out of Range", obDebug); |
| 117 |
\endcode |
| 118 |
|
| 119 |
or |
| 120 |
|
| 121 |
\code |
| 122 |
stringstream errorMsg; |
| 123 |
errorMsg << " Could not parse line in type translation table types.txt -- incorect number of columns"; |
| 124 |
errorMsg << " found " << vc.size() << " expected " << _ncols << "."; |
| 125 |
obErrorLog.ThrowError(__func__, errorMsg.str(), obInfo); |
| 126 |
\endcode |
| 127 |
|
| 128 |
The __func__ builtin is defined by many compilers (e.g., <a |
| 129 |
href="http://gcc.gnu.org/">GCC</a>) but can be defined to an empty |
| 130 |
string on some platforms without this compiler extension. |
| 131 |
|
| 132 |
Output from the error log typically looks like: |
| 133 |
\code |
| 134 |
============================== |
| 135 |
*** Open Babel Audit Log in ReadChemObject |
| 136 |
OpenBabel::Read molecule Protein Data Bank format |
| 137 |
============================== |
| 138 |
*** Open Babel Information in ParseConectRecord |
| 139 |
WARNING: Problems reading a PDB file |
| 140 |
Problems reading a CONECT record. |
| 141 |
According to the PDB specification, |
| 142 |
the record should have 70 columns, but OpenBabel found 61 columns. |
| 143 |
\endcode |
| 144 |
|
| 145 |
**/ |
| 146 |
|
| 147 |
OBMessageHandler::OBMessageHandler() : |
| 148 |
_outputLevel(obWarning), _outputStream(&clog), _logging(true) |
| 149 |
{ |
| 150 |
// StartErrorWrap(); // (don't turn on error wrapping by default) |
| 151 |
} |
| 152 |
|
| 153 |
OBMessageHandler::~OBMessageHandler() |
| 154 |
{ |
| 155 |
StopErrorWrap(); |
| 156 |
|
| 157 |
// free the internal filter streambuf |
| 158 |
if (_filterStreamBuf != NULL) |
| 159 |
delete _filterStreamBuf; |
| 160 |
} |
| 161 |
|
| 162 |
void OBMessageHandler::ThrowError(OBError err) |
| 163 |
{ |
| 164 |
_messageList.push_back(err); |
| 165 |
if (_maxEntries != 0 && _messageList.size() > _maxEntries) |
| 166 |
_messageList.pop_front(); |
| 167 |
|
| 168 |
if (_logging && err.GetLevel() <= _outputLevel) |
| 169 |
{ |
| 170 |
*_outputStream << err; |
| 171 |
} |
| 172 |
} |
| 173 |
|
| 174 |
void OBMessageHandler::ThrowError(const std::string &method, |
| 175 |
const std::string &errorMsg, |
| 176 |
obMessageLevel level) |
| 177 |
{ |
| 178 |
if (errorMsg.length() > 1) |
| 179 |
{ |
| 180 |
OBError err(method, errorMsg, "", "", "", level); |
| 181 |
ThrowError(err); |
| 182 |
} |
| 183 |
} |
| 184 |
|
| 185 |
std::vector<std::string> OBMessageHandler::GetMessagesOfLevel(const obMessageLevel level) |
| 186 |
{ |
| 187 |
vector<string> results; |
| 188 |
deque<OBError>::iterator i; |
| 189 |
OBError error; |
| 190 |
|
| 191 |
for (i = _messageList.begin(); i != _messageList.end(); i++) |
| 192 |
{ |
| 193 |
error = (*i); |
| 194 |
if (error.GetLevel() == level) |
| 195 |
results.push_back( error.message() ); |
| 196 |
} |
| 197 |
|
| 198 |
return results; |
| 199 |
} |
| 200 |
|
| 201 |
bool OBMessageHandler::StartErrorWrap() |
| 202 |
{ |
| 203 |
if (_inWrapStreamBuf != NULL) |
| 204 |
return true; // already wrapped cerr -- don't go into loops! |
| 205 |
|
| 206 |
_inWrapStreamBuf = cerr.rdbuf(); |
| 207 |
|
| 208 |
if (_filterStreamBuf == NULL) |
| 209 |
{ |
| 210 |
_filterStreamBuf = new(obLogBuf); |
| 211 |
} |
| 212 |
|
| 213 |
cerr.rdbuf(_filterStreamBuf); |
| 214 |
return true; |
| 215 |
} |
| 216 |
|
| 217 |
bool OBMessageHandler::StopErrorWrap() |
| 218 |
{ |
| 219 |
if (_inWrapStreamBuf == NULL) |
| 220 |
return true; // never wrapped cerr |
| 221 |
|
| 222 |
// don't free the filter streambuf yet -- we might start wrapping later |
| 223 |
// it's freed in the dtor |
| 224 |
|
| 225 |
cerr.rdbuf(_inWrapStreamBuf); |
| 226 |
return true; |
| 227 |
} |
| 228 |
|
| 229 |
} // end namespace OpenBabel |
| 230 |
|
| 231 |
//! \file oberror.cpp |
| 232 |
//! \brief Handle error messages, warnings, notices, etc. |
| 233 |
//! Implements OBMessageHandler class. |