Allow fractional frames per second when computing Time from frames.
[libdcp.git] / asdcplib / src / KM_log.h
1 /*
2 Copyright (c) 2004-2009, 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: KM_log.h,v 1.13 2011/03/05 19:15:35 jhurst Exp $
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 #include <iosfwd>
42
43 #define LOG_MSG_IMPL(t) \
44   va_list args; \
45   va_start(args, fmt); \
46   vLogf((t), fmt, &args); \
47   va_end(args)
48
49 // Returns RESULT_PTR if the given argument is NULL.
50 # define KM_TEST_NULL_L(p) \
51   if ( (p) == 0  ) { \
52     DefaultLogSink().Error("NULL pointer in file %s, line %d\n", __FILE__, __LINE__); \
53     return Kumu::RESULT_PTR; \
54   }
55
56 // Returns RESULT_PTR if the given argument is NULL. It then
57 // assumes that the argument is a pointer to a string and returns
58 // RESULT_NULL_STR if the first character is '\0'.
59 //
60 # define KM_TEST_NULL_STR_L(p) \
61   KM_TEST_NULL_L(p); \
62   if ( (p)[0] == '\0' ) { \
63     DefaultLogSink().Error("Empty string in file %s, line %d\n", __FILE__, __LINE__); \
64     return Kumu::RESULT_NULL_STR; \
65   }
66
67
68 namespace Kumu
69 {
70   // no log message will exceed this length
71   const ui32_t MaxLogLength = 512;
72
73   //---------------------------------------------------------------------------------
74   // message logging
75
76   // Log messages are recorded by objects which implement the interface given
77   // in the class ILogSink below. The library maintains a pointer to a default
78   // log sink which is used by the library to report messages.
79   //
80
81   // types of log messages
82   enum LogType_t {
83     LOG_DEBUG,    // detailed developer info
84     LOG_INFO,     // developer info
85     LOG_WARN,     // library non-fatal or near-miss error
86     LOG_ERROR,    // library fatal error
87     LOG_NOTICE,   // application user info
88     LOG_ALERT,    // application non-fatal or near-miss error
89     LOG_CRIT,     // application fatal error
90   };
91
92
93   // OR these values together to come up with sink filter flags.
94   // The default mask is LOG_ALLOW_ALL (all messages).
95   const i32_t LOG_ALLOW_DEBUG      = 0x00000001;
96   const i32_t LOG_ALLOW_INFO       = 0x00000002;
97   const i32_t LOG_ALLOW_WARN       = 0x00000004;
98   const i32_t LOG_ALLOW_ERROR      = 0x00000008;
99   const i32_t LOG_ALLOW_NOTICE     = 0x00000010;
100   const i32_t LOG_ALLOW_ALERT      = 0x00000020;
101   const i32_t LOG_ALLOW_CRIT       = 0x00000040;
102   const i32_t LOG_ALLOW_NONE       = 0x00000000;
103   const i32_t LOG_ALLOW_ALL        = 0x000fffff;
104
105   // options are used to control display format default is 0.
106   const i32_t LOG_OPTION_TYPE      = 0x01000000;
107   const i32_t LOG_OPTION_TIMESTAMP = 0x02000000;
108   const i32_t LOG_OPTION_PID       = 0x04000000;
109   const i32_t LOG_OPTION_NONE      = 0x00000000;
110   const i32_t LOG_OPTION_ALL       = 0xfff00000;
111
112   // A log message with environmental metadata
113  class LogEntry : public IArchive
114   {
115   public:
116     ui32_t      PID;
117     Timestamp   EventTime;
118     LogType_t   Type;
119     std::string Msg;
120
121     LogEntry() {}
122     LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); }
123     virtual ~LogEntry() {}
124
125     // returns true if the message Type is present in the mask
126     bool   TestFilter(i32_t mask_value) const;
127
128     // renders the message into outstr using the given dispaly options
129     // returns outstr&
130     std::string& CreateStringWithOptions(std::string& outstr, i32_t mask_value) const;
131
132     // IArchive
133     bool   HasValue() const { return ! Msg.empty(); }
134     ui32_t ArchiveLength() const;
135     bool   Archive(MemIOWriter* Writer) const;
136     bool   Unarchive(MemIOReader* Reader);
137   };
138
139   //
140   std::basic_ostream<char, std::char_traits<char> >&
141     operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry);
142
143
144   typedef ArchivableList<LogEntry> LogEntryList;
145   
146   //
147   class ILogSink
148     {
149     protected:
150       i32_t m_filter;
151       i32_t m_options;
152
153     public:
154     ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {}
155       virtual ~ILogSink() {}
156
157       void  SetFilterFlag(i32_t f) { m_filter |= f; }
158       void  UnsetFilterFlag(i32_t f) { m_filter &= ~f; }
159       bool  TestFilterFlag(i32_t f) const  { return ((m_filter & f) == f); }
160
161       void  SetOptionFlag(i32_t o) { m_options |= o; }
162       void  UnsetOptionFlag(i32_t o) { m_options &= ~o; }
163       bool  TestOptionFlag(i32_t o) const  { return ((m_options & o) == o); }
164
165       // library messages
166       void Error(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ERROR); }
167       void Warn(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_WARN);  }
168       void Info(const char* fmt, ...)     { LOG_MSG_IMPL(LOG_INFO);  }
169       void Debug(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_DEBUG); }
170
171       // application messages
172       void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); }
173       void Alert(const char* fmt, ...)    { LOG_MSG_IMPL(LOG_ALERT); }
174       void Notice(const char* fmt, ...)   { LOG_MSG_IMPL(LOG_NOTICE); }
175
176       // message with type
177       void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); }
178
179       // actual log sink input
180       virtual void vLogf(LogType_t, const char*, va_list*);
181       virtual void WriteEntry(const LogEntry&) = 0;
182     };
183
184
185   // Sets the internal default sink to the given receiver. If the given value
186   // is zero, sets the default sink to the internally allocated stderr sink.
187   void SetDefaultLogSink(ILogSink* = 0);
188
189   // Returns the internal default sink.
190   ILogSink& DefaultLogSink();
191
192
193   // Sets a log sink as the default until the object is destroyed.
194   // The original default sink is saved and then restored on delete.
195   class LogSinkContext
196   {
197     KM_NO_COPY_CONSTRUCT(LogSinkContext);
198     LogSinkContext();
199     ILogSink* m_orig;
200
201   public:
202     LogSinkContext(ILogSink& sink) {
203       m_orig = &DefaultLogSink();
204       SetDefaultLogSink(&sink);
205     }
206
207     ~LogSinkContext() {
208       SetDefaultLogSink(m_orig);
209     }
210   };
211
212   //------------------------------------------------------------------------------------------
213   //
214
215   // write messages to two subordinate log sinks 
216   class TeeLogSink : public ILogSink
217   {
218     KM_NO_COPY_CONSTRUCT(TeeLogSink);
219     TeeLogSink();
220
221     ILogSink& m_a;
222     ILogSink& m_b;
223
224   public:
225     TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {}
226     virtual ~TeeLogSink() {}
227
228     void WriteEntry(const LogEntry& Entry) {
229       m_a.WriteEntry(Entry);
230       m_b.WriteEntry(Entry);
231     }
232   };
233
234   // collect log messages into the given list, does not test filter
235   class EntryListLogSink : public ILogSink
236   {
237     Mutex m_Lock;
238     LogEntryList& m_Target;
239     KM_NO_COPY_CONSTRUCT(EntryListLogSink);
240     EntryListLogSink();
241
242   public:
243     EntryListLogSink(LogEntryList& target) : m_Target(target) {}
244     virtual ~EntryListLogSink() {}
245
246     void WriteEntry(const LogEntry& Entry);
247   };
248
249
250   // write messages to a POSIX stdio stream
251   class StdioLogSink : public ILogSink
252     {
253       Mutex m_Lock;
254       FILE* m_stream;
255       KM_NO_COPY_CONSTRUCT(StdioLogSink);
256
257     public:
258     StdioLogSink() : m_stream(stderr) {}
259     StdioLogSink(FILE* stream) : m_stream(stream) {}
260       virtual ~StdioLogSink() {}
261
262     void WriteEntry(const LogEntry&);
263     };
264
265 #ifdef KM_WIN32
266   // write messages to the Win32 debug stream
267   class WinDbgLogSink : public ILogSink
268     {
269       Mutex m_Lock;
270       KM_NO_COPY_CONSTRUCT(WinDbgLogSink);
271
272     public:
273       WinDbgLogSink() {}
274       virtual ~WinDbgLogSink() {}
275
276       void WriteEntry(const LogEntry&);
277     };
278 #endif
279
280 #ifndef KM_WIN32
281   // write messages to a POSIX file descriptor
282   class StreamLogSink : public ILogSink
283     {
284       Mutex m_Lock;
285       int   m_fd;
286       KM_NO_COPY_CONSTRUCT(StreamLogSink);
287       StreamLogSink();
288
289     public:
290       StreamLogSink(int fd) : m_fd(fd) {}
291       virtual ~StreamLogSink() {}
292
293       void WriteEntry(const LogEntry&);
294     };
295
296   // write messages to the syslog facility
297   class SyslogLogSink : public ILogSink
298     {
299       Mutex m_Lock;
300       KM_NO_COPY_CONSTRUCT(SyslogLogSink);
301       SyslogLogSink();
302   
303     public:
304       SyslogLogSink(const std::string& source_name, int facility);
305       virtual ~SyslogLogSink();
306       void WriteEntry(const LogEntry&);
307     };
308
309   // convert a string into the appropriate syslog facility id
310   int SyslogNameToFacility(const std::string& facility_name);
311
312 #endif
313
314
315 } // namespace Kumu
316
317 #endif // _KM_LOG_H_
318
319 //
320 // end KM_log.h
321 //