23f17d8008a380594b1aff54f9f90022b65fd36d
[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& e)
186 {
187   int priority;
188
189   switch ( e.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   syslog(priority, "%s", e.Msg.substr(0, e.Msg.size() - 1).c_str());
201 }
202
203 //
204 int
205 Kumu::SyslogNameToFacility(const std::string& facility_name)
206 {
207   if ( facility_name == "LOG_DAEMON" ) return LOG_DAEMON;
208   if ( facility_name == "LOG_LOCAL0" ) return LOG_LOCAL0;
209   if ( facility_name == "LOG_LOCAL1" ) return LOG_LOCAL1;
210   if ( facility_name == "LOG_LOCAL2" ) return LOG_LOCAL2;
211   if ( facility_name == "LOG_LOCAL3" ) return LOG_LOCAL3;
212   if ( facility_name == "LOG_LOCAL4" ) return LOG_LOCAL4;
213   if ( facility_name == "LOG_LOCAL5" ) return LOG_LOCAL5;
214   if ( facility_name == "LOG_LOCAL6" ) return LOG_LOCAL6;
215   if ( facility_name == "LOG_LOCAL7" ) return LOG_LOCAL7;
216
217   DefaultLogSink().Error("Unsupported facility name: %s, using default value LOG_DAEMON\n", facility_name.c_str());
218   return LOG_DAEMON;
219 }
220
221 #endif
222
223 //------------------------------------------------------------------------------------------
224
225 //
226 std::basic_ostream<char, std::char_traits<char> >&
227 Kumu::operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry)
228 {
229   std::basic_ostringstream<char, std::char_traits<char> > s;
230   s.copyfmt(strm);
231   s.width(0);
232   std::string buf;
233
234   s << Entry.CreateStringWithOptions(buf, LOG_OPTION_ALL);
235
236   strm << s.str();
237   return strm;
238 }
239
240 //------------------------------------------------------------------------------------------
241
242
243 //
244 bool
245 Kumu::LogEntry::TestFilter(i32_t filter) const
246 {
247   switch ( Type )
248     {
249     case LOG_CRIT:
250       if ( (filter & LOG_ALLOW_CRIT) == 0 )
251         return false;
252       break;
253
254     case LOG_ALERT:
255       if ( (filter & LOG_ALLOW_ALERT) == 0 )
256         return false;
257       break;
258
259     case LOG_NOTICE:
260       if ( (filter & LOG_ALLOW_NOTICE) == 0 )
261         return false;
262       break;
263
264     case LOG_ERROR:
265       if ( (filter & LOG_ALLOW_ERROR) == 0 )
266         return false;
267       break;
268
269     case LOG_WARN:
270       if ( (filter & LOG_ALLOW_WARN) == 0 )
271         return false;
272       break;
273
274     case LOG_INFO:
275       if ( (filter & LOG_ALLOW_INFO) == 0 )
276         return false;
277       break;
278
279     case LOG_DEBUG:
280       if ( (filter & LOG_ALLOW_DEBUG) == 0 )
281         return false;
282       break;
283
284     }
285
286  return true;
287 }
288
289 //
290 std::string&
291 Kumu::LogEntry::CreateStringWithOptions(std::string& out_buf, i32_t opt) const
292 {
293   out_buf.erase();
294
295   if ( opt != 0 )
296     {
297       char buf[64];
298
299       if ( (opt & LOG_OPTION_TIMESTAMP) != 0 )
300         {
301           Timestamp Now;
302           out_buf += Now.EncodeString(buf, 64);
303         }
304
305       if ( (opt & LOG_OPTION_PID) != 0 )
306         {
307           if ( ! out_buf.empty() )  out_buf += " ";
308           snprintf(buf, 64, "%d", PID);
309           out_buf += buf;
310         }
311
312       if ( (opt & LOG_OPTION_TYPE) != 0 )
313         {
314           if ( ! out_buf.empty() )  out_buf += " ";
315           
316           switch ( Type )
317             {
318             case LOG_CRIT:   out_buf += "CRT";      break;
319             case LOG_ALERT:  out_buf += "ALR";      break;
320             case LOG_NOTICE: out_buf += "NTC";      break;
321             case LOG_ERROR:  out_buf += "ERR";      break;
322             case LOG_WARN:   out_buf += "WRN";      break;
323             case LOG_INFO:   out_buf += "INF";      break;
324             case LOG_DEBUG:  out_buf += "DBG";      break;
325             default:         out_buf += "DFL";      break;
326             }
327         }
328
329       out_buf.insert(0, "[");
330       out_buf += "]: ";
331     }
332
333   out_buf += Msg;
334   return out_buf;
335 }
336
337
338 //
339 ui32_t
340 Kumu::LogEntry::ArchiveLength() const
341 {
342   return sizeof(ui32_t)
343     + EventTime.ArchiveLength()
344     + sizeof(ui32_t)
345     + sizeof(ui32_t) + Msg.size();
346 }
347
348 //
349 bool
350 Kumu::LogEntry::Archive(Kumu::MemIOWriter* Writer) const
351 {
352   if ( ! Writer->WriteUi32BE(PID) ) return false;
353   if ( ! EventTime.Archive(Writer) ) return false;
354   if ( ! Writer->WriteUi32BE(Type) ) return false;
355   if ( ! ArchiveString(*Writer, Msg) ) return false;
356   return true;
357 }
358
359 //
360 bool
361 Kumu::LogEntry::Unarchive(Kumu::MemIOReader* Reader)
362 {
363   if ( ! Reader->ReadUi32BE(&PID) ) return false;
364   if ( ! EventTime.Unarchive(Reader) ) return false;
365   if ( ! Reader->ReadUi32BE((ui32_t*)&Type) ) return false;
366   if ( ! UnarchiveString(*Reader, Msg) ) return false;
367   return true;
368 }
369
370 //
371 // end
372 //