1 /**********************************************************************
2 oberror.h - Handle error messages, warnings, notices, etc.
3 
4 Copyright (C) 2002 by Stefan Kebekus
5 Some portions Copyright (C) 2003-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 #ifndef OB_ERROR_H
21 #define OB_ERROR_H
22 
23 #include <openbabel/babelconfig.h>
24 
25 #include <iosfwd>
26 #include <sstream>
27 #include <string>
28 #include <vector>
29 #include <deque>
30 
31 #ifndef OBERROR
32 #define OBERROR
33 #endif
34 
35 namespace OpenBabel
36 {
37 
38   //! \brief Levels of error and audit messages to allow filtering
39   enum obMessageLevel {
40     obError,     //!< for critical errors (e.g., cannot read a file)
41     obWarning,   //!< for non-critical problems (e.g., molecule appears empty)
42     obInfo,      //!< for informative messages (e.g., file is a non-standard format)
43     obAuditMsg,  //!< for messages auditing methods which destroy or perceive molecular data (e.g., kekulization, atom typing, etc.)
44     obDebug      //!< for messages only useful for debugging purposes
45   };
46 
47   enum errorQualifier {always, onceOnly};
48 
49   /** \class OBError oberror.h <openbabel/oberror.h>
50       \brief Customizable error handling and logging -- store a message,
51       including the method yielding the error, causes, etc. **/
52   class OBERROR OBError
53     {
54     public:
55 
56       //! Constructor for an error message e.g. OBError(__FUNCTION__, " message ")
57       OBError( const std::string &method = "",
58                const std::string &errorMsg = "",
59                const std::string &explanation = "",
60                const std::string &possibleCause = "",
61                const std::string &suggestedRemedy = "",
62                const obMessageLevel = obDebug );
63 
64       //! \return A formatted message string, including optional explanations, etc.
65       std::string message(void) const;
66 
67       //! Output a formatted message string
68       friend std::ostream& operator<< ( std::ostream &os, const OBError &er )
69         { return os << er.message(); };
70 
71       /** \return The method which caused this error
72           (typically supplied via the __FUNCTION__ compiler macro **/
GetMethod()73       std::string    GetMethod() const           { return _method;          }
74       //! \return The main error message
GetError()75       std::string    GetError() const            { return _errorMsg;        }
76       //! \return A more detailed explanation of the error (optional)
GetExplanation()77       std::string    GetExplanation() const      { return _explanation;     }
78       //! \return A possible cause for the error (optional)
GetPossibleCause()79       std::string    GetPossibleCause() const    { return _possibleCause;   }
80       //! \return The suggested workaround or remedy for the error (optional)
GetSuggestedRemedy()81       std::string    GetSuggestedRemedy() const  { return _suggestedRemedy; }
82       //! \return The severity level of this error
GetLevel()83       obMessageLevel GetLevel() const            { return _level;           }
84 
85       bool operator== (const OBError&)const;
86 
87     protected:
88 
89       //! The method causing the error (typically from the compiler macro __FUNCTION__)
90       std::string _method;
91       //! The actual error message
92       std::string _errorMsg;
93       //! Optional explanation message: more detailed than the brief error
94       std::string _explanation;
95       //! Optional cause message
96       std::string _possibleCause;
97       //! Optional workaround or remedy
98       std::string _suggestedRemedy;
99 
100       //! The severity level: used for filtering via OBMessageHandler
101       obMessageLevel _level;
102     };
103 
104   //! \brief Handle error messages, warnings, debugging information and the like
105   // More documentation in oberror.cpp
106   class OBERROR OBMessageHandler
107     {
108     protected:
109       //! Count of messages at each message level
110       unsigned int           _messageCount[5];
111 
112     public:
113       OBMessageHandler();
114       ~OBMessageHandler();
115 
116       //! Throw an error with an already-formatted OBError object
117       void ThrowError(OBError err, errorQualifier qqualifier = always);
118       //! Throw an error in the specified method with an appropriate level
119       void ThrowError(const std::string &method, const std::string &errorMsg,
120                       obMessageLevel level = obDebug, errorQualifier qualifier = always);
121 
122       //! \return all messages matching a specified level
123       std::vector<std::string> GetMessagesOfLevel(const obMessageLevel);
124 
125       //! Start logging messages (default)
StartLogging()126       void StartLogging() { _logging = true; }
127       //! Stop logging messages completely
StopLogging()128       void StopLogging()  { _logging = false; }
129 
130       //! Set the maximum number of entries (or 0 for no limit)
SetMaxLogEntries(unsigned int max)131       void SetMaxLogEntries(unsigned int max) { _maxEntries = max; }
132       //! \return the current maximum number of entries (default = 0 for no limit)
GetMaxLogEntries()133       unsigned int GetMaxLogEntries() { return _maxEntries; }
134 
135       //! Clear the current message log entirely
ClearLog()136       void ClearLog() { _messageList.clear(); }
137 
138       //! \brief Set the level of messages to output
139       //! (i.e., messages with at least this priority will be output)
SetOutputLevel(const obMessageLevel level)140       void SetOutputLevel(const obMessageLevel level) { _outputLevel = level; }
141       //! \return the current output level
GetOutputLevel()142       obMessageLevel GetOutputLevel() { return _outputLevel; }
143 
SetOutputStream(std::ostream * os)144       void SetOutputStream(std::ostream *os) { _outputStream = os; }
GetOutputStream()145       std::ostream* GetOutputStream() { return _outputStream; }
146 
147       //! Start "wrapping" messages to cerr into ThrowError calls
148       bool StartErrorWrap();
149       //! Turn off "wrapping" messages, restoring normal cerr use (default)
150       bool StopErrorWrap();
151 
152       //! \return Count of messages received at the obError level
GetErrorMessageCount()153       unsigned int GetErrorMessageCount() { return _messageCount[obError];}
154       //! \return Count of messages received at the obWarning level
GetWarningMessageCount()155       unsigned int GetWarningMessageCount() { return _messageCount[obWarning];}
156       //! \return Count of messages received at the obInfo level
GetInfoMessageCount()157       unsigned int GetInfoMessageCount() { return _messageCount[obInfo];}
158       //! \return Count of messages received at the obAuditMsg level
GetAuditMessageCount()159       unsigned int GetAuditMessageCount() { return _messageCount[obAuditMsg];}
160       //! \return Count of messages received at the obDebug level
GetDebugMessageCount()161       unsigned int GetDebugMessageCount() { return _messageCount[obDebug];}
162       //! \return Summary of messages received at all levels
163       std::string GetMessageSummary();
164 
165     protected:
166       //! Log of messages for later retrieval via GetMessagesOfLevel()
167       std::deque<OBError>    _messageList;
168 
169       //! Filtering level for messages and logging (messages of lower priority will be ignored
170       obMessageLevel         _outputLevel;
171 
172       // self-explanatory
173       std::ostream          *_outputStream;
174 
175       //! Whether messages will be logged into _messageList
176       bool                   _logging;
177       //! The maximum size of _messageList log
178       unsigned int           _maxEntries;
179 
180       //! The default stream buffer for the output stream (saved if wrapping is ued)
181       std::streambuf        *_inWrapStreamBuf;
182       //! The filtered obLogBuf stream buffer to wrap error messages
183       std::streambuf        *_filterStreamBuf;
184     };
185 
186   //! Global OBMessageHandler error handler
187   OBERROR extern  OBMessageHandler obErrorLog;
188 
189   //! \class obLogBuf oberror.h <openbabel/oberror.h>
190   //! \brief A minimal streambuf derivative to wrap calls to cerr into calls to OBMessageHandler as needed
191   /** This class is used for internal use, via OBMessageHandler::StartErrorWrap()
192       To use this class, use the global OBMessageHandler object @p obErrorLog:
193       \code
194       obErrorLog.StartErrorWrap(); // All output to cerr will become OBErrors
195       cerr << " This is error 1" << endl; // flush output, create a new error
196       cerr << " Error 2" << endl;
197       cerr << " Error 3: Done with output wrapping." << endl;
198       obErrorLog.StopErrorWrap(); // return to default behavior
199       \endcode
200   **/
201   class OBERROR obLogBuf : public std::stringbuf
202     {
203     public:
204       //! Close the output buffer, flush, and call OBMessageHandler::ThrowError()
~obLogBuf()205       virtual ~obLogBuf() { sync(); }
206 
207     protected:
208       //! Call OBMessageHandler::ThrowError() and flush the buffer
sync()209       int sync()
210         {
211           obErrorLog.ThrowError("", str(), obInfo);
212           str(std::string()); // clear the buffer
213           return 0;
214         }
215     };
216 
217 } // end namespace OpenBabel
218 
219 #endif
220 
221 //! \file oberror.h
222 //! \brief Handle error messages, warnings, notices, etc.
223