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