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