hmac pad fix
[asdcplib.git] / src / KM_log.cpp
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.cpp
28     \version $Id$
29     \brief   message logging API
30   */
31
32 #include <KM_util.h>
33 #include <KM_log.h>
34 #include <KM_mutex.h>
35 #include <sys/types.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <iostream>
39 #include <sstream>
40
41 #ifdef KM_WIN32
42 #define getpid GetCurrentProcessId
43 #else
44 #include <unistd.h>
45 #endif
46
47 //------------------------------------------------------------------------------------------
48 //
49
50 void
51 Kumu::ILogSink::vLogf(LogType_t type, const char* fmt, va_list* list)
52 {
53   char buf[MaxLogLength];
54   vsnprintf(buf, MaxLogLength, fmt, *list);
55
56   WriteEntry(LogEntry(getpid(), type, buf));
57 }
58
59 //------------------------------------------------------------------------------------------
60 //
61
62 static Kumu::Mutex     s_DefaultLogSinkLock;
63 static Kumu::ILogSink* s_DefaultLogSink = 0;
64 static Kumu::StdioLogSink s_StderrLogSink;
65
66 //
67 void
68 Kumu::SetDefaultLogSink(ILogSink* Sink)
69 {
70   AutoMutex L(s_DefaultLogSinkLock);
71   s_DefaultLogSink = Sink;
72 }
73
74 // Returns the internal default sink.
75 Kumu::ILogSink&
76 Kumu::DefaultLogSink()
77 {
78   AutoMutex L(s_DefaultLogSinkLock);
79
80   if ( s_DefaultLogSink == 0 )
81     s_DefaultLogSink = &s_StderrLogSink;
82
83   return *s_DefaultLogSink;
84 }
85
86
87 //------------------------------------------------------------------------------------------
88 //
89
90 void
91 Kumu::EntryListLogSink::WriteEntry(const LogEntry& Entry)
92 {
93   AutoMutex L(m_Lock);
94
95   if ( Entry.TestFilter(m_filter) )
96     m_Target.push_back(Entry);
97 }
98
99 //------------------------------------------------------------------------------------------
100 //
101
102 void
103 Kumu::StdioLogSink::WriteEntry(const LogEntry& Entry)
104 {
105   AutoMutex L(m_Lock);
106   std::string buf;
107
108   if ( Entry.TestFilter(m_filter) )
109     {
110       Entry.CreateStringWithOptions(buf, m_options);
111       fputs(buf.c_str(), m_stream);
112     }
113 }
114
115 //---------------------------------------------------------------------------------
116
117 #ifdef KM_WIN32
118 //
119 void
120 Kumu::WinDbgLogSink::WriteEntry(const LogEntry& Entry)
121 {
122   AutoMutex L(m_Lock);
123   std::string buf;
124
125   if ( Entry.TestFilter(m_filter) )
126     {
127       Entry.CreateStringWithOptions(buf, m_options);
128       ::OutputDebugString(buf.c_str());
129     }
130 }
131 #endif
132
133 //------------------------------------------------------------------------------------------
134 //
135
136 #ifndef KM_WIN32
137 //
138 void
139 Kumu::StreamLogSink::WriteEntry(const LogEntry& Entry)
140 {
141   AutoMutex L(m_Lock);
142   std::string buf;
143
144   if ( Entry.TestFilter(m_filter) )
145     {
146       Entry.CreateStringWithOptions(buf, m_options);
147       write(m_fd, buf.c_str(), buf.size());
148     }
149 }
150
151 // foolin with symbols
152 //------------------------------------------------------------------------------------------
153 #include <syslog.h>
154 int const SYSLOG_ALERT = LOG_ALERT;
155 int const SYSLOG_CRIT = LOG_CRIT;
156 int const SYSLOG_ERR = LOG_ERR;
157 int const SYSLOG_WARNING = LOG_WARNING;
158 int const SYSLOG_NOTICE = LOG_NOTICE;
159 int const SYSLOG_INFO = LOG_INFO;
160 int const SYSLOG_DEBUG = LOG_DEBUG;
161 #undef LOG_ALERT
162 #undef LOG_CRIT
163 #undef LOG_ERR
164 #undef LOG_WARNING
165 #undef LOG_NOTICE
166 #undef LOG_INFO
167 #undef LOG_DEBUG
168 //------------------------------------------------------------------------------------------
169
170 Kumu::SyslogLogSink::SyslogLogSink(const std::string& source_name, int facility)
171 {
172   if ( facility == 0 )
173     facility == LOG_DAEMON;
174
175   openlog(source_name.c_str(), LOG_CONS|LOG_NDELAY||LOG_PID, facility);
176 }
177
178 Kumu::SyslogLogSink::~SyslogLogSink()
179 {
180   closelog();
181 }
182
183 //
184 void
185 Kumu::SyslogLogSink::WriteEntry(const LogEntry& Entry)
186 {
187   int priority;
188
189   switch ( Entry.Type )
190     {
191     case Kumu::LOG_ALERT:   priority = SYSLOG_ALERT; break;
192     case Kumu::LOG_CRIT:    priority = SYSLOG_CRIT; break;
193     case Kumu::LOG_ERROR:   priority = SYSLOG_ERR; break;
194     case Kumu::LOG_WARN:    priority = SYSLOG_WARNING; break;
195     case Kumu::LOG_NOTICE:  priority = SYSLOG_NOTICE; break;
196     case Kumu::LOG_INFO:    priority = SYSLOG_INFO; break;
197     case Kumu::LOG_DEBUG:   priority = SYSLOG_DEBUG; break;
198     }
199
200   AutoMutex L(m_Lock);
201
202   if ( Entry.TestFilter(m_filter) )
203     {
204       syslog(priority, "%s", Entry.Msg.substr(0, Entry.Msg.size() - 1).c_str());
205     }
206 }
207
208 //
209 int
210 Kumu::SyslogNameToFacility(const std::string& facility_name)
211 {
212   if ( facility_name == "LOG_DAEMON" ) return LOG_DAEMON;
213   if ( facility_name == "LOG_LOCAL0" ) return LOG_LOCAL0;
214   if ( facility_name == "LOG_LOCAL1" ) return LOG_LOCAL1;
215   if ( facility_name == "LOG_LOCAL2" ) return LOG_LOCAL2;
216   if ( facility_name == "LOG_LOCAL3" ) return LOG_LOCAL3;
217   if ( facility_name == "LOG_LOCAL4" ) return LOG_LOCAL4;
218   if ( facility_name == "LOG_LOCAL5" ) return LOG_LOCAL5;
219   if ( facility_name == "LOG_LOCAL6" ) return LOG_LOCAL6;
220   if ( facility_name == "LOG_LOCAL7" ) return LOG_LOCAL7;
221
222   DefaultLogSink().Error("Unsupported facility name: %s, using default value LOG_DAEMON\n", facility_name.c_str());
223   return LOG_DAEMON;
224 }
225
226 #endif
227
228 //------------------------------------------------------------------------------------------
229
230 //
231 std::basic_ostream<char, std::char_traits<char> >&
232 Kumu::operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry)
233 {
234   std::basic_ostringstream<char, std::char_traits<char> > s;
235   s.copyfmt(strm);
236   s.width(0);
237   std::string buf;
238
239   s << Entry.CreateStringWithOptions(buf, LOG_OPTION_ALL);
240
241   strm << s.str();
242   return strm;
243 }
244
245 //------------------------------------------------------------------------------------------
246
247
248 //
249 bool
250 Kumu::LogEntry::TestFilter(i32_t filter) const
251 {
252   switch ( Type )
253     {
254     case LOG_CRIT:
255       if ( (filter & LOG_ALLOW_CRIT) == 0 )
256         return false;
257       break;
258
259     case LOG_ALERT:
260       if ( (filter & LOG_ALLOW_ALERT) == 0 )
261         return false;
262       break;
263
264     case LOG_NOTICE:
265       if ( (filter & LOG_ALLOW_NOTICE) == 0 )
266         return false;
267       break;
268
269     case LOG_ERROR:
270       if ( (filter & LOG_ALLOW_ERROR) == 0 )
271         return false;
272       break;
273
274     case LOG_WARN:
275       if ( (filter & LOG_ALLOW_WARN) == 0 )
276         return false;
277       break;
278
279     case LOG_INFO:
280       if ( (filter & LOG_ALLOW_INFO) == 0 )
281         return false;
282       break;
283
284     case LOG_DEBUG:
285       if ( (filter & LOG_ALLOW_DEBUG) == 0 )
286         return false;
287       break;
288
289     }
290
291  return true;
292 }
293
294 //
295 std::string&
296 Kumu::LogEntry::CreateStringWithOptions(std::string& out_buf, i32_t opt) const
297 {
298   out_buf.erase();
299
300   if ( opt != 0 )
301     {
302       char buf[64];
303
304       if ( (opt & LOG_OPTION_TIMESTAMP) != 0 )
305         {
306           Timestamp Now;
307           out_buf += Now.EncodeString(buf, 64);
308         }
309
310       if ( (opt & LOG_OPTION_PID) != 0 )
311         {
312           if ( ! out_buf.empty() )  out_buf += " ";
313           snprintf(buf, 64, "%d", PID);
314           out_buf += buf;
315         }
316
317       if ( (opt & LOG_OPTION_TYPE) != 0 )
318         {
319           if ( ! out_buf.empty() )  out_buf += " ";
320           
321           switch ( Type )
322             {
323             case LOG_CRIT:   out_buf += "CRT";      break;
324             case LOG_ALERT:  out_buf += "ALR";      break;
325             case LOG_NOTICE: out_buf += "NTC";      break;
326             case LOG_ERROR:  out_buf += "ERR";      break;
327             case LOG_WARN:   out_buf += "WRN";      break;
328             case LOG_INFO:   out_buf += "INF";      break;
329             case LOG_DEBUG:  out_buf += "DBG";      break;
330             default:         out_buf += "DFL";      break;
331             }
332         }
333
334       out_buf.insert(0, "[");
335       out_buf += "]: ";
336     }
337
338   out_buf += Msg;
339   return out_buf;
340 }
341
342
343 //
344 ui32_t
345 Kumu::LogEntry::ArchiveLength() const
346 {
347   return sizeof(ui32_t)
348     + EventTime.ArchiveLength()
349     + sizeof(ui32_t)
350     + sizeof(ui32_t) + Msg.size();
351 }
352
353 //
354 bool
355 Kumu::LogEntry::Archive(Kumu::MemIOWriter* Writer) const
356 {
357   if ( ! Writer->WriteUi32BE(PID) ) return false;
358   if ( ! EventTime.Archive(Writer) ) return false;
359   if ( ! Writer->WriteUi32BE(Type) ) return false;
360   if ( ! ArchiveString(*Writer, Msg) ) return false;
361   return true;
362 }
363
364 //
365 bool
366 Kumu::LogEntry::Unarchive(Kumu::MemIOReader* Reader)
367 {
368   if ( ! Reader->ReadUi32BE(&PID) ) return false;
369   if ( ! EventTime.Unarchive(Reader) ) return false;
370   if ( ! Reader->ReadUi32BE((ui32_t*)&Type) ) return false;
371   if ( ! UnarchiveString(*Reader, Msg) ) return false;
372   return true;
373 }
374
375 //
376 // end
377 //