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