DABC (Data Acquisition Backbone Core)  2.9.9
logging.cxx
Go to the documentation of this file.
1 // $Id: logging.cxx 4477 2020-04-15 14:19:58Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/logging.h"
17 
18 #include <cstdio>
19 #include <cstdarg>
20 #include <cstring>
21 #include <iostream>
22 #include <list>
23 
24 #ifndef _BSD_SOURCE
25 #define _BSD_SOURCE
26 #endif
27 
28 #include <sys/time.h>
29 #include <unistd.h>
30 #include <syslog.h>
31 
32 #include "dabc/timing.h"
33 #include "dabc/threads.h"
34 
36 
37 dabc::Logger mydebug; // here is an instance of default debug output
38 
39 namespace dabc {
40 
41  class LoggerEntry {
42  public:
43  std::string fFileName;
44  std::string fFuncName;
45  unsigned fLine;
46  int fLevel;
47  unsigned fCounter;
48  time_t fMsgTime; // normal time when message will be output
49  std::string fLastMsg; // last shown message
50  TimeStamp fLastTm; // dabc (fast) time of last output
51  unsigned fDropCnt; // number of dropped messages
52  bool fShown; // used in statistic output
53 
54  LoggerEntry(const char* fname, const char* funcname, unsigned line, int lvl) :
55  fFileName(fname),
56  fFuncName(funcname),
57  fLine(line),
58  fLevel(lvl),
59  fCounter(0),
60  fMsgTime(),
61  fLastMsg(),
62  fLastTm(),
63  fDropCnt(0),
64  fShown(false)
65  {
66  }
67 
69  };
70 
72  public:
73 
74  typedef std::list<LoggerEntry*> flist;
75 
77  unsigned fLine;
78 
79  LoggerLineEntry(unsigned line) : fFiles(), fLine(line) {}
80 
82  {
83  while (fFiles.size()>0) {
84  delete fFiles.front();
85  fFiles.pop_front();
86  }
87  }
88 
89  LoggerEntry* GetFile(const char* filename, const char* funcname, int lvl)
90  {
91  flist::iterator iter = fFiles.begin();
92  while (iter != fFiles.end()) {
93  if ((*iter)->fFileName.compare(filename)==0) return *iter;
94  iter++;
95  }
96 
97  LoggerEntry* f = new LoggerEntry(filename, funcname, fLine, lvl);
98  fFiles.push_front(f);
99  return f;
100  }
101  };
102 
103 }
104 
105 // ____________________________________________________________
106 
107 
108 dabc::Logger::Logger(bool withmutex)
109 {
110  fPrev = gDebug;
111 
112  fDebugLevel = 1;
113  fFileLevel = 1;
114  fSyslogLevel = 0;
115  fLevel = 1;
116  fPrefix = "";
117 
120  fFileMask = lNoPrefix | lTime; // disable prefix and enable time
121 
122  fMutex = withmutex ? new Mutex(true) : 0;
123  fMaxLine = 0;
124  fLines = 0;
125 
126  fLogFileName = "";
127  fFile = 0;
128  fSyslogPrefix = "";
129  fLogReopenTime = 0.;
130  fLogFileModified = false;
131  fLogLimit = 100;
132  fLogReopenDisabled = false;
133 
134  LockGuard lock(fMutex);
135  _ExtendLines(1024);
136 
137  gDebug = this;
138 }
139 
141 {
142  gDebug = fPrev;
143 
144  CloseFile();
145 
146  Syslog(0);
147 
148  {
149  LockGuard lock(fMutex);
150 
151 // printf("Destroy logger %p lines %u\n", this, fMaxLine);
152 
153  for (unsigned n=0; n<fMaxLine; n++)
154  if (fLines[n]) { /*printf(" destroy line %3u %p\n", n, fLines[n]); */ delete fLines[n]; }
155  _ExtendLines(0);
156  }
157 
158  delete fMutex; fMutex = 0;
159 }
160 
162 {
163  LockGuard lock(fMutex);
164 
165  if (fFile) fclose(fFile);
166  fFile = 0;
167 }
168 
169 
171 {
172  fDebugLevel = level;
173  fLevel = fDebugLevel < fFileLevel ? fFileLevel : fDebugLevel;
174 }
175 
177 {
178  fFileLevel = level;
179  fLevel = fDebugLevel < fFileLevel ? fFileLevel : fDebugLevel;
180 }
181 
183 {
184  fSyslogLevel = level;
185 }
186 
187 
188 void dabc::Logger::_ExtendLines(unsigned max)
189 {
190  if ((max>0) && (max<fMaxLine)) return;
191 
192  LoggerLineEntry **lin = 0;
193  if (max>0) {
194 
195 // printf("Extend logger lines %u\n", max);
196 
197  lin = new LoggerLineEntry* [max];
198  unsigned n = 0;
199 
200  while (n < fMaxLine) { lin[n] = fLines[n]; n++; }
201  while (n < max) { lin[n] = 0; n++; }
202  }
203 
204  if (fLines) delete[] fLines;
205 
206  fLines = lin;
207  fMaxLine = max;
208 }
209 
210 void dabc::Logger::LogFile(const char* fname)
211 {
212  LockGuard lock(fMutex);
213 
214  if (fFile) fclose(fFile);
215 
216  fFile = 0;
217 
218  if ((fname!=0) && (strlen(fname)>0)) {
219  fLogFileName = fname;
220  fFile = fopen(fname, "a");
221  fLogReopenTime = dabc::Now().AsDouble();
222  fLogFileModified = false;
223  }
224 }
225 
226 void dabc::Logger::Syslog(const char* prefix)
227 {
228  LockGuard lock(fMutex);
229 
230  fSyslogPrefix = prefix ? prefix : "";
231 }
232 
233 
234 void dabc::Logger::_FillString(std::string& str, unsigned mask, LoggerEntry* entry)
235 {
236  str.clear();
237  if (mask==0) return;
238 
239  if ((mask & lPrefix) && ((mask & lNoPrefix) == 0))
240  if (fPrefix.length() > 0) {
241  str = fPrefix;
242  //str += ":";
243  }
244 
245  if (mask & lLevel) {
246  if (str.length() > 0) str+=" ";
247  if (entry->fLevel<0)
248  str += "EOUT";
249  else
250  str += dabc::format("DOUT%d", entry->fLevel);
251  }
252 
253  if (mask & lSyslgLvl) {
254  if (str.length() > 0) str+=" ";
255  if (entry->fLevel<0)
256  str += " <E>";
257  else
258  str += " <I>";
259  }
260 
261  if (mask & (lDate | lTime)) {
262  struct tm tm_res;
263  struct tm * inf = localtime_r ( &(entry->fMsgTime), &tm_res );
264  if (mask & lDate) {
265  if (str.length() > 0) str+=" ";
266  str += dabc::format("%d-%02d-%d", inf->tm_mday, inf->tm_mon, inf->tm_year + 1900);
267  }
268 
269  if (mask & lTime) {
270  if (str.length() > 0) str+=" ";
271  str += dabc::format("%02d:%02d:%02d", inf->tm_hour, inf->tm_min, inf->tm_sec);
272  }
273  }
274 
275  if ((mask & lTStamp) && !(mask & lSyslgLvl)) {
276  double tm = dabc::Now().AsDouble();
277  if (str.length() > 0) str+=" ";
278  str += dabc::format("%10.6f", tm);
279  }
280 
281  if (mask & lFile) {
282  if (str.length() > 0) str+=" ";
283 // str += "File:";
284  str += entry->fFileName;
285  }
286 
287  if (mask & lFunc) {
288  if (str.length() > 0) str+=":";
289 // str += "Func:";
290  str += entry->fFuncName;
291  }
292 
293  if (mask & lLine) {
294  if (str.length() > 0) str+=":";
295  str += dabc::format("%u", entry->fLine);
296  }
297 
298  if (mask & lMessage) {
299  if (str.length() > 0) str+=" ";
300  str += entry->fLastMsg;
301  }
302 
303  if ((mask & lNoDrop) == 0)
304  if (entry->fDropCnt > 0)
305  str += dabc::format(" [Drop %u]", entry->fDropCnt);
306 }
307 
308 void dabc::Logger::DoOutput(int level, const char* filename, unsigned linenumber, const char* funcname, const char* message)
309 {
310  TimeStamp now = dabc::Now();
311 
312  std::string syslogout;
313 
314  {
315 
316  LockGuard lock(fMutex);
317 
318  if (linenumber>=fMaxLine)
319  _ExtendLines((linenumber/1024 + 1) * 1024);
320 
321  LoggerLineEntry* lentry = fLines[linenumber];
322 
323  if (lentry == 0) {
324  lentry = new LoggerLineEntry(linenumber);
325  fLines[linenumber] = lentry;
326  }
327 
328  LoggerEntry* entry = lentry->GetFile(filename, funcname, level);
329  entry->fCounter++;
330 
331  unsigned mask = level>=0 ? fDebugMask : fErrorMask;
332  unsigned fmask = mask | (fFile ? fFileMask : 0);
333  bool drop_msg = (entry->fCounter > fLogLimit) &&
334  ((now - entry->fLastTm) < 0.5);
335 
336  if (drop_msg) entry->fDropCnt++;
337 
338  if (drop_msg && ((mask & lNoDrop) == 0) && ((fmask & lNoDrop) == 0)) return;
339 
340  entry->fMsgTime = time(0);
341  entry->fLastMsg = message;
342 
343  if ((!drop_msg || (mask & lNoDrop)) && (level<=fDebugLevel)) {
344  std::string str;
345  _FillString(str, mask, entry);
346 
347  if (str.length() > 0) {
348  FILE* out = level < 0 ? stderr : stdout;
349  fprintf(out, "%s\n", str.c_str());
350  fflush(out);
351  }
352  }
353 
354  if (!fSyslogPrefix.empty() && (!drop_msg || (mask & lNoDrop)) && (level<=fSyslogLevel)) {
355  _FillString(syslogout, mask | lSyslgLvl, entry);
356  }
357 
358  if (fFile && (!drop_msg || (fmask & lNoDrop)) && (level<=fFileLevel)) {
359  std::string str;
360  _FillString(str, fmask, entry);
361  if (str.length()>0) {
362  fprintf(fFile, "%s\n", str.c_str());
363  fflush(fFile);
364  fLogFileModified = true;
365  }
366  _DoCheckTimeout();
367  }
368 
369  if (!drop_msg) {
370  entry->fDropCnt = 0;
371  entry->fLastTm = now;
372  }
373 
374  } // end of LockGuard
375 
376  if (!syslogout.empty()) {
377  openlog(fSyslogPrefix.c_str(), LOG_ODELAY, LOG_LOCAL1);
378  syslog(level < 0 ? LOG_ERR : LOG_INFO, "%s", syslogout.c_str());
379  closelog();
380  }
381 
382 }
383 
385 {
386  if (fLogReopenDisabled || (fFile==0) || fLogFileName.empty() || !fLogFileModified) return;
387 
388  double now = dabc::Now().AsDouble();
389 
390  if ((now - fLogReopenTime) > 3.) {
391  fLogReopenTime = now;
392  fclose(fFile);
393  fFile = fopen(fLogFileName.c_str(), "a");
394  fLogFileModified = false;
395  }
396 }
397 
399 {
400  if ((Instance()==0) || Instance()->fLogReopenDisabled) return;
401  LockGuard lock(Instance()->fMutex);
402  Instance()->_DoCheckTimeout();
403 }
404 
406 {
407  if (Instance()) Instance()->fLogReopenDisabled = true;
408 }
409 
410 void dabc::Logger::ShowStat(bool tofile)
411 {
412  LockGuard lock(fMutex);
413 
414  FILE* out = tofile ? fFile : stdout;
415  if (out==0) out = stdout;
416 
417  fprintf(out,"\n======= Begin debug statistic =============\n");
418 
419  for (unsigned n=0; n<fMaxLine;n++) {
420  LoggerLineEntry* entry = fLines[n];
421  if (entry==0) continue;
422 
423  LoggerLineEntry::flist::iterator iter = entry->fFiles.begin();
424 
425  while (iter != entry->fFiles.end()) {
426  (*iter)->fShown = false;
427  iter++;
428  }
429  }
430 
431  std::string* currfile = 0;
432 
433  do {
434 
435  currfile = 0;
436 
437  for (unsigned n=0; n<fMaxLine;n++) {
438  LoggerLineEntry* entry = fLines[n];
439  if (entry==0) continue;
440 
441  LoggerLineEntry::flist::iterator iter = entry->fFiles.begin();
442 
443  while (iter != entry->fFiles.end()) {
444  LoggerEntry* fentry = *iter++;
445 
446  if (fentry->fShown) continue;
447 
448  if ((currfile!=0) && (fentry->fFileName.compare(*currfile) != 0)) continue;
449 
450  if (currfile==0) {
451  currfile = &(fentry->fFileName);
452  fprintf(out, "\nFile: %s\n", currfile->c_str());
453  }
454 
455  fprintf(out," Line:%4u Lvl:%2d Cnt:%4u Func:%s Msg:'%s'\n",
456  n, fentry->fLevel, fentry->fCounter, fentry->fFuncName.c_str(), fentry->fLastMsg.c_str());
457 
458  fentry->fShown = true;
459  }
460  }
461  } while (currfile != 0);
462 
463  fprintf(out,"\n======= Stop debug statistic =============\n");
464 
465  fflush(out);
466 }
467 
468 void dabc::SetDebugLevel(int level)
469 {
471 }
472 
473 void dabc::SetFileLevel(int level)
474 {
476 }
477 
478 void dabc::SetDebugPrefix(const char* prefix)
479 {
481 }
482 
484 {
485  return dabc::Logger::Instance();
486 }
Lock guard for posix mutex.
Definition: threads.h:127
unsigned fDropCnt
Definition: logging.cxx:51
std::string fLastMsg
Definition: logging.cxx:49
unsigned fLine
Definition: logging.cxx:45
LoggerEntry(const char *fname, const char *funcname, unsigned line, int lvl)
Definition: logging.cxx:54
TimeStamp fLastTm
Definition: logging.cxx:50
unsigned fCounter
Definition: logging.cxx:47
std::string fFuncName
Definition: logging.cxx:44
std::string fFileName
Definition: logging.cxx:43
LoggerLineEntry(unsigned line)
Definition: logging.cxx:79
std::list< LoggerEntry * > flist
Definition: logging.cxx:74
LoggerEntry * GetFile(const char *filename, const char *funcname, int lvl)
Definition: logging.cxx:89
Logging class.
Definition: logging.h:49
void SetFileLevel(int level=0)
Definition: logging.cxx:176
LoggerLineEntry ** fLines
Definition: logging.h:126
double fLogReopenTime
Definition: logging.h:140
Mutex * fMutex
Definition: logging.h:128
unsigned fErrorMask
Definition: logging.h:132
std::string fLogFileName
Definition: logging.h:139
virtual void Syslog(const char *prefix)
Definition: logging.cxx:226
bool fLogReopenDisabled
Definition: logging.h:143
virtual ~Logger()
Definition: logging.cxx:140
void CloseFile()
Close any file open by logger.
Definition: logging.cxx:161
virtual void LogFile(const char *fname)
Definition: logging.cxx:210
void SetPrefix(const char *prefix=0)
Definition: logging.h:89
Logger(bool withmutex=true)
Definition: logging.cxx:108
void SetSyslogLevel(int level=0)
Definition: logging.cxx:182
unsigned fDebugMask
Definition: logging.h:131
std::string fSyslogPrefix
Definition: logging.h:130
int fDebugLevel
Definition: logging.h:134
int fSyslogLevel
Definition: logging.h:136
unsigned fFileMask
Definition: logging.h:133
static Logger * Instance()
Definition: logging.h:104
std::string fPrefix
Definition: logging.h:138
static void DisableLogReopen()
Definition: logging.cxx:405
void ShowStat(bool tofile=true)
Definition: logging.cxx:410
virtual void _DoCheckTimeout()
Definition: logging.cxx:384
unsigned fLogLimit
Definition: logging.h:142
FILE * fFile
Definition: logging.h:129
int fFileLevel
Definition: logging.h:135
void _ExtendLines(unsigned max)
Definition: logging.cxx:188
void SetDebugLevel(int level=0)
Definition: logging.cxx:170
int fLevel
Definition: logging.h:137
virtual void DoOutput(int level, const char *filename, unsigned linenumber, const char *funcname, const char *message)
Definition: logging.cxx:308
bool fLogFileModified
Definition: logging.h:141
unsigned fMaxLine
Definition: logging.h:127
Logger * fPrev
Definition: logging.h:125
static Logger * gDebug
Definition: logging.h:114
static void CheckTimeout()
Definition: logging.cxx:398
void _FillString(std::string &str, unsigned mask, LoggerEntry *entry)
Definition: logging.cxx:234
posix pthread mutex
Definition: threads.h:61
dabc::Logger mydebug
Definition: logging.cxx:37
Event manipulation API.
Definition: api.h:23
TimeStamp Now()
Definition: timing.h:260
void SetDebugLevel(int level=0)
Definition: logging.cxx:468
std::string format(const char *fmt,...)
Definition: string.cxx:49
void SetDebugPrefix(const char *prefix=0)
Definition: logging.cxx:478
void SetFileLevel(int level=0)
Definition: logging.cxx:473
Logger * lgr()
Definition: logging.cxx:483
Class for acquiring and holding timestamps.
Definition: timing.h:40
double AsDouble() const
Return time stamp in form of double (in seconds)
Definition: timing.h:120