Rename local variable "PIC" to "pic" so to avoid namespace
[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 LOG_ALLOW_ALL (all messages).
94   const i32_t LOG_ALLOW_DEBUG      = 0x00000001;
95   const i32_t LOG_ALLOW_INFO       = 0x00000002;
96   const i32_t LOG_ALLOW_WARN       = 0x00000004;
97   const i32_t LOG_ALLOW_ERROR      = 0x00000008;
98   const i32_t LOG_ALLOW_NOTICE     = 0x00000010;
99   const i32_t LOG_ALLOW_ALERT      = 0x00000020;
100   const i32_t LOG_ALLOW_CRIT       = 0x00000040;
101   const i32_t LOG_ALLOW_NONE       = 0x00000000;
102   const i32_t LOG_ALLOW_ALL        = 0x000fffff;
103
104   // options are used to control display format default is 0.
105   const i32_t LOG_OPTION_TYPE      = 0x01000000;
106   const i32_t LOG_OPTION_TIMESTAMP = 0x02000000;
107   const i32_t LOG_OPTION_PID       = 0x04000000;
108   const i32_t LOG_OPTION_NONE      = 0x00000000;
109   const i32_t LOG_OPTION_ALL       = 0xfff00000;
110
111   // A log message with environmental metadata
112  class LogEntry : public IArchive
113   {
114   public:
115     ui32_t      PID;
116     Timestamp   EventTime;
117     LogType_t   Type;
118     std::string Msg;
119
120     LogEntry() {}
121     LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
122     virtual ~LogEntry() {}
123
124     // returns true if the message Type is present in the mask
125     bool   TestFilter(i32_t mask_value) const;
126
127     // renders the message into outstr using the given dispaly options
128     // returns outstr&
129     std::string& CreateStringWithOptions(std::string& outstr, i32_t mask_value) const;
130
131     // IArchive
132     bool   HasValue() const { return ! Msg.empty(); }
133     ui32_t ArchiveLength() const;
134     bool   Archive(MemIOWriter* Writer) const;
135     bool   Unarchive(MemIOReader* Reader);
136   };
137
138
139   typedef ArchivableList<LogEntry> LogEntryList;
140   
141   //
142   class ILogSink
143     {
144     protected:
145       i32_t m_filter;
146       i32_t m_options;
147
148     public:
149     ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {}
150       virtual ~ILogSink() {}
151
152       void  SetFilterFlag(i32_t f) { m_filter |= f; }
153       void  UnsetFilterFlag(i32_t f) { m_filter &= ~f; }
154       bool  TestFilterFlag(i32_t f) const  { return ((m_filter & f) == f); }
155
156       void  SetOptionFlag(i32_t o) { m_options |= o; }
157       void  UnsetOptionFlag(i32_t o) { m_options &= ~o; }
158       bool  TestOptionFlag(i32_t o) const  { return ((m_options & o) == o); }
159
160       // library messages
161       void Error(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ERROR); }
162       void Warn(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_WARN);  }
163       void Info(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_INFO);  }
164       void Debug(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_DEBUG); }
165
166       // application messages
167       void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); }
168       void Alert(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ALERT); }
169       void Notice(const char* fmt, ...)   { LOG_MSG_IMPL(LOG_NOTICE); }
170
171       // message with type
172       void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
173
174       // actual log sink input
175       virtual void vLogf(LogType_t, const char*, va_list*);
176       virtual void WriteEntry(const LogEntry&) = 0;
177     };
178
179
180   // Sets the internal default sink to the given receiver. If the given value
181   // is zero, sets the default sink to the internally allocated stderr sink.
182   void SetDefaultLogSink(ILogSink* = 0);
183
184   // Returns the internal default sink.
185   ILogSink& DefaultLogSink();
186
187
188   // Sets a log sink as the default until the object is destroyed.
189   // The original default sink is saved and then restored on delete.
190   class LogSinkContext
191   {
192     KM_NO_COPY_CONSTRUCT(LogSinkContext);
193     LogSinkContext();
194     ILogSink* m_orig;
195
196   public:
197     LogSinkContext(ILogSink& sink) {
198       m_orig = &DefaultLogSink();
199       SetDefaultLogSink(&sink);
200     }
201
202     ~LogSinkContext() {
203       SetDefaultLogSink(m_orig);
204     }
205   };
206
207   //------------------------------------------------------------------------------------------
208   //
209
210   // write messages to two subordinate log sinks 
211   class TeeLogSink : public ILogSink
212   {
213     KM_NO_COPY_CONSTRUCT(TeeLogSink);
214     TeeLogSink();
215
216     ILogSink& m_a;
217     ILogSink& m_b;
218
219   public:
220     TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {}
221     virtual ~TeeLogSink() {}
222
223     void WriteEntry(const LogEntry& Entry) {
224       m_a.WriteEntry(Entry);
225       m_b.WriteEntry(Entry);
226     }
227   };
228
229   // collect log messages into the given list, does not test filter
230   class EntryListLogSink : public ILogSink
231   {
232     Mutex m_Lock;
233     LogEntryList& m_Target;
234     KM_NO_COPY_CONSTRUCT(EntryListLogSink);
235     EntryListLogSink();
236
237   public:
238     EntryListLogSink(LogEntryList& target) : m_Target(target) {}
239     virtual ~EntryListLogSink() {}
240
241     void WriteEntry(const LogEntry& Entry);
242   };
243
244
245   // write messages to a POSIX stdio stream
246   class StdioLogSink : public ILogSink
247     {
248       Mutex m_Lock;
249       FILE* m_stream;
250       KM_NO_COPY_CONSTRUCT(StdioLogSink);
251
252     public:
253     StdioLogSink() : m_stream(stderr) {}
254     StdioLogSink(FILE* stream) : m_stream(stream) {}
255       virtual ~StdioLogSink() {}
256
257     void WriteEntry(const LogEntry&);
258     };
259
260 #ifdef KM_WIN32
261   // write messages to the Win32 debug stream
262   class WinDbgLogSink : public ILogSink
263     {
264       Mutex m_Lock;
265       KM_NO_COPY_CONSTRUCT(WinDbgLogSink);
266
267     public:
268       WinDbgLogSink() {}
269       virtual ~WinDbgLogSink() {}
270
271       void WriteEntry(const LogEntry&);
272     };
273 #endif
274
275 #ifndef KM_WIN32
276   // write messages to a POSIX file descriptor
277   class StreamLogSink : public ILogSink
278     {
279       Mutex m_Lock;
280       int   m_fd;
281       KM_NO_COPY_CONSTRUCT(StreamLogSink);
282       StreamLogSink();
283
284     public:
285       StreamLogSink(int fd) : m_fd(fd) {}
286       virtual ~StreamLogSink() {}
287
288       void WriteEntry(const LogEntry&);
289     };
290 #endif
291
292
293 } // namespace Kumu
294
295 #endif // _KM_LOG_H_
296
297 //
298 // end KM_log.h
299 //