source: box/trunk/lib/common/Logging.h @ 3101

Revision 3101, 11.2 KB checked in by chris, 4 weeks ago (diff)

Allow hiding specific exceptions to keep test output cleaner.

Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    Logging.h
5//              Purpose: Generic logging core routines declarations and macros
6//              Created: 2006/12/16
7//
8// --------------------------------------------------------------------------
9
10#ifndef LOGGING__H
11#define LOGGING__H
12
13#include <assert.h>
14
15#include <cerrno>
16#include <cstring>
17#include <iomanip>
18#include <sstream>
19#include <vector>
20
21#include "FileStream.h"
22
23#define BOX_LOG(level, stuff) \
24{ \
25        std::ostringstream _box_log_line; \
26        _box_log_line << stuff; \
27        Logging::Log(level, __FILE__, __LINE__, _box_log_line.str()); \
28}
29
30#define BOX_SYSLOG(level, stuff) \
31{ \
32        std::ostringstream _box_log_line; \
33        _box_log_line << stuff; \
34        Logging::LogToSyslog(level, __FILE__, __LINE__, _box_log_line.str()); \
35}
36
37#define BOX_FATAL(stuff)   BOX_LOG(Log::FATAL,   stuff)
38#define BOX_ERROR(stuff)   BOX_LOG(Log::ERROR,   stuff)
39#define BOX_WARNING(stuff) BOX_LOG(Log::WARNING, stuff)
40#define BOX_NOTICE(stuff)  BOX_LOG(Log::NOTICE,  stuff)
41#define BOX_INFO(stuff)    BOX_LOG(Log::INFO,    stuff)
42#define BOX_TRACE(stuff)   \
43        if (Logging::IsEnabled(Log::TRACE)) \
44        { BOX_LOG(Log::TRACE, stuff) }
45
46#define BOX_SYS_ERRNO_MESSAGE(error_number, stuff) \
47        stuff << ": " << std::strerror(error_number) << \
48        " (" << error_number << ")"
49
50#define BOX_FILE_MESSAGE(filename, message) \
51        message << ": " << filename
52
53#define BOX_SYS_FILE_ERRNO_MESSAGE(filename, error_number, message) \
54        BOX_SYS_ERRNO_MESSAGE(error_number, BOX_FILE_MESSAGE(filename, message))
55
56#define BOX_SYS_ERROR_MESSAGE(stuff) \
57        BOX_SYS_ERRNO_MESSAGE(errno, stuff)
58
59#define BOX_LOG_SYS_WARNING(stuff) \
60        BOX_WARNING(BOX_SYS_ERROR_MESSAGE(stuff))
61#define BOX_LOG_SYS_ERROR(stuff) \
62        BOX_ERROR(BOX_SYS_ERROR_MESSAGE(stuff))
63#define BOX_LOG_SYS_ERRNO(error_number, stuff) \
64        BOX_ERROR(BOX_SYS_ERRNO_MESSAGE(error_number, stuff))
65#define BOX_LOG_SYS_FATAL(stuff) \
66        BOX_FATAL(BOX_SYS_ERROR_MESSAGE(stuff))
67
68#define THROW_SYS_ERROR_NUMBER(message, error_number, exception, subtype) \
69        THROW_EXCEPTION_MESSAGE(exception, subtype, \
70                BOX_SYS_ERRNO_MESSAGE(error_number, message))
71
72#define THROW_SYS_ERROR(message, exception, subtype) \
73        THROW_SYS_ERROR_NUMBER(message, errno, exception, subtype)
74
75#define THROW_SYS_FILE_ERROR(message, filename, exception, subtype) \
76        THROW_SYS_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \
77                errno, exception, subtype)
78
79#define THROW_SYS_FILE_ERRNO(message, filename, error_number, exception, subtype) \
80        THROW_SYS_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \
81                error_number, exception, subtype)
82
83#define THROW_FILE_ERROR(message, filename, exception, subtype) \
84        THROW_EXCEPTION_MESSAGE(exception, subtype, \
85                BOX_FILE_MESSAGE(filename, message))
86
87#ifdef WIN32
88        #define BOX_LOG_WIN_ERROR(stuff) \
89                BOX_ERROR(stuff << ": " << GetErrorMessage(GetLastError()))
90        #define BOX_LOG_WIN_WARNING(stuff) \
91                BOX_WARNING(stuff << ": " << GetErrorMessage(GetLastError()))
92        #define BOX_LOG_WIN_ERROR_NUMBER(stuff, number) \
93                BOX_ERROR(stuff << ": " << GetErrorMessage(number))
94        #define BOX_LOG_WIN_WARNING_NUMBER(stuff, number) \
95                BOX_WARNING(stuff << ": " << GetErrorMessage(number))
96        #define BOX_LOG_NATIVE_ERROR(stuff)   BOX_LOG_WIN_ERROR(stuff)
97        #define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_WIN_WARNING(stuff)
98        #define BOX_WIN_ERRNO_MESSAGE(error_number, stuff) \
99                stuff << ": " << GetErrorMessage(error_number)
100        #define THROW_WIN_ERROR_NUMBER(message, error_number, exception, subtype) \
101                THROW_EXCEPTION_MESSAGE(exception, subtype, \
102                        BOX_WIN_ERRNO_MESSAGE(error_number, message))
103        #define THROW_WIN_FILE_ERRNO(message, filename, error_number, exception, subtype) \
104                THROW_WIN_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \
105                        error_number, exception, subtype)
106        #define THROW_WIN_FILE_ERROR(message, filename, exception, subtype) \
107                THROW_WIN_FILE_ERRNO(message, filename, GetLastError(), \
108                        exception, subtype)
109#else
110        #define BOX_LOG_NATIVE_ERROR(stuff)   BOX_LOG_SYS_ERROR(stuff)
111        #define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_SYS_WARNING(stuff)
112#endif
113
114#ifdef WIN32
115#       define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \
116        BOX_LOG_WIN_ERROR_NUMBER(stuff << " (type " << _type << ", name " << \
117                _name << ", port " << _port << ")", WSAGetLastError())
118#else
119#       define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \
120        BOX_LOG_NATIVE_ERROR(stuff << " (type " << _type << ", name " << \
121                _name << ", port " << _port << ")")
122#endif
123
124#define BOX_FORMAT_HEX32(number) \
125        std::hex << \
126        std::showbase << \
127        std::internal << \
128        std::setw(10) << \
129        std::setfill('0') << \
130        (number) << \
131        std::dec
132
133#define BOX_FORMAT_ACCOUNT(accno) \
134        BOX_FORMAT_HEX32(accno)
135
136#define BOX_FORMAT_OBJECTID(objectid) \
137        std::hex << \
138        std::showbase << \
139        (objectid) << \
140        std::dec
141
142#define BOX_FORMAT_TIMESPEC(timespec) \
143        timespec.tv_sec << \
144        std::setw(6) << \
145        timespec.tv_usec
146
147#undef ERROR
148
149namespace Log
150{
151        enum Level
152        {
153                NOTHING = 1,
154                FATAL,
155                ERROR,
156                WARNING,
157                NOTICE,
158                INFO,
159                TRACE, 
160                EVERYTHING,
161                INVALID = -1
162        };
163}
164
165// --------------------------------------------------------------------------
166//
167// Class
168//              Name:    Logger
169//              Purpose: Abstract base class for log targets
170//              Created: 2006/12/16
171//
172// --------------------------------------------------------------------------
173
174class Logger
175{
176        private:
177        Log::Level mCurrentLevel;
178       
179        public:
180        Logger();
181        Logger(Log::Level level);
182        virtual ~Logger();
183       
184        virtual bool Log(Log::Level level, const std::string& rFile, 
185                int line, std::string& rMessage) = 0;
186       
187        void Filter(Log::Level level)
188        {
189                mCurrentLevel = level;
190        }
191
192        virtual const char* GetType() = 0;
193        Log::Level GetLevel() { return mCurrentLevel; }
194       
195        virtual void SetProgramName(const std::string& rProgramName) = 0;
196};
197
198// --------------------------------------------------------------------------
199//
200// Class
201//              Name:    Console
202//              Purpose: Console logging target
203//              Created: 2006/12/16
204//
205// --------------------------------------------------------------------------
206
207class Console : public Logger
208{
209        private:
210        static bool sShowTag;
211        static bool sShowTime;
212        static bool sShowTimeMicros;
213        static bool sShowPID;
214        static std::string sTag;
215
216        public:
217        virtual bool Log(Log::Level level, const std::string& rFile, 
218                int line, std::string& rMessage);
219        virtual const char* GetType() { return "Console"; }
220        virtual void SetProgramName(const std::string& rProgramName);
221
222        static void SetShowTag(bool enabled);
223        static void SetShowTime(bool enabled);
224        static void SetShowTimeMicros(bool enabled);
225        static void SetShowPID(bool enabled);
226};
227
228// --------------------------------------------------------------------------
229//
230// Class
231//              Name:    Syslog
232//              Purpose: Syslog (or Windows Event Viewer) logging target
233//              Created: 2006/12/16
234//
235// --------------------------------------------------------------------------
236
237class Syslog : public Logger
238{
239        private:
240        std::string mName;
241        int mFacility;
242
243        public:
244        Syslog();
245        virtual ~Syslog();
246       
247        virtual bool Log(Log::Level level, const std::string& rFile, 
248                int line, std::string& rMessage);
249        virtual const char* GetType() { return "Syslog"; }
250        virtual void SetProgramName(const std::string& rProgramName);
251        virtual void SetFacility(int facility);
252        static int GetNamedFacility(const std::string& rFacility);
253};
254
255// --------------------------------------------------------------------------
256//
257// Class
258//              Name:    Logging
259//              Purpose: Static logging helper, keeps track of enabled loggers
260//                       and distributes log messages to them.
261//              Created: 2006/12/16
262//
263// --------------------------------------------------------------------------
264
265class Logging
266{
267        private:
268        static std::vector<Logger*> sLoggers;
269        static bool sLogToSyslog, sLogToConsole;
270        static std::string sContext;
271        static bool sContextSet;
272        static Console* spConsole;
273        static Syslog*  spSyslog;
274        static Log::Level sGlobalLevel;
275        static Logging    sGlobalLogging;
276        static std::string sProgramName;
277       
278        public:
279        Logging ();
280        ~Logging();
281        static void ToSyslog  (bool enabled);
282        static void ToConsole (bool enabled);
283        static void FilterSyslog  (Log::Level level);
284        static void FilterConsole (Log::Level level);
285        static void Add    (Logger* pNewLogger);
286        static void Remove (Logger* pOldLogger);
287        static void Log(Log::Level level, const std::string& rFile, 
288                int line, const std::string& rMessage);
289        static void LogToSyslog(Log::Level level, const std::string& rFile, 
290                int line, const std::string& rMessage);
291        static void SetContext(std::string context);
292        static void ClearContext();
293        static void SetGlobalLevel(Log::Level level) { sGlobalLevel = level; }
294        static Log::Level GetGlobalLevel() { return sGlobalLevel; }
295        static Log::Level GetNamedLevel(const std::string& rName);
296        static bool IsEnabled(Log::Level level)
297        {
298                return (int)sGlobalLevel >= (int)level;
299        }
300        static void SetProgramName(const std::string& rProgramName);
301        static std::string GetProgramName() { return sProgramName; }
302        static void SetFacility(int facility);
303
304        class Guard
305        {
306                private:
307                Log::Level mOldLevel;
308                static int sGuardCount;
309                static Log::Level sOriginalLevel;
310
311                public:
312                Guard(Log::Level newLevel)
313                {
314                        mOldLevel = Logging::GetGlobalLevel();
315                        if(sGuardCount == 0)
316                        {
317                                sOriginalLevel = mOldLevel;
318                        }
319                        sGuardCount++;
320                        Logging::SetGlobalLevel(newLevel);
321                }
322                ~Guard()
323                {
324                        sGuardCount--;
325                        Logging::SetGlobalLevel(mOldLevel);
326                }
327
328                static bool IsActive() { return (sGuardCount > 0); }
329                static Log::Level GetOriginalLevel() { return sOriginalLevel; }
330                static bool IsGuardingFrom(Log::Level originalLevel)
331                {
332                        return IsActive() &&
333                                (int)sOriginalLevel >= (int)originalLevel;
334                }
335        };
336
337        class Tagger
338        {
339                private:
340                std::string mOldTag;
341
342                public:
343                Tagger(const std::string& rTempTag)
344                {
345                        mOldTag = Logging::GetProgramName();
346                        Logging::SetProgramName(mOldTag + " " + rTempTag);
347                }
348                ~Tagger()
349                {
350                        Logging::SetProgramName(mOldTag);
351                }
352        };
353};
354
355class FileLogger : public Logger
356{
357        private:
358        FileStream mLogFile;
359        FileLogger(const FileLogger& forbidden)
360        : mLogFile("") { /* do not call */ }
361       
362        public:
363        FileLogger(const std::string& rFileName, Log::Level Level)
364        : Logger(Level),
365          mLogFile(rFileName, O_WRONLY | O_CREAT | O_APPEND)
366        { }
367       
368        virtual bool Log(Log::Level Level, const std::string& rFile, 
369                int Line, std::string& rMessage);
370       
371        virtual const char* GetType() { return "FileLogger"; }
372        virtual void SetProgramName(const std::string& rProgramName) { }
373};
374
375class HideExceptionMessageGuard
376{
377        public:
378        HideExceptionMessageGuard()
379        {
380                mOldHiddenState = sHiddenState;
381                sHiddenState = true;
382        }
383        ~HideExceptionMessageGuard()
384        {
385                sHiddenState = mOldHiddenState;
386        }
387        static bool ExceptionsHidden() { return sHiddenState; }
388
389        private:
390        static bool sHiddenState;
391        bool mOldHiddenState;
392};
393
394class HideSpecificExceptionGuard
395{
396        private:
397        std::pair<int, int> mExceptionCode;
398
399        public:
400        typedef std::vector<std::pair<int, int> > SuppressedExceptions_t;
401        static SuppressedExceptions_t sSuppressedExceptions;
402
403        HideSpecificExceptionGuard(int type, int subtype)
404        : mExceptionCode(std::pair<int, int>(type, subtype))
405        {
406                sSuppressedExceptions.push_back(mExceptionCode);
407        }
408        ~HideSpecificExceptionGuard()
409        {
410                SuppressedExceptions_t::reverse_iterator i =
411                        sSuppressedExceptions.rbegin();
412                assert(*i == mExceptionCode);
413                sSuppressedExceptions.pop_back();
414        }
415        static bool IsHidden(int type, int subtype);
416};
417
418std::string PrintEscapedBinaryData(const std::string& rInput);
419
420#endif // LOGGING__H
Note: See TracBrowser for help on using the repository browser.