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