GSI Object Oriented Online Offline (Go4)  GO4-6.3.0
TGo4Log.cxx
Go to the documentation of this file.
1 // $Id$
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 #include "TGo4Log.h"
15 
16 #ifndef _MSC_VER
17 #include <unistd.h>
18 #include <fcntl.h>
19 #endif
20 
21 #include <stdarg.h>
22 #include <fstream>
23 #include <iostream>
24 
25 #include "TDatime.h"
26 #include "TDataType.h"
27 #include "TMutex.h"
28 #include "TSystem.h"
29 
30 
31 const char *TGo4Log::fgcLEFT = "GO4-";
32 //const char *TGo4Log::fgcRIGHT = " <GO4";
33 const char *TGo4Log::fgcRIGHT = " ";
34 const char *TGo4Log::fgcDEBUG = "d";
35 const char *TGo4Log::fgcINFO = "*";
36 const char *TGo4Log::fgcWARN = "#";
37 const char *TGo4Log::fgcERR = "!";
38 const char *TGo4Log::fgcDEFAULTLOG = "go4logfile.txt";
39 
40 TString TGo4Log::fgsGO4SYS = "";
41 
43 Int_t TGo4Log::fgiIgnoreLevel = 1;
44 Bool_t TGo4Log::fgbOutputEnabled = kTRUE;
45 Bool_t TGo4Log::fgbLogfileEnabled = kFALSE;
46 Bool_t TGo4Log::fgbAutoMode = kFALSE;
47 void *TGo4Log::fgxLogfile = nullptr;
48 TMutex *TGo4Log::fgxMutex = nullptr;
49 TGo4Log *TGo4Log::fgxInstance = nullptr;
50 
52 
53 TNamed *TGo4Log::fgSniffer = nullptr;
54 
55 int TGo4Log::fgStdPipe[2] = {-1, -1};
56 int TGo4Log::fgStdSave = -1;
57 
58 class TLogTimer : public TTimer {
59  public:
60  TLogTimer(Int_t millisec) : TTimer(millisec) {}
61 
62  Bool_t Notify() override { TGo4Log::ProcessRedirection(); return kTRUE; }
63 };
64 
65 
66 TLogTimer *TGo4Log::fgTimer = nullptr;
67 
69 {
70  if (!fgxMutex) fgxMutex = new TMutex(kTRUE);
71 
72  // initialization at first time we call logger
73  // we use recursive mode for cascading lockguards
74  if (IsLogfileEnabled()) {
75  OpenLogfile(fgcDEFAULTLOG,"--- This is the default Go4 Message logfile ---");
76  LogfileEnable(kFALSE); // after first write disable logfile
77  }
78 }
79 
81 {
82  CloseLogfile();
83 }
84 
86 {
87  if(!fgxInstance)
88  fgxInstance = new TGo4Log();
89 
90  return fgxInstance;
91 }
92 
94 {
95  if (fgStdSave > 0) return;
96 
97 #ifndef _MSC_VER
98 
99  fflush(stdout);
100 
101  fgStdSave = dup(STDOUT_FILENO); /* save stdout for display later */
102 
103  if(pipe(fgStdPipe) != 0) return; /* make a pipe */
104 
105  dup2(fgStdPipe[1], STDOUT_FILENO); /* redirect stdout to the pipe */
106  long flags = fcntl(fgStdPipe[0], F_GETFL);
107  flags |= O_NONBLOCK;
108  fcntl(fgStdPipe[0], F_SETFL, flags);
109 
110  if (!fgTimer) {
111  fgTimer = new TLogTimer(200);
112  fgTimer->Start(200);
113  }
114 #endif
115 }
116 
117 
119 {
120  if (fgStdSave < 0) return;
121 
122 #ifndef _MSC_VER
123 
124  if (kind >= 0) {
125 
126  std::cout.flush();
127  fflush(stdout);
128 
129  char buffer[20000];
130  memset(buffer, 0, sizeof(buffer));
131  int len = read(fgStdPipe[0], buffer, sizeof(buffer)-1); /* read from pipe into buffer */
132 
133  // when nothing to read, than nothing to redirect
134  if (len == 0) return;
135 
136  dup2(fgStdSave, STDOUT_FILENO); /* reconnect stdout for realoutput */
137 
138  printf("%s", buffer);
139  fflush(stdout);
140 
141  if (fgSniffer) fgSniffer->SetTitle(buffer);
142  }
143 
144  if (kind <= 0) {
145  dup2(fgStdPipe[1], STDOUT_FILENO); // redirect again
146  }
147 
148 #endif
149 }
150 
151 void TGo4Log::SetSniffer(TNamed *sniff)
152 {
153  fgSniffer = sniff;
154 }
155 
156 const char *TGo4Log::GO4SYS()
157 {
158  if (fgsGO4SYS.Length()>0) return fgsGO4SYS.Data();
159  const char *go4sys = gSystem->Getenv("GO4SYS");
160 #ifdef COMP_GO4SYS
161  if (!go4sys || (strlen(go4sys) == 0)) go4sys = COMP_GO4SYS;
162 #endif
163  if (!go4sys || (strlen(go4sys) == 0)) return "";
164 
165  fgsGO4SYS = go4sys;
166  if (fgsGO4SYS.Length() > 0) {
167 #ifdef _MSC_VER
168  char lastsymbol = '\\';
169  fgsGO4SYS.ReplaceAll("/","\\"); // while in cygpath we cannot deliver windows-like slashes
170 #else
171  char lastsymbol = '/';
172 #endif
173  if (fgsGO4SYS[fgsGO4SYS.Length() - 1] != lastsymbol) fgsGO4SYS += lastsymbol;
174  }
175 
176  return fgsGO4SYS.Length()>0 ? fgsGO4SYS.Data() : "";
177 }
178 
179 const char *TGo4Log::GO4INCPATH()
180 {
181  #ifdef COMP_GO4INC
182  return COMP_GO4INC;
183  #else
184  return "";
185  #endif
186 }
187 
188 
189 TString TGo4Log::subGO4SYS(const char *subdir)
190 {
191  const char *go4sys = GO4SYS();
192 
193  if (!subdir || (strlen(subdir) == 0)) return TString(go4sys);
194 
195  TString res = go4sys;
196 
197 #ifdef _MSC_VER
198  res += TString(subdir).ReplaceAll("/","\\");
199 #else
200  res += subdir;
201 #endif
202 
203  return res;
204 }
205 
206 const char *TGo4Log::Message(Int_t prio, const char *text,...)
207 {
208  Instance();
209  //TGo4LockGuard(fxMutex);
210  if(prio>-1 && prio<fgiIgnoreLevel) return nullptr;
211  char txtbuf[fguMESLEN-20];
212  va_list args;
213  va_start(args, text);
214  vsnprintf(txtbuf, fguMESLEN-20, text, args);
215  va_end(args);
216  const char *prefix = fgcINFO;
217  switch(prio) {
218  // info output independent of current ignorelevel
219  case -1: prefix = fgcINFO; break;
220  case 0: prefix = fgcDEBUG; break;
221  case 1: prefix = fgcINFO; break;
222  case 2: prefix = fgcWARN; break;
223  case 3: prefix = fgcERR; break;
224  } // switch()
225 
226  if(fgbLogfileEnabled) {
227  // message format for logfile is different:
228  int resf = snprintf(fgcMessagetext, __MESSAGETEXTLENGTH__, "%s %s", prefix, txtbuf);
229  WriteLogfile(fgcMessagetext);
230 
231  (void) resf; // prevent compiler warnings
232  }
233 
234  // we compose the full messagetext anyway, for further use outside
235  int res = snprintf(fgcMessagetext, __MESSAGETEXTLENGTH__, "%s%s> %s %s", fgcLEFT, prefix, txtbuf, fgcRIGHT);
236  (void) res; // prevent compiler warnings
237 
238  if(fgbOutputEnabled) {
239 
240  ProcessRedirection(1); // disable redirection
241 
242  std::cout << fgcMessagetext << std::endl;
243 
244  std::cout.flush();
245 
246  if (fgSniffer) fgSniffer->SetTitle(fgcMessagetext);
247 
248  ProcessRedirection(-1); // enable again
249  }
250 
251  return fgcMessagetext;
252 }
253 
254 void TGo4Log::Printf(Bool_t _stdout, const char *text)
255 {
256  ProcessRedirection(1); // disable redirection
257 
258  if (_stdout) {
259  fprintf(stdout, "%s", text);
260  fflush(stdout);
261  } else {
262  fprintf(stderr, "%s", text);
263  fflush(stderr);
264  }
265 
266  ProcessRedirection(-1); // enable again
267 }
268 
269 
270 void TGo4Log::PrintRate(ULong64_t cnt, double rate)
271 {
272  ProcessRedirection(1); // disable redirection
273 
274  int width = (rate > 1e4) ? 0 : (rate < 1. ? 3 : 1);
275  fprintf(stdout, "\rCnt = %llu Rate = %5.*f Ev/s", cnt, width, rate);
276  fflush(stdout);
277 
278  ProcessRedirection(-1); // enable again
279 }
280 
281 void TGo4Log::Debug(const char *text,...)
282 {
283  if(fgiIgnoreLevel>0) return;
284  Instance();
285  //TGo4LockGuard(fxMutex);
286  char txtbuf[fguMESLEN];
287  va_list args;
288  va_start(args, text);
289  vsnprintf(txtbuf, fguMESLEN, text, args);
290  va_end(args);
291  Message(0, "%s", txtbuf);
292 }
293 
294 void TGo4Log::Info(const char *text,...)
295 {
296  if(fgiIgnoreLevel>1) return;
297  Instance();
298  //TGo4LockGuard(fxMutex);
299  char txtbuf[fguMESLEN];
300  va_list args;
301  va_start(args, text);
302  vsnprintf(txtbuf, fguMESLEN, text, args);
303  va_end(args);
304  Message(1, "%s", txtbuf);
305 }
306 
307 void TGo4Log::Warn(const char *text,...)
308 {
309  if(fgiIgnoreLevel>2) return;
310  Instance();
311  //TGo4LockGuard(fxMutex);
312  char txtbuf[fguMESLEN];
313  va_list args;
314  va_start(args, text);
315  vsnprintf(txtbuf, fguMESLEN, text, args);
316  va_end(args);
317  Message(2, "%s", txtbuf);
318 }
319 
320 void TGo4Log::Error(const char *text,...)
321 {
322  Instance();
323  //TGo4LockGuard(fxMutex);
324  char txtbuf[fguMESLEN];
325  va_list args;
326  va_start(args, text);
327  vsnprintf(txtbuf, fguMESLEN, text, args);
328  va_end(args);
329  Message(3, "%s", txtbuf);
330 }
331 
332 void TGo4Log::SetIgnoreLevel(Int_t level)
333 {
334  //TGo4LockGuard(fxMutex);
335  fgiIgnoreLevel = level;
336 }
337 
339 {
340  return fgiIgnoreLevel;
341 }
342 
343 const char *TGo4Log::GetLogname()
344 {
345  return fgxLogName.Data();
346 }
347 
349 {
350  return fgcDEFAULTLOG;
351 }
352 
353 void TGo4Log::OutputEnable(Bool_t on)
354 {
355  fgbOutputEnabled = on;
356 }
357 
359 {
360  return fgbOutputEnabled;
361 }
362 
363 void TGo4Log::LogfileEnable(Bool_t on)
364 {
365  fgbLogfileEnabled = on;
366 }
367 
369 {
370  return fgbLogfileEnabled;
371 }
372 
373 void TGo4Log::AutoEnable(Bool_t on)
374 {
375  fgbAutoMode = on;
376 }
377 
379 {
380  return fgbAutoMode;
381 }
382 
383 void TGo4Log::OpenLogfile(const char *name, const char *headercomment, Bool_t appendmode)
384 {
385  //TGo4LockGuard(fxMutex);
386  try
387  {
388  CloseLogfile();
389  char txtbuf[fguMESLEN];
390  if(!name)
391  // default: encode pid into filename
392  snprintf(txtbuf,fguMESLEN,"go4log-%d.txt", gSystem->GetPid());
393  else
394  snprintf(txtbuf,fguMESLEN,"%s",name);
395 
396  std::ofstream* lf = new std::ofstream(txtbuf, appendmode ? std::ios::app : std::ios::out);
397 
398  if(lf->fail()) {
399  LogfileEnable(kFALSE);
400  delete lf;
401  std::cerr <<"TGo4Log::OpenLogfile() - Error opening logfile "<< name << std::endl;
402  } else {
403  fgxLogfile = lf;
404  fgxLogName = txtbuf; // remember our last filename
405  }
406  // write headercomment into the first lines:
407  if(headercomment) WriteLogfile(headercomment, kFALSE);
408  } // try
409 
410  catch(std::exception& ex) // treat standard library exceptions
411  {
412  std::cerr <<"standard exception "<<ex.what()<<"in TGo4Log::OpenLogfile" << std::endl;
413  }
414  catch(...)
415  {
416  std::cerr <<"!!! Unexpected exception in TGo4Log::OpenLogfile !!!" << std::endl;
417  } // catch
418 }
419 
420 void TGo4Log::WriteLogfile(const char *text, Bool_t withtime)
421 {
422  //TGo4LockGuard(fxMutex);
423  if(!text || !fgbLogfileEnabled || !fgxLogfile) return;
424  try {
425  std::ofstream *lf = static_cast<std::ofstream*>(fgxLogfile);
426  if (lf->is_open()) {
427  if(withtime) {
428  TDatime now;
429  *lf << now.AsSQLString() << ": ";
430  }
431  *lf << text << std::endl;
432  }
433  }// try
434  catch(std::exception& ex) // treat standard library exceptions
435  {
436  std::cerr <<"standard exception "<<ex.what()<<"in TGo4Log::WriteLogfile" << std::endl;
437  }
438  catch(...)
439  {
440  std::cerr <<"!!! Unexpected exception in TGo4Log::WriteLogfile !!!" << std::endl;
441  } // catch
442 }
443 
445 {
446  //TGo4LockGuard(fxMutex);
447  if(fgxLogfile)
448  {
449  try
450  {
451  delete (std::ofstream*)fgxLogfile;
452  fgxLogfile = nullptr;
453  }
454  catch(std::exception& ex) // treat standard library exceptions
455  {
456  std::cerr <<"standard exception "<<ex.what()<<"in TGo4Log::CloseLogfile" << std::endl;
457  }
458  catch(...)
459  {
460  std::cerr <<"!!! Unexpected exception in TGo4Log::CloseLogfile !!!" << std::endl;
461  } //
462  }
463 }
static const char * GetLogname()
Definition: TGo4Log.cxx:343
static TGo4Log * Instance()
Definition: TGo4Log.cxx:85
static TGo4Log * fgxInstance
Definition: TGo4Log.h:188
static const char * fgcWARN
Definition: TGo4Log.h:163
static void Info(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:294
static void WriteLogfile(const char *text, Bool_t withtime=kTRUE)
Definition: TGo4Log.cxx:420
static void CloseLogfile()
Definition: TGo4Log.cxx:444
static Bool_t IsOutputEnabled()
Definition: TGo4Log.cxx:358
static Bool_t fgbLogfileEnabled
Definition: TGo4Log.h:200
static void OpenLogfile(const char *name=nullptr, const char *headercomment=nullptr, Bool_t appendmode=kFALSE)
Definition: TGo4Log.cxx:383
static const char * GetDefaultLogname()
Definition: TGo4Log.cxx:348
static Bool_t fgbAutoMode
Definition: TGo4Log.h:203
static void SetIgnoreLevel(Int_t level)
Definition: TGo4Log.cxx:332
static void OutputEnable(Bool_t on=kTRUE)
Definition: TGo4Log.cxx:353
static const char * fgcRIGHT
Definition: TGo4Log.h:154
static const char * fgcDEBUG
Definition: TGo4Log.h:157
static Bool_t fgbOutputEnabled
Definition: TGo4Log.h:197
static TString fgsGO4SYS
Definition: TGo4Log.h:214
static int fgStdSave
redirected pipe for stdout
Definition: TGo4Log.h:219
static void ProcessRedirection(int kind=0)
Definition: TGo4Log.cxx:118
virtual ~TGo4Log()
Definition: TGo4Log.cxx:80
static void SetSniffer(TNamed *sniff)
Definition: TGo4Log.cxx:151
static const char * Message(Int_t prio, const char *text,...) GO4_PRINTF2_ARGS
Definition: TGo4Log.cxx:206
static void Debug(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:281
TLogTimer(Int_t millisec)
Definition: TGo4Log.cxx:60
static const char * fgcINFO
Definition: TGo4Log.h:160
TGo4Log()
Definition: TGo4Log.cxx:68
static const char * GO4INCPATH()
Definition: TGo4Log.cxx:179
static void EnableRedirection()
Definition: TGo4Log.cxx:93
static int fgStdPipe[2]
optional object to get all output via SetTitle method
Definition: TGo4Log.h:218
static Bool_t IsLogfileEnabled()
Definition: TGo4Log.cxx:368
static const char * fgcDEFAULTLOG
Definition: TGo4Log.h:169
static Int_t fgiIgnoreLevel
Definition: TGo4Log.h:194
static void Error(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:320
static TString fgxLogName
Definition: TGo4Log.h:212
static void Printf(Bool_t _stdout, const char *text)
Definition: TGo4Log.cxx:254
static void PrintRate(ULong64_t cnt, double rate)
Definition: TGo4Log.cxx:270
static TMutex * fgxMutex
Definition: TGo4Log.h:191
static void * fgxLogfile
Definition: TGo4Log.h:209
static Int_t GetIgnoreLevel()
Definition: TGo4Log.cxx:338
static TNamed * fgSniffer
value of GO4SYS during run
Definition: TGo4Log.h:216
static TString subGO4SYS(const char *subdir)
Definition: TGo4Log.cxx:189
static char fgcMessagetext[__MESSAGETEXTLENGTH__]
Definition: TGo4Log.h:206
static const char * fgcLEFT
Definition: TGo4Log.h:151
static const char * GO4SYS()
Definition: TGo4Log.cxx:156
static TLogTimer * fgTimer
saved file for stdout
Definition: TGo4Log.h:221
static void AutoEnable(Bool_t on=kTRUE)
Definition: TGo4Log.cxx:373
Bool_t Notify() override
Definition: TGo4Log.cxx:62
#define __MESSAGETEXTLENGTH__
Definition: TGo4Log.h:22
static const char * fgcERR
Definition: TGo4Log.h:166
static void Warn(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:307
static Bool_t IsAutoEnabled()
Definition: TGo4Log.cxx:378
static void LogfileEnable(Bool_t on=kTRUE)
Definition: TGo4Log.cxx:363