58c1b8f176c8c3e6e723497421356bea1123e3a6
[asdcplib.git] / src / KM_log.h
1 /*
2 Copyright (c) 2004-2007, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    KM_log.h
28     \version $Id$
29     \brief   message logging API
30   */
31
32
33 #ifndef _KM_LOG_H_
34 #define _KM_LOG_H_
35
36 #include <KM_platform.h>
37 #include <KM_mutex.h>
38 #include <KM_util.h>
39 #include <stdarg.h>
40 #include <errno.h>
41
42 #define LOG_MSG_IMPL(t) \
43   va_list args; \
44   va_start(args, fmt); \
45   vLogf((t), fmt, &args); \
46   va_end(args)
47
48 // Returns RESULT_PTR if the given argument is NULL.
49 # define KM_TEST_NULL_L(p) \
50   if ( (p) == 0  ) { \
51     DefaultLogSink().Error("NULL pointer in file %s, line %d\n", __FILE__, __LINE__); \
52     return Kumu::RESULT_PTR; \
53   }
54
55 // Returns RESULT_PTR if the given argument is NULL. It then
56 // assumes that the argument is a pointer to a string and returns
57 // RESULT_NULL_STR if the first character is '\0'.
58 //
59 # define KM_TEST_NULL_STR_L(p) \
60   KM_TEST_NULL_L(p); \
61   if ( (p)[0] == '\0' ) { \
62     DefaultLogSink().Error("Empty string in file %s, line %d\n", __FILE__, __LINE__); \
63     return Kumu::RESULT_NULL_STR; \
64   }
65
66
67 namespace Kumu
68 {
69   // no log message will exceed this length
70   const ui32_t MaxLogLength = 512;
71
72   //---------------------------------------------------------------------------------
73   // message logging
74
75   // Log messages are recorded by objects which implement the interface given
76   // in the class ILogSink below. The library maintains a pointer to a default
77   // log sink which is used by the library to report messages.
78   //
79
80   // types of log messages
81   enum LogType_t {
82     LOG_DEBUG,    // detailed developer info
83     LOG_INFO,     // developer info
84     LOG_WARN,     // library non-fatal or near-miss error
85     LOG_ERROR,    // library fatal error
86     LOG_NOTICE,   // application user info
87     LOG_ALERT,    // application non-fatal or near-miss error
88     LOG_CRIT,     // application fatal error
89   };
90
91
92   // OR these values together to come up with sink filter flags.
93   // The default mask is 0x0000ffff (no time stamp, no pid, all messages).
94   const i32_t LOG_ALLOW_TIMESTAMP = 0x01000000;
95   const i32_t LOG_ALLOW_PID       = 0x02000000;
96
97   const i32_t LOG_ALLOW_DEBUG     = 0x00000001;
98   const i32_t LOG_ALLOW_INFO      = 0x00000002;
99   const i32_t LOG_ALLOW_WARN      = 0x00000004;
100   const i32_t LOG_ALLOW_ERROR     = 0x00000008;
101   const i32_t LOG_ALLOW_NOTICE    = 0x00000010;
102   const i32_t LOG_ALLOW_ALERT     = 0x00000020;
103   const i32_t LOG_ALLOW_CRIT      = 0x00000040;
104
105   const i32_t LOG_ALLOW_DEFAULT   = 0x00008000; // show messages having an unknown type
106   const i32_t LOG_ALLOW_NONE      = 0x00000000;
107   const i32_t LOG_ALLOW_MESSAGES  = 0x0000ffff;
108   const i32_t LOG_ALLOW_ANY       = 0xffffffff;
109
110   // A log message with environmental metadata
111  class LogEntry : public IArchive
112   {
113   public:
114     ui32_t      PID;
115     Timestamp   EventTime;
116     LogType_t   Type;
117     std::string Msg;
118
119     LogEntry() {}
120     LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
121     virtual ~LogEntry() {}
122
123     bool   CreateStringWithFilter(i32_t, std::string&) const;
124
125     // IArchive
126     bool   HasValue() const { return ! Msg.empty(); }
127     ui32_t ArchiveLength() const;
128     bool   Archive(MemIOWriter* Writer) const;
129     bool   Unarchive(MemIOReader* Reader);
130   };
131
132
133   typedef ArchivableList<LogEntry> LogEntryList_t;
134   
135   //
136   class ILogSink
137     {
138     protected:
139       i32_t m_filter;
140
141     public:
142       virtual ~ILogSink() {}
143
144       void  SetFilterFlags(i32_t f) { m_filter = f; }
145       i32_t GetFilterFlags() const  { return m_filter; }
146       void  SetFilterFlag(i32_t f) { m_filter |= f; }
147       void  UnsetFilterFlag(i32_t f) { m_filter &= ~f; }
148       bool  TestFilterFlag(i32_t f) const  { return ((m_filter & f) != 0); }
149
150       // library messages
151       void Error(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ERROR); }
152       void Warn(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_WARN);  }
153       void Info(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_INFO);  }
154       void Debug(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_DEBUG); }
155
156       // application messages
157       void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); }
158       void Alert(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ALERT); }
159       void Notice(const char* fmt, ...)   { LOG_MSG_IMPL(LOG_NOTICE); }
160
161       // message with type
162       void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
163
164       // actual log sink input
165       virtual void vLogf(LogType_t, const char*, va_list*);
166       virtual void WriteEntry(const LogEntry&) = 0;
167     };
168
169
170   // Sets the internal default sink to the given receiver. If the given value
171   // is zero, sets the default sink to the internally allocated stderr sink.
172   void SetDefaultLogSink(ILogSink* = 0);
173
174   // Returns the internal default sink.
175   ILogSink& DefaultLogSink();
176
177
178   // Sets a log sink as the default until the object is destroyed.
179   // The original default sink is saved and then restored on delete.
180   class LogSinkContext
181   {
182     KM_NO_COPY_CONSTRUCT(LogSinkContext);
183     LogSinkContext();
184     ILogSink* m_orig;
185
186   public:
187     LogSinkContext(ILogSink& sink) {
188       m_orig = &DefaultLogSink();
189       SetDefaultLogSink(&sink);
190     }
191
192     ~LogSinkContext() {
193       SetDefaultLogSink(m_orig);
194     }
195   };
196
197   //------------------------------------------------------------------------------------------
198   //
199
200   // write messages to two subordinate log sinks 
201   class TeeLogSink : public ILogSink
202   {
203     KM_NO_COPY_CONSTRUCT(TeeLogSink);
204     TeeLogSink();
205
206     ILogSink& m_a;
207     ILogSink& m_b;
208
209   public:
210     TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {}
211     virtual ~TeeLogSink() {}
212
213     void WriteEntry(const LogEntry& Entry) {
214       m_a.WriteEntry(Entry);
215       m_b.WriteEntry(Entry);
216     }
217   };
218
219   // collect log messages into the given list
220   class EntryListLogSink : public ILogSink
221   {
222     KM_NO_COPY_CONSTRUCT(EntryListLogSink);
223     EntryListLogSink();
224
225     LogEntryList_t& m_Target;
226
227   public:
228     EntryListLogSink(LogEntryList_t& target) : m_Target(target) {}
229     virtual ~EntryListLogSink() {}
230
231     void WriteEntry(const LogEntry& Entry) {
232       m_Target.push_back(Entry);
233     }
234   };
235
236
237   // write messages to a POSIX stdio stream
238   class StdioLogSink : public ILogSink
239     {
240       Mutex m_Lock;
241       FILE* m_stream;
242       KM_NO_COPY_CONSTRUCT(StdioLogSink);
243
244     public:
245       StdioLogSink() : m_stream(stderr) {};
246       StdioLogSink(FILE* stream) : m_stream(stream) {}
247       virtual ~StdioLogSink() {}
248
249     void WriteEntry(const LogEntry&);
250     };
251
252 #ifdef KM_WIN32
253   // write messages to the Win32 debug stream
254   class WinDbgLogSink : public ILogSink
255     {
256       Mutex m_Lock;
257       KM_NO_COPY_CONSTRUCT(WinDbgLogSink);
258
259     public:
260       WinDbgLogSink() {}
261       virtual ~WinDbgLogSink() {}
262
263       void WriteEntry(const LogEntry&);
264     };
265 #endif
266
267 #ifndef KM_WIN32
268   // write messages to a POSIX file descriptor
269   class StreamLogSink : public ILogSink
270     {
271       Mutex m_Lock;
272       int   m_fd;
273       KM_NO_COPY_CONSTRUCT(StreamLogSink);
274       StreamLogSink();
275
276     public:
277       StreamLogSink(int fd) : m_fd(fd) {}
278       virtual ~StreamLogSink() {}
279
280       void WriteEntry(const LogEntry&);
281     };
282 #endif
283
284
285 } // namespace Kumu
286
287 #endif // _KM_LOG_H_
288
289 //
290 // end KM_log.h
291 //