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