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