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