The following changes have been checked into napali:
[asdcplib.git] / src / KM_log.cpp
1 /*
2 Copyright (c) 2004-2008, 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 #endif
151
152 //------------------------------------------------------------------------------------------
153
154 //
155 std::basic_ostream<char, std::char_traits<char> >&
156 Kumu::operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry)
157 {
158   std::basic_ostringstream<char, std::char_traits<char> > s;
159   s.copyfmt(strm);
160   s.width(0);
161   std::string buf;
162
163   s << Entry.CreateStringWithOptions(buf, LOG_OPTION_ALL);
164
165   strm << s.str();
166   return strm;
167 }
168
169 //------------------------------------------------------------------------------------------
170
171
172 //
173 bool
174 Kumu::LogEntry::TestFilter(i32_t filter) const
175 {
176   switch ( Type )
177     {
178     case LOG_CRIT:
179       if ( (filter & LOG_ALLOW_CRIT) == 0 )
180         return false;
181       break;
182
183     case LOG_ALERT:
184       if ( (filter & LOG_ALLOW_ALERT) == 0 )
185         return false;
186       break;
187
188     case LOG_NOTICE:
189       if ( (filter & LOG_ALLOW_NOTICE) == 0 )
190         return false;
191       break;
192
193     case LOG_ERROR:
194       if ( (filter & LOG_ALLOW_ERROR) == 0 )
195         return false;
196       break;
197
198     case LOG_WARN:
199       if ( (filter & LOG_ALLOW_WARN) == 0 )
200         return false;
201       break;
202
203     case LOG_INFO:
204       if ( (filter & LOG_ALLOW_INFO) == 0 )
205         return false;
206       break;
207
208     case LOG_DEBUG:
209       if ( (filter & LOG_ALLOW_DEBUG) == 0 )
210         return false;
211       break;
212
213     }
214
215  return true;
216 }
217
218 //
219 std::string&
220 Kumu::LogEntry::CreateStringWithOptions(std::string& out_buf, i32_t opt) const
221 {
222   out_buf.erase();
223
224   if ( opt != 0 )
225     {
226       char buf[64];
227
228       if ( (opt & LOG_OPTION_TIMESTAMP) != 0 )
229         {
230           Timestamp Now;
231           out_buf += Now.EncodeString(buf, 64);
232         }
233
234       if ( (opt & LOG_OPTION_PID) != 0 )
235         {
236           if ( ! out_buf.empty() )  out_buf += " ";
237           snprintf(buf, 64, "%d", PID);
238           out_buf += buf;
239         }
240
241       if ( (opt & LOG_OPTION_TYPE) != 0 )
242         {
243           if ( ! out_buf.empty() )  out_buf += " ";
244           
245           switch ( Type )
246             {
247             case LOG_CRIT:   out_buf += "CRT";      break;
248             case LOG_ALERT:  out_buf += "ALR";      break;
249             case LOG_NOTICE: out_buf += "NTC";      break;
250             case LOG_ERROR:  out_buf += "ERR";      break;
251             case LOG_WARN:   out_buf += "WRN";      break;
252             case LOG_INFO:   out_buf += "INF";      break;
253             case LOG_DEBUG:  out_buf += "DBG";      break;
254             default:         out_buf += "DFL";      break;
255             }
256         }
257
258       out_buf.insert(0, "[");
259       out_buf += "]: ";
260     }
261
262   out_buf += Msg;
263   return out_buf;
264 }
265
266
267 //
268 ui32_t
269 Kumu::LogEntry::ArchiveLength() const
270 {
271   return sizeof(ui32_t)
272     + EventTime.ArchiveLength()
273     + sizeof(ui32_t)
274     + sizeof(ui32_t) + Msg.size();
275 }
276
277 //
278 bool
279 Kumu::LogEntry::Archive(Kumu::MemIOWriter* Writer) const
280 {
281   if ( ! Writer->WriteUi32BE(PID) ) return false;
282   if ( ! EventTime.Archive(Writer) ) return false;
283   if ( ! Writer->WriteUi32BE(Type) ) return false;
284   if ( ! ArchiveString(*Writer, Msg) ) return false;
285   return true;
286 }
287
288 //
289 bool
290 Kumu::LogEntry::Unarchive(Kumu::MemIOReader* Reader)
291 {
292   if ( ! Reader->ReadUi32BE(&PID) ) return false;
293   if ( ! EventTime.Unarchive(Reader) ) return false;
294   if ( ! Reader->ReadUi32BE((ui32_t*)&Type) ) return false;
295   if ( ! UnarchiveString(*Reader, Msg) ) return false;
296   return true;
297 }
298
299 //
300 // end
301 //