blob: b5c02b03a290fddf9c33f753bbb67cd4dd505e54 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 2005-2009 Angelo Naselli, Penta Engineering s.r.l.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License for more details.
11//
12// You should have received a copy of the GNU General Public License
13// along with this program; if not, write to the Free Software
14// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15//
16// As a special exception, you may use this file as part of a free software
17// library without restriction. Specifically, if other files instantiate
18// templates or use macros or inline functions from this file, or you compile
19// this file and link it with other files to produce an executable, this
20// file does not by itself cause the resulting executable to be covered by
21// the GNU General Public License. This exception does not however
22// invalidate any other reasons why the executable file might be covered by
23// the GNU General Public License.
24//
25// This exception applies only to the code released under the name GNU
26// Common C++. If you copy code from other releases into a copy of GNU
27// Common C++, as the General Public License permits, the exception does
28// not apply to the code that you add in this way. To avoid misleading
29// anyone as to the status of such modified files, you must delete
30// this exception notice from them.
31//
32// If you write modifications of your own for GNU Common C++, it is your choice
33// whether to permit this exception to apply to your modifications.
34// If you do not wish that, delete this exception notice.
35//
36
37#include <cc++/config.h>
38#include <cc++/thread.h>
39#include <cc++/slog.h>
40#include <cc++/buffer.h>
41#include <string>
42#include <iomanip>
43#include <iostream>
44#include <cstdio>
45#include <cstdlib>
46#include <stdarg.h>
47#include <errno.h>
48
49// TODO sc: test if has to move up now that it is into commoncpp
50// NOTE: the order of inclusion is important do not move following include line
51// redefinition of __EXPORT needed if we're compiling our dll
52#include <cc++/export.h>
53// local includes
54#include <cc++/applog.h>
55
56#ifdef CCXX_NAMESPACES
57using namespace std;
58namespace ost
59{
60#endif
61
62
63class logStruct
64{
65 public:
66 string _ident;
67 int _priority;
68 Slog::Level _level;
69 bool _enable;
70 bool _clogEnable;
71 bool _slogEnable;
72 size_t _msgpos;
73
74 enum logEnum
75 {
76 BUFF_SIZE = 512,
77 LAST_CHAR = BUFF_SIZE - 1
78 };
79 char _msgbuf[BUFF_SIZE];
80
81 logStruct() : _ident("") , _priority(Slog::levelDebug),
82 _level(Slog::levelDebug), _enable(false),
83 _clogEnable(false), _slogEnable(false), _msgpos(0)
84 {
85 memset(_msgbuf, 0, BUFF_SIZE);
86 };
87
88 ~logStruct() {};
89};
90
91struct levelNamePair
92{
93 const char *name;
94 Slog::Level level;
95};
96
97#ifdef WIN32
98template class std::map<string, Slog::Level >;
99#endif
100
101class LevelName : public map<string, Slog::Level>
102{
103 public:
104
105 LevelName(const levelNamePair initval[], int num)
106 {
107 for (int i = 0; i < num; i++)
108 insert(make_pair(initval[i].name, initval[i].level));
109 };
110};
111
112class logger : public ost::ThreadQueue
113{
114 private:
115 string _nomeFile;
116 std::fstream _logfs;
117 bool _usePipe;
118
119 protected:
120 // to dequeue log messages and write them to file if not log_directly
121 virtual void runQueue(void *data);
122 virtual void startQueue(void);
123 virtual void stopQueue(void);
124 virtual void onTimer(void);
125 virtual void final(void);
126
127 public:
128 logger(const char* logFileName = NULL, bool usePipe = false);
129 virtual ~logger();
130
131 // To change log file name
132 void logFileName(const char* FileName, bool usePipe = false);
133
134};
135
136
137// mapping thread ID <-> logStruct (buffer)
138typedef map <cctid_t, logStruct> LogPrivateData;
139// map ident <-> levels
140typedef map <string, Slog::Level> IdentLevel;
141
142
143class AppLogPrivate
144{
145 public:
146 // subscription and unsubsciption must be protected as well
147 ost::Mutex _subMutex;
148 // mapping thread ID <-> logStruct (buffer)
149 LogPrivateData _logs;
150 // map ident <-> levels
151 IdentLevel _identLevel;
152 // log directly into file
153 bool _logDirectly;
154 bool _logPipe;
155 // log spooler
156 logger *_pLogger;
157
158 string _nomeFile;
159 Mutex _lock;
160 std::fstream _logfs;
161
162 static const levelNamePair _values[];
163 static LevelName _assoc;
164
165 AppLogPrivate() : _pLogger(NULL) {}
166
167 ~AppLogPrivate()
168 {
169 if (_pLogger)
170 delete _pLogger;
171 }
172};
173
174
175
176const levelNamePair AppLogPrivate::_values[] =
177{
178 { "emerg", Slog::levelEmergency },
179 { "alert", Slog::levelAlert },
180 { "critical", Slog::levelCritical },
181 { "error", Slog::levelError },
182 { "warn", Slog::levelWarning },
183 { "notice", Slog::levelNotice },
184 { "info", Slog::levelInfo },
185 { "debug", Slog::levelDebug }
186};
187
188AppLog alog;
189
190LevelName AppLogPrivate::_assoc(_values, sizeof AppLogPrivate::_values / sizeof *AppLogPrivate::_values);
191map<string, Slog::Level> *AppLog::assoc = &AppLogPrivate::_assoc;
192
193HEXdump::HEXdump(const unsigned char *buffer, int len, int max_len) : _str()
194{
195 std::stringstream sstr;
196
197
198 if (buffer == NULL || len <= 0)
199 return ;
200
201 long buf_len = (max_len > 0 && len > max_len) ? max_len : len;
202 long int addr = 0;
203 int cnt2 = 0;
204 int n;
205 int i;
206
207 sstr.str("");
208 // get exception from ifstream failures
209 sstr.exceptions(ifstream::failbit | ifstream::badbit);
210 try
211 {
212 sstr << std::endl;
213 sstr << "dump " << len << " byte." << std::endl;
214
215 for (n = 0; n < buf_len; n++)
216 {
217 if (cnt2 == 0)
218 {
219 // Print address.
220 sstr << std::setw(7) << std::setfill('0') << int (addr) << " - ";
221 addr = addr + 16;
222 }
223 cnt2 = (cnt2 + 1) % 18;
224 if (cnt2 <= 16)
225 {
226 // print hex value
227 sstr << std::hex << std::setw(2) << std::setfill('0') << int (buffer[n]) << " ";
228 }
229 else
230 {
231 sstr << " ";
232 sstr << std::setfill(' ');
233 for (i = n - cnt2 + 1; i < n; i++)
234 {
235 // print ascii value
236 if (buffer[i] < 32 || 126 < buffer[i])
237 {
238 sstr << '.';
239 }
240 else
241 {
242 sstr << buffer[i];
243 }
244 }
245 sstr << std::endl;
246 sstr << std::dec;
247 cnt2 = 0;
248 n--;
249 }
250 }
251
252 sstr << std::setfill(' ');
253
254 for (i = cnt2 + 1; i <= 16 ; i++)
255 {
256 sstr << std::setw(2) << "--" << " ";
257 }
258 sstr << " ";
259
260 for (i = n - cnt2; cnt2 <= 16 && i < n; i++)
261 {
262 if (buffer[i] < 32 || 126 < buffer[i])
263 {
264 sstr << '.';
265 }
266 else
267 {
268 sstr << buffer[i];
269 }
270 }
271 sstr << std::dec;
272 if (max_len > 0 && len > max_len)
273 sstr << std::endl << "dump troncato a " << max_len << " byte." << std::endl;
274 }
275 catch (...)
276 {
277 sstr.str("HEXdump failed!");
278 }
279
280 _str = sstr.str();
281}
282
283// class logger
284logger::logger(const char* logFileName, bool usePipe) : ThreadQueue(NULL, 0, 0), _usePipe(usePipe)
285{
286 _nomeFile = "";
287
288 if (logFileName)
289 _nomeFile = logFileName;
290 if (!_nomeFile.empty())
291 {
292 if (!_usePipe)
293 {
294 _logfs.open(_nomeFile.c_str(), std::ofstream::out | std::ofstream::app | std::ofstream::ate);
295 }
296#ifndef WIN32
297 else
298 {
299 // create pipe
300 int err = mkfifo(_nomeFile.c_str(), S_IREAD | S_IWRITE);
301 if (err == 0 || errno == EEXIST)
302 {
303 // and open it
304 _logfs.open(_nomeFile.c_str(), std::fstream::in | std::fstream::out);
305 }
306 else
307 THROW(AppLogException("Can't create pipe"));
308 }
309#endif
310 if (_logfs.fail())
311 THROW(AppLogException("Can't open log file name"));
312 }
313}
314
315logger::~logger()
316{
317 Semaphore::post();
318 Thread::terminate();
319
320 _logfs.flush();
321 _logfs.close();
322}
323
324// New log file name
325void logger::logFileName(const char* FileName, bool usePipe)
326{
327 if (!FileName)
328 return;
329
330 _usePipe = usePipe;
331 _nomeFile = FileName;
332 if (_logfs.is_open())
333 _logfs.close();
334
335 if (!_nomeFile.empty())
336 {
337 if (!_usePipe)
338 {
339 _logfs.open(_nomeFile.c_str(), std::ofstream::out | std::ofstream::app | std::ofstream::ate);
340 }
341#ifndef WIN32
342 else
343 {
344 // create pipe
345 int err = mkfifo(_nomeFile.c_str(), S_IREAD | S_IWRITE);
346 if (err == 0 || errno == EEXIST)
347 {
348 // and open it
349 _logfs.open(_nomeFile.c_str(), std::fstream::in | std::fstream::out);
350 }
351 else
352 THROW(AppLogException("Can't create pipe"));
353 }
354#endif
355 if (_logfs.fail())
356 THROW(AppLogException("Can't open log file name"));
357 }
358
359}
360
361// writes into filename enqueued messages
362void logger::runQueue(void * data)
363{
364 char *str = (char *) data;
365
366 if (_logfs.is_open())
367 {
368 Thread::setCancel(cancelDisabled);
369 _logfs << str;
370 _logfs.flush();
371 Thread::setCancel(cancelImmediate);
372 }
373}
374
375void logger::startQueue()
376{
377 testCancel();
378}
379
380void logger::stopQueue()
381{
382 testCancel();
383}
384
385void logger::onTimer()
386{
387}
388
389void logger::final()
390{
391 if (started)
392 {
393 data_t *pFirst = first;
394 while (pFirst)
395 {
396 runQueue(pFirst->data);
397 pFirst = pFirst->next;
398 }
399 }
400}
401
402#ifndef WIN32
403AppLog::AppLog(const char* logFileName, bool logDirectly, bool usePipe) :
404 streambuf(), ostream((streambuf*) this)
405#else
406AppLog::AppLog(const char* logFileName, bool logDirectly) :
407 streambuf(), ostream((streambuf*) this)
408#endif
409{
410 d= NULL; // pedantic fussy about initing members before base classes...
411 d = new AppLogPrivate();
412 if (!d)
413 THROW(AppLogException("Memory allocation problem"));
414
415 d->_nomeFile = "";
416 d->_logDirectly = logDirectly;
417#ifndef WIN32
418 d->_logPipe = usePipe;
419#else
420 d->_logPipe = false;
421#endif
422 // level string to level value
423 // assoc["emerg"] = levelEmergency;
424 // assoc["alert"] = levelAlert;
425 // assoc["critical"] = levelCritical;
426 // assoc["error"] = levelError;
427 // assoc["warn"] = levelWarning;
428 // assoc["notice"] = levelNotice;
429 // assoc["info"] = levelInfo;
430 // assoc["debug"] = levelDebug;
431
432 if (logFileName)
433 d->_nomeFile = logFileName;
434
435 if (!d->_logDirectly && logFileName)
436 d->_pLogger = new logger(logFileName, d->_logPipe);
437 else
438 d->_pLogger = NULL;
439
440 // writes to file directly
441 if (!d->_nomeFile.empty() && d->_logDirectly)
442 {
443 if (!d->_logPipe)
444 {
445 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
446
447 if (!d->_logfs.is_open())
448 {
449 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
450 }
451 else
452 d->_logfs.seekg(0, std::fstream::end);
453 }
454// on Windows pipe are not used as they are not supported on WinNT
455#ifndef WIN32
456 else
457 {
458 // create pipe
459 int err = mkfifo(d->_nomeFile.c_str(), S_IREAD | S_IWRITE);
460 if (err == 0 || errno == EEXIST)
461 {
462 // and open it
463 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
464 }
465 else
466 THROW(AppLogException("Can't create pipe"));
467 }
468#endif
469 if (d->_logfs.fail())
470 THROW(AppLogException("Can't open log file name"));
471 }
472
473 //from Error level on write to syslog also
474 slog.level(Slog::levelError);
475 slog.clogEnable(false);
476}
477
478AppLog::~AppLog()
479{
480 // if _logDirectly
481 close();
482 if (d) delete d;
483}
484
485void AppLog::subscribe()
486{
487 ost::MutexLock mtx(d->_subMutex);
488
489 Thread *pThr = getThread();
490 if (pThr)
491 {
492 cctid_t tid = pThr->getId();
493
494 LogPrivateData::iterator logIt = d->_logs.find(tid);
495 if (logIt == d->_logs.end())
496 {
497 // subscribes new thread
498 d->_logs[tid];
499 }
500 }
501}
502
503void AppLog::unsubscribe()
504{
505 ost::MutexLock mtx(d->_subMutex);
506
507 Thread *pThr = getThread();
508 if (pThr)
509 {
510 cctid_t tid = pThr->getId();
511
512 LogPrivateData::iterator logIt = d->_logs.find(tid);
513 if (logIt != d->_logs.end())
514 {
515 // unsubscribes thread
516 d->_logs.erase(logIt);
517 }
518 }
519}
520
521#ifndef WIN32
522void AppLog::logFileName(const char* FileName, bool logDirectly, bool usePipe)
523#else
524void AppLog::logFileName(const char* FileName, bool logDirectly)
525#endif
526{
527 if (!FileName)
528 {
529 slog.error("Null file name!");
530 return;
531 }
532
533 d->_lock.enterMutex();
534 d->_nomeFile = FileName;
535 close();
536 d->_logDirectly = logDirectly;
537#ifndef WIN32
538 d->_logPipe = usePipe;
539#else
540 d->_logPipe = false;
541#endif
542 if (!d->_logDirectly)
543 {
544 d->_nomeFile = FileName;
545 if (d->_pLogger)
546 d->_pLogger->logFileName(FileName, d->_logPipe);
547 else
548 d->_pLogger = new logger(FileName, d->_logPipe);
549
550 d->_lock.leaveMutex();
551 return;
552 }
553
554 // log directly
555 if (!d->_nomeFile.empty())
556 {
557 if (!d->_logPipe)
558 {
559 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
560 }
561#ifndef WIN32
562 else
563 {
564 // create pipe
565 int err = mkfifo(d->_nomeFile.c_str(), S_IREAD | S_IWRITE);
566 if (err == 0 || errno == EEXIST)
567 {
568 // and open it
569 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::in | std::fstream::out);
570 }
571 else
572 THROW(AppLogException("Can't create pipe"));
573 }
574#endif
575 if (d->_logfs.fail())
576 THROW(AppLogException("Can't open log file name"));
577 }
578 d->_lock.leaveMutex();
579}
580
581// writes to log
582void AppLog::writeLog(bool endOfLine)
583{
584 Thread *pThr = getThread();
585 if (pThr)
586 {
587 cctid_t tid = pThr->getId();
588
589 LogPrivateData::iterator logIt = d->_logs.find(tid);
590 if (logIt == d->_logs.end())
591 return;
592
593 if ((d->_logDirectly && !d->_logfs.is_open() && !logIt->second._clogEnable) ||
594 (!d->_logDirectly && !d->_pLogger && !logIt->second._clogEnable))
595
596 {
597 logIt->second._msgpos = 0;
598 logIt->second._msgbuf[0] = '\0';
599 return;
600 }
601
602 if (logIt->second._enable)
603 {
604 time_t now;
605 struct tm *dt;
606 time(&now);
607 struct timeval detail_time;
608 gettimeofday(&detail_time, NULL);
609 dt = localtime(&now);
610 char buf[50];
611
612 const char *p = "unknown";
613 switch (logIt->second._priority)
614 {
615 case Slog::levelEmergency:
616 p = "emerg";
617 break;
618 case Slog::levelInfo:
619 p = "info";
620 break;
621 case Slog::levelError:
622 p = "error";
623 break;
624 case Slog::levelAlert:
625 p = "alert";
626 break;
627 case Slog::levelDebug:
628 p = "debug";
629 break;
630 case Slog::levelNotice:
631 p = "notice";
632 break;
633 case Slog::levelWarning:
634 p = "warn";
635 break;
636 case Slog::levelCritical:
637 p = "crit";
638 break;
639 }
640
641 snprintf(buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
642 dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
643 dt->tm_hour, dt->tm_min, dt->tm_sec, (int)(detail_time.tv_usec / 1000));
644
645 buf[sizeof(buf)-1] = 0; // per sicurezza
646
647 if (d->_logDirectly)
648 {
649 d->_lock.enterMutex();
650 if (d->_logfs.is_open())
651 {
652 d->_logfs << buf;
653 if (!logIt->second._ident.empty())
654 d->_logfs << logIt->second._ident.c_str() << ": ";
655 d->_logfs << "[" << p << "] ";
656
657 d->_logfs << logIt->second._msgbuf;
658
659 if (endOfLine)
660 d->_logfs << endl;
661
662 d->_logfs.flush();
663 }
664 }
665 else if (d->_pLogger)
666 {
667 // ThreadQueue
668 std::stringstream sstr;
669 sstr.str(""); // reset contents
670 sstr << buf;
671
672 if (!logIt->second._ident.empty())
673 sstr << logIt->second._ident.c_str() << ": ";
674 sstr << "[" << p << "] ";
675
676 sstr << logIt->second._msgbuf;
677 if (endOfLine)
678 sstr << endl;
679 sstr.flush();
680
681 if (sstr.fail())
682 cerr << "stringstream failed!!!! " << endl;
683
684 // enqueues log message
685 d->_pLogger->post((void *) sstr.str().c_str(), sstr.str().length() + 1);
686
687 d->_lock.enterMutex();
688 }
689
690 // slog it if error level is right
691 if (logIt->second._slogEnable && logIt->second._priority <= Slog::levelError)
692 {
693 slog((Slog::Level) logIt->second._priority) << logIt->second._msgbuf;
694 if (endOfLine) slog << endl;
695 }
696 if (logIt->second._clogEnable
697#ifndef WIN32
698 && (getppid() > 1)
699#endif
700 )
701 {
702 clog << logIt->second._msgbuf;
703 if (endOfLine)
704 clog << endl;
705 }
706
707 d->_lock.leaveMutex();
708 }
709
710 logIt->second._msgpos = 0;
711 logIt->second._msgbuf[0] = '\0';
712 }
713}
714
715void AppLog::close(void)
716{
717 if (d->_logDirectly)
718 {
719 d->_lock.enterMutex();
720 if (d->_logfs.is_open())
721 {
722 d->_logfs.flush();
723 d->_logfs.close();
724 }
725 d->_lock.leaveMutex();
726 }
727}
728
729void AppLog::open(const char *ident)
730{
731 Thread *pThr = getThread();
732 if (pThr)
733 {
734 cctid_t tid = pThr->getId();
735
736 LogPrivateData::iterator logIt = d->_logs.find(tid);
737 if (logIt == d->_logs.end())
738 return;
739
740 if (d->_nomeFile.empty())
741 {
742 std::cerr << "Empty file name" << std::endl;
743 slog.emerg("Empty file nane!\n");
744 }
745 if (d->_logDirectly)
746 {
747 d->_lock.enterMutex();
748 if (!d->_logfs.is_open())
749 {
750 d->_logfs.open(d->_nomeFile.c_str(), std::fstream::out | std::fstream::app);
751 }
752 if (!d->_logfs.is_open())
753 {
754 std::cerr << "Can't open file name!" << std::endl;
755 slog.emerg("Can't open file name!\n");
756 }
757 d->_lock.leaveMutex();
758 }
759 if (ident != NULL)
760 logIt->second._ident = ident;
761
762 }
763}
764
765void AppLog::identLevel(const char *ident, Slog::Level level)
766{
767 if (!ident)
768 return;
769
770 string id = ident;
771
772 IdentLevel::iterator idLevIt = d->_identLevel.find(id);
773 if (idLevIt == d->_identLevel.end())
774 {
775 d->_identLevel[id] = level;
776 }
777 else
778 idLevIt->second = level;
779
780}
781
782void AppLog::level(Slog::Level enable)
783{
784 Thread *pThr = getThread();
785 if (pThr)
786 {
787 cctid_t tid = pThr->getId();
788
789 LogPrivateData::iterator logIt = d->_logs.find(tid);
790 if (logIt == d->_logs.end())
791 return;
792 logIt->second._level = enable;
793 }
794}
795
796void AppLog::clogEnable(bool f)
797{
798 Thread *pThr = getThread();
799 if (pThr)
800 {
801 cctid_t tid = pThr->getId();
802
803 LogPrivateData::iterator logIt = d->_logs.find(tid);
804 if (logIt == d->_logs.end())
805 return;
806 logIt->second._clogEnable = f;
807 }
808}
809
810void AppLog::slogEnable(bool en)
811{
812 Thread *pThr = getThread();
813 if (pThr)
814 {
815 cctid_t tid = pThr->getId();
816
817 LogPrivateData::iterator logIt = d->_logs.find(tid);
818 if (logIt == d->_logs.end())
819 return;
820
821 logIt->second._slogEnable = en;
822 }
823}
824
825int AppLog::sync()
826{
827 int retVal = (pbase() != pptr());
828
829 if (fail())
830 {
831 slog(Slog::levelNotice) << "fail() is true, calling clear()" << endl;
832 clear();
833 }
834
835 Thread *pThr = getThread();
836 if (pThr)
837 {
838 cctid_t tid = pThr->getId();
839 LogPrivateData::iterator logIt = d->_logs.find(tid);
840 if (logIt != d->_logs.end())
841 {
842 retVal = (logIt->second._msgpos > 0);
843 if (retVal)
844 {
845 slog(Slog::levelNotice) << "sync called and msgpos > 0" << endl;
846 }
847 }
848 }
849
850 overflow(EOF);
851
852 return retVal;
853
854}
855
856int AppLog::overflow(int c)
857{
858 Thread *pThr = getThread();
859 if (pThr)
860 {
861 cctid_t tid = pThr->getId();
862
863 LogPrivateData::iterator logIt = d->_logs.find(tid);
864 if (logIt == d->_logs.end())
865 return c;
866 if (!logIt->second._enable)
867 return c;
868
869 if (c == '\n' || !c || c == EOF)
870 {
871 if (!logIt->second._msgpos)
872 {
873 if (c == '\n') writeLog(true);
874 return c;
875 }
876 if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1))
877 logIt->second._msgbuf[logIt->second._msgpos] = 0;
878 else
879 logIt->second._msgbuf[logIt->second._msgpos-1] = 0;
880
881 writeLog(c == '\n');
882 //reset buffer
883 logIt->second._msgpos = 0;
884
885 return c;
886 }
887
888 if (logIt->second._msgpos < (int)(sizeof(logIt->second._msgbuf) - 1))
889 logIt->second._msgbuf[logIt->second._msgpos++] = c;
890
891 }
892
893 return c;
894}
895
896#ifdef HAVE_SNPRINTF
897
898void AppLog::error(const char *format, ...)
899{
900 va_list args;
901
902 Thread *pThr = getThread();
903 if (pThr)
904 {
905 cctid_t tid = pThr->getId();
906
907 LogPrivateData::iterator logIt = d->_logs.find(tid);
908 if (logIt == d->_logs.end())
909 return;
910
911 error();
912 if (!logIt->second._enable)
913 return;
914 overflow(EOF);
915
916 va_start(args, format);
917 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
918 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
919 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
920 overflow(EOF);
921 if (logIt->second._slogEnable)
922 slog.error(logIt->second._msgbuf);
923 va_end(args);
924 }
925}
926
927void AppLog::warn(const char *format, ...)
928{
929 va_list args;
930
931 Thread *pThr = getThread();
932 if (pThr)
933 {
934 cctid_t tid = pThr->getId();
935
936 LogPrivateData::iterator logIt = d->_logs.find(tid);
937 if (logIt == d->_logs.end())
938 return;
939
940 warn();
941 if (!logIt->second._enable)
942 return;
943 overflow(EOF);
944
945 va_start(args, format);
946 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
947 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
948 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
949 overflow(EOF);
950 if (logIt->second._slogEnable)
951 slog.warn(logIt->second._msgbuf);
952 va_end(args);
953 }
954}
955
956void AppLog::debug(const char *format, ...)
957{
958 va_list args;
959
960 Thread *pThr = getThread();
961 if (pThr)
962 {
963 cctid_t tid = pThr->getId();
964
965 LogPrivateData::iterator logIt = d->_logs.find(tid);
966 if (logIt == d->_logs.end())
967 return;
968
969 debug();
970 if (!logIt->second._enable)
971 return;
972 overflow(EOF);
973
974 va_start(args, format);
975 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
976 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
977 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
978 overflow(EOF);
979 va_end(args);
980 }
981}
982
983void AppLog::emerg(const char *format, ...)
984{
985 va_list args;
986
987 Thread *pThr = getThread();
988 if (pThr)
989 {
990 cctid_t tid = pThr->getId();
991
992 LogPrivateData::iterator logIt = d->_logs.find(tid);
993 if (logIt == d->_logs.end())
994 return;
995
996 emerg();
997 if (!logIt->second._enable)
998 return;
999 overflow(EOF);
1000
1001 va_start(args, format);
1002 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
1003 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
1004 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
1005 overflow(EOF);
1006 if (logIt->second._slogEnable)
1007 slog.emerg(logIt->second._msgbuf);
1008 va_end(args);
1009 }
1010}
1011
1012void AppLog::alert(const char *format, ...)
1013{
1014 va_list args;
1015
1016 Thread *pThr = getThread();
1017 if (pThr)
1018 {
1019 cctid_t tid = pThr->getId();
1020
1021 LogPrivateData::iterator logIt = d->_logs.find(tid);
1022 if (logIt == d->_logs.end())
1023 return;
1024
1025 alert();
1026 if (!logIt->second._enable)
1027 return;
1028 overflow(EOF);
1029
1030 va_start(args, format);
1031 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
1032 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
1033 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
1034 overflow(EOF);
1035 if (logIt->second._slogEnable)
1036 slog.alert(logIt->second._msgbuf);
1037 va_end(args);
1038 }
1039}
1040
1041void AppLog::critical(const char *format, ...)
1042{
1043 va_list args;
1044
1045 Thread *pThr = getThread();
1046 if (pThr)
1047 {
1048 cctid_t tid = pThr->getId();
1049
1050 LogPrivateData::iterator logIt = d->_logs.find(tid);
1051 if (logIt == d->_logs.end())
1052 return;
1053
1054 critical();
1055 if (!logIt->second._enable)
1056 return;
1057 overflow(EOF);
1058
1059 va_start(args, format);
1060 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
1061 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
1062 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
1063 overflow(EOF);
1064 if (logIt->second._slogEnable)
1065 slog.critical(logIt->second._msgbuf);
1066 va_end(args);
1067 }
1068}
1069
1070void AppLog::notice(const char *format, ...)
1071{
1072 va_list args;
1073
1074 Thread *pThr = getThread();
1075 if (pThr)
1076 {
1077 cctid_t tid = pThr->getId();
1078
1079 LogPrivateData::iterator logIt = d->_logs.find(tid);
1080 if (logIt == d->_logs.end())
1081 return;
1082
1083 notice();
1084 if (!logIt->second._enable)
1085 return;
1086 overflow(EOF);
1087
1088 va_start(args, format);
1089 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
1090 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
1091 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
1092 overflow(EOF);
1093 if (logIt->second._slogEnable)
1094 slog.notice(logIt->second._msgbuf);
1095 va_end(args);
1096 }
1097}
1098
1099void AppLog::info(const char *format, ...)
1100{
1101 va_list args;
1102
1103 Thread *pThr = getThread();
1104 if (pThr)
1105 {
1106 cctid_t tid = pThr->getId();
1107
1108 LogPrivateData::iterator logIt = d->_logs.find(tid);
1109 if (logIt == d->_logs.end())
1110 return;
1111
1112 info();
1113 if (!logIt->second._enable)
1114 return;
1115 overflow(EOF);
1116
1117 va_start(args, format);
1118 logIt->second._msgbuf[logStruct::BUFF_SIZE-1] = '\0';
1119 logIt->second._msgpos = vsnprintf(logIt->second._msgbuf, logStruct::BUFF_SIZE, format, args);
1120 if (logIt->second._msgpos > logStruct::BUFF_SIZE - 1) logIt->second._msgpos = logStruct::BUFF_SIZE - 1;
1121 overflow(EOF);
1122 va_end(args);
1123 }
1124}
1125
1126#endif //HAVE_SNPRINTF
1127
1128AppLog &AppLog::operator()(Slog::Level lev)
1129{
1130 Thread *pThr = getThread();
1131 if (pThr)
1132 {
1133 cctid_t tid = pThr->getId();
1134
1135 LogPrivateData::iterator logIt = d->_logs.find(tid);
1136 if (logIt == d->_logs.end())
1137 return *this;
1138
1139 // needed? overflow(EOF);
1140
1141 // enables log
1142 Slog::Level th_lev = logIt->second._level;
1143 logIt->second._enable = (th_lev >= lev);
1144 // is there a log level per module?
1145 if (!logIt->second._ident.empty())
1146 {
1147 std::string st = logIt->second._ident;
1148 IdentLevel::iterator idLevIt = d->_identLevel.find(st);
1149 if (idLevIt != d->_identLevel.end())
1150 {
1151 th_lev = idLevIt->second;
1152 logIt->second._enable = (th_lev >= lev);
1153 }
1154 }
1155
1156 logIt->second._priority = lev;
1157 }
1158
1159 return *this;
1160}
1161
1162AppLog &AppLog::operator()(const char *ident, Slog::Level lev)
1163{
1164 Thread *pThr = getThread();
1165 if (pThr)
1166 {
1167 cctid_t tid = pThr->getId();
1168
1169 LogPrivateData::iterator logIt = d->_logs.find(tid);
1170 if (logIt == d->_logs.end())
1171 return this->operator()(lev);
1172
1173 logIt->second._enable = true;
1174 open(ident);
1175 }
1176
1177 return this->operator()(lev);
1178}
1179
1180
1181AppLog& AppLog::operator<< (AppLog& (*pfManipulator)(AppLog&))
1182{
1183 return (*pfManipulator)(*this);
1184}
1185
1186AppLog& AppLog::operator<< (ostream& (*pfManipulator)(ostream&))
1187{
1188 (*pfManipulator)(*(dynamic_cast<ostream*>(this)));
1189
1190 return *this ;
1191}
1192
1193
1194#ifdef CCXX_NAMESPACES
1195}
1196#endif
1197