blob: fb6bbab80a79818bb68fdb48d040379be37b3877 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/thread.h>
42#include <cc++/slog.h>
43#ifdef __BORLANDC__
44#include <stdio.h>
45#include <stdarg.h>
46#else
47#include <cstdio>
48#include <cstdarg>
49#endif
50#include "../src/private.h"
51
52#ifdef HAVE_SYSLOG_H
53#include <syslog.h>
54#endif
55
56using std::streambuf;
57using std::ofstream;
58using std::ostream;
59using std::clog;
60using std::endl;
61using std::ios;
62
63#ifdef CCXX_NAMESPACES
64namespace ost {
65#endif
66
67Slog slog;
68
69Slog::Slog(void) :
70streambuf()
71#ifdef HAVE_OLD_IOSTREAM
72,ostream()
73#else
74,ostream((streambuf *)this)
75#endif
76{
77#ifdef HAVE_OLD_IOSTREAM
78 init((streambuf *)this);
79#endif
80 _enable = true;
81 _level = levelDebug;
82 _clogEnable = true;
83#ifndef HAVE_SYSLOG_H
84 syslog = NULL;
85#endif
86}
87
88Slog::~Slog(void)
89{
90#ifdef HAVE_SYSLOG_H
91 closelog();
92#else
93 if(syslog)
94 fclose(syslog);
95#endif
96}
97
98ThreadImpl *Slog::getPriv(void)
99{
100 Thread *thread = Thread::get();
101
102 if(!thread)
103 return NULL;
104
105 return thread->priv;
106}
107
108void Slog::close(void)
109{
110#ifdef HAVE_SYSLOG_H
111 closelog();
112#else
113 lock.enterMutex();
114 if(syslog)
115 fclose(syslog);
116 syslog = NULL;
117 lock.leaveMutex();
118#endif
119}
120
121void Slog::open(const char *ident, Class grp)
122{
123 const char *cp;
124
125#ifdef HAVE_SYSLOG_H
126 cp = strrchr(ident, '/');
127 if(cp)
128 ident = ++cp;
129
130 int fac;
131
132 switch(grp) {
133 case classUser:
134 fac = LOG_USER;
135 break;
136
137 case classDaemon:
138 fac = LOG_DAEMON;
139 break;
140
141 case classAudit:
142#ifdef LOG_AUTHPRIV
143 fac = LOG_AUTHPRIV;
144 break;
145#endif
146 case classSecurity:
147 fac = LOG_AUTH;
148 break;
149
150 case classLocal0:
151 fac = LOG_LOCAL0;
152 break;
153
154 case classLocal1:
155 fac = LOG_LOCAL1;
156 break;
157
158 case classLocal2:
159 fac = LOG_LOCAL2;
160 break;
161
162 case classLocal3:
163 fac = LOG_LOCAL3;
164 break;
165
166 case classLocal4:
167 fac = LOG_LOCAL4;
168 break;
169
170 case classLocal5:
171 fac = LOG_LOCAL5;
172 break;
173
174 case classLocal6:
175 fac = LOG_LOCAL6;
176 break;
177
178 case classLocal7:
179 fac = LOG_LOCAL7;
180 break;
181
182 default:
183 fac = LOG_USER;
184 break;
185 }
186 openlog(ident, 0, fac);
187#else
188 char *buf;
189
190 lock.enterMutex();
191 if(syslog)
192 fclose(syslog);
193 buf = new char[strlen(ident) + 1];
194 strcpy(buf, ident);
195 cp = (const char *)buf;
196 buf = strrchr(buf, '.');
197 if(buf) {
198 if(!stricmp(buf, ".exe"))
199 strcpy(buf, ".log");
200 }
201 syslog = fopen(cp, "a");
202 delete[] (char *)cp;
203 lock.leaveMutex();
204#endif
205}
206
207#ifdef HAVE_SNPRINTF
208
209void Slog::error(const char *format, ...)
210{
211 ThreadImpl *thread = getPriv();
212 va_list args;
213 va_start(args, format);
214 overflow(EOF);
215
216 if(!thread)
217 return;
218
219 error();
220
221 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
222 thread->_msgpos = strlen(thread->_msgbuf);
223 overflow(EOF);
224 va_end(args);
225}
226
227void Slog::warn(const char *format, ...)
228{
229 ThreadImpl *thread = getPriv();
230 va_list args;
231
232 if(!thread)
233 return;
234
235 va_start(args, format);
236 overflow(EOF);
237 warn();
238 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
239 thread->_msgpos = strlen(thread->_msgbuf);
240 overflow(EOF);
241 va_end(args);
242}
243
244void Slog::debug(const char *format, ...)
245{
246 ThreadImpl *thread = getPriv();
247 va_list args;
248
249 if(!thread)
250 return;
251
252 va_start(args, format);
253 overflow(EOF);
254 debug();
255 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
256 thread->_msgpos = strlen(thread->_msgbuf);
257 overflow(EOF);
258 va_end(args);
259}
260
261void Slog::emerg(const char *format, ...)
262{
263 ThreadImpl *thread = getPriv();
264 va_list args;
265
266 if(!thread)
267 return;
268
269 va_start(args, format);
270 overflow(EOF);
271 emerg();
272 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
273 thread->_msgpos = strlen(thread->_msgbuf);
274 overflow(EOF);
275 va_end(args);
276}
277
278void Slog::alert(const char *format, ...)
279{
280 ThreadImpl *thread = getPriv();
281 va_list args;
282
283 if(!thread)
284 return;
285
286 va_start(args, format);
287 overflow(EOF);
288 alert();
289 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
290 thread->_msgpos = strlen(thread->_msgbuf);
291 overflow(EOF);
292 va_end(args);
293}
294
295void Slog::critical(const char *format, ...)
296{
297 ThreadImpl *thread = getPriv();
298 va_list args;
299
300 if(!thread)
301 return;
302
303 va_start(args, format);
304 overflow(EOF);
305 critical();
306 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
307 thread->_msgpos = strlen(thread->_msgbuf);
308 overflow(EOF);
309 va_end(args);
310}
311
312void Slog::notice(const char *format, ...)
313{
314 ThreadImpl *thread = getPriv();
315 va_list args;
316
317 if(!thread)
318 return;
319
320 va_start(args, format);
321 overflow(EOF);
322 notice();
323 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
324 thread->_msgpos = strlen(thread->_msgbuf);
325 overflow(EOF);
326 va_end(args);
327}
328
329void Slog::info(const char *format, ...)
330{
331 ThreadImpl *thread = getPriv();
332 va_list args;
333
334 if(!thread)
335 return;
336
337 va_start(args, format);
338 overflow(EOF);
339 info();
340 vsnprintf(thread->_msgbuf, sizeof(thread->_msgbuf), format, args);
341 thread->_msgpos = strlen(thread->_msgbuf);
342 overflow(EOF);
343 va_end(args);
344 }
345#endif
346
347int Slog::overflow(int c)
348{
349 ThreadImpl *thread = getPriv();
350 if(!thread)
351 return c;
352
353 if(c == '\n' || !c || c == EOF) {
354 if(!thread->_msgpos)
355 return c;
356
357 thread->_msgbuf[thread->_msgpos] = 0;
358 if (_enable)
359#ifdef HAVE_SYSLOG_H
360 syslog(priority, "%s", thread->_msgbuf);
361#else
362 {
363 time_t now;
364 struct tm *dt;
365 time(&now);
366 dt = localtime(&now);
367 char buf[256];
368 const char *p = "unknown";
369 switch(priority) {
370 case levelEmergency:
371 p = "emerg";
372 break;
373 case levelInfo:
374 p = "info";
375 break;
376 case levelError:
377 p = "error";
378 break;
379 case levelAlert:
380 p = "alert";
381 break;
382 case levelDebug:
383 p = "debug";
384 break;
385 case levelNotice:
386 p = "notice";
387 break;
388 case levelWarning:
389 p = "warn";
390 break;
391 case levelCritical:
392 p = "crit";
393 break;
394 }
395
396 lock.enterMutex();
397 snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d [%s] %s\n",
398 dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
399 dt->tm_hour, dt->tm_min, dt->tm_sec,
400 p, thread->_msgbuf);
401 if(syslog)
402 fputs(buf, syslog);
403// syslog << "[" << priority << "] " << thread->_msgbuf << endl;
404 lock.leaveMutex();
405 }
406#endif
407 thread->_msgpos = 0;
408
409 if ( _enable && _clogEnable
410#ifndef WIN32
411 && (getppid() > 1)
412#endif
413 )
414 clog << thread->_msgbuf << endl;
415 _enable = true;
416 return c;
417 }
418
419 if (thread->_msgpos < (int)(sizeof(thread->_msgbuf) - 1))
420 thread->_msgbuf[thread->_msgpos++] = c;
421
422 return c;
423}
424
425Slog &Slog::operator()(const char *ident, Class grp, Level lev)
426{
427 ThreadImpl *thread = getPriv();
428
429 if(!thread)
430 return *this;
431
432 thread->_msgpos = 0;
433 _enable = true;
434 open(ident, grp);
435 return this->operator()(lev, grp);
436}
437
438Slog &Slog::operator()(Level lev, Class grp)
439{
440 ThreadImpl *thread = getPriv();
441
442 if(!thread)
443 return *this;
444
445 thread->_msgpos = 0;
446 if(_level >= lev)
447 _enable = true;
448 else
449 _enable = false;
450
451#ifdef HAVE_SYSLOG_H
452 switch(lev) {
453 case levelEmergency:
454 priority = LOG_EMERG;
455 break;
456 case levelAlert:
457 priority = LOG_ALERT;
458 break;
459 case levelCritical:
460 priority = LOG_CRIT;
461 break;
462 case levelError:
463 priority = LOG_ERR;
464 break;
465 case levelWarning:
466 priority = LOG_WARNING;
467 break;
468 case levelNotice:
469 priority = LOG_NOTICE;
470 break;
471 case levelInfo:
472 priority = LOG_INFO;
473 break;
474 case levelDebug:
475 priority = LOG_DEBUG;
476 break;
477 }
478 switch(grp) {
479 case classAudit:
480#ifdef LOG_AUTHPRIV
481 priority |= LOG_AUTHPRIV;
482 break;
483#endif
484 case classSecurity:
485 priority |= LOG_AUTH;
486 break;
487 case classUser:
488 priority |= LOG_USER;
489 break;
490 case classDaemon:
491 priority |= LOG_DAEMON;
492 break;
493 case classDefault:
494 priority |= LOG_USER;
495 break;
496 case classLocal0:
497 priority |= LOG_LOCAL0;
498 break;
499 case classLocal1:
500 priority |= LOG_LOCAL1;
501 break;
502 case classLocal2:
503 priority |= LOG_LOCAL2;
504 break;
505 case classLocal3:
506 priority |= LOG_LOCAL3;
507 break;
508 case classLocal4:
509 priority |= LOG_LOCAL4;
510 break;
511 case classLocal5:
512 priority |= LOG_LOCAL5;
513 break;
514 case classLocal6:
515 priority |= LOG_LOCAL6;
516 break;
517 case classLocal7:
518 priority |= LOG_LOCAL7;
519 break;
520 }
521#else
522 priority = lev;
523#endif
524 return *this;
525}
526
527Slog &Slog::operator()(void)
528{
529 return *this;
530}
531
532#ifdef CCXX_NAMESPACES
533}
534#endif
535
536/** EMACS **
537 * Local variables:
538 * mode: c++
539 * c-basic-offset: 6
540 * End:
541 */