#include <TNamed.h>
#include <TSystem.h>
#include <TEnv.h>
+#include <TArrayC.h>
+#include <Varargs.h> // platform independent definition of va_copy
#include "AliLog.h"
TObject(),
fGlobalLogLevel(kInfo),
fModuleDebugLevels(),
- fClassDebugLevels()
+ fClassDebugLevels(),
+ fPrintRepetitions(kTRUE),
+ fRepetitions(0),
+ fLastType(0),
+ fLastMessage(),
+ fLastModule(),
+ fLastClassName(),
+ fLastFunction(),
+ fLastFile(),
+ fLastLine(0)
{
// default constructor: set default values
fFileNames[iType] = "";
fOutputFiles[iType] = NULL;
fOutputStreams[iType] = NULL;
+ fCallBacks[iType]=NULL;
fPrintType[iType] = kTRUE;
fPrintModule[iType] = kFALSE;
fPrintLocation[iType] = (iType == kDebug);
}
- SetHandleRootMessages(kTRUE);
-
// replace the previous instance by this one
if (fgInstance) delete fgInstance;
fgInstance = this;
+ SetHandleRootMessages(kTRUE);
+
// read the .rootrc settings
ReadEnvSettings();
}
{
// destructor: clean up and reset instance pointer
+ if (fRepetitions > 0) PrintRepetitions();
+
for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++) {
if (fModuleDebugLevels[i]) fModuleDebugLevels[i]->Delete();
}
//_____________________________________________________________________________
AliLog::AliLog(const AliLog& log) :
- TObject(log)
+ TObject(log),
+ fGlobalLogLevel(log.fGlobalLogLevel),
+ fModuleDebugLevels(log.fModuleDebugLevels),
+ fClassDebugLevels(log.fClassDebugLevels),
+ fPrintRepetitions(log.fPrintRepetitions),
+ fRepetitions(log.fRepetitions),
+ fLastType(log.fLastType),
+ fLastMessage(log.fLastMessage),
+ fLastModule(log.fLastModule),
+ fLastClassName(log.fLastClassName),
+ fLastFunction(log.fLastFunction),
+ fLastFile(log.fLastFile),
+ fLastLine(log.fLastLine)
{
// copy constructor
if (gEnv->Defined(name)) {
TString stream = gEnv->GetValue(name, "Standard");
if (stream.CompareTo("standard", TString::kIgnoreCase) == 0) {
- SetStandardOutput(EType(iType));
+ SetStandardOutput(EType_t(iType));
AliDebug(3, Form("output stream set to standard output for type %s",
typeNames[iType]));
} else if (stream.CompareTo("error", TString::kIgnoreCase) == 0) {
- SetErrorOutput(EType(iType));
+ SetErrorOutput(EType_t(iType));
AliDebug(3, Form("output stream set to error output for type %s",
typeNames[iType]));
} else if (!stream.IsNull()) {
- SetFileOutput(EType(iType), stream);
+ SetFileOutput(EType_t(iType), stream);
AliDebug(3, Form("output stream set to file %s for type %s",
stream.Data(), typeNames[iType]));
}
}
}
}
+
+ // repetition of messages
+ if (gEnv->Defined("AliRoot.AliLog.PrintRepetitions")) {
+ Bool_t on = gEnv->GetValue("AliRoot.AliLog.PrintRepetitions", kTRUE);
+ fPrintRepetitions = on;
+ AliDebug(3, Form("printing of message repetitions %sabled",
+ ((on) ? "en" : "dis")));
+ }
}
}
//_____________________________________________________________________________
-void AliLog::SetGlobalLogLevel(EType type)
+void AliLog::SetGlobalLogLevel(EType_t type)
{
// set the global debug level
}
//_____________________________________________________________________________
-void AliLog::SetStandardOutput(EType type)
+void AliLog::SetStandardOutput(EType_t type)
{
// write log messages of the given type to the standard output (stdout)
}
//_____________________________________________________________________________
-void AliLog::SetErrorOutput(EType type)
+void AliLog::SetErrorOutput(EType_t type)
{
// write log messages of the given type to the error output (stderr)
}
//_____________________________________________________________________________
-void AliLog::SetFileOutput(EType type, const char* fileName)
+void AliLog::SetFileOutput(EType_t type, const char* fileName)
{
// write log messages of the given type to the given file
}
if (closeFile) {
fclose(fOutputFiles[type]);
- fOutputStreams[type]->close();
+ ofstream* stream=reinterpret_cast<ofstream*>(fOutputStreams[type]);
+ stream->close();
delete fOutputStreams[type];
}
}
else if (fOutputTypes[type] == 2) {
if (!fOutputFiles[type]) {
FILE* file = NULL;
- ofstream* stream = NULL;
+ ostream* stream = NULL;
if (!fFileNames[type].IsNull()) {
for (Int_t iType = kFatal; iType < kMaxType; iType++) {
if ((iType != type) &&
{
// enable or disable the handling of messages form root
+ if (!fgInstance) new AliLog;
if (on) {
SetErrorHandler(RootErrorHandler);
} else {
}
//_____________________________________________________________________________
-void AliLog::SetPrintType(EType type, Bool_t on)
+void AliLog::SetPrintType(EType_t type, Bool_t on)
{
// switch on or off the printing of the message type for the given message type
}
//_____________________________________________________________________________
-void AliLog::SetPrintModule(EType type, Bool_t on)
+void AliLog::SetPrintModule(EType_t type, Bool_t on)
{
// switch on or off the printing of the module for the given message type
}
//_____________________________________________________________________________
-void AliLog::SetPrintScope(EType type, Bool_t on)
+void AliLog::SetPrintScope(EType_t type, Bool_t on)
{
// switch on or off the printing of the scope/class name
// for the given message type
}
//_____________________________________________________________________________
-void AliLog::SetPrintLocation(EType type, Bool_t on)
+void AliLog::SetPrintLocation(EType_t type, Bool_t on)
{
// switch on or off the printing of the file name and line number
// for the given message type
//_____________________________________________________________________________
-void AliLog::Write(const char* name, Int_t option)
+void AliLog::SetPrintRepetitions(Bool_t on)
+{
+// switch on or off the printing of the number of repetitions of a message
+// instead of repeating the same message
+
+ if (!fgInstance) new AliLog;
+ if (!on && (fgInstance->fRepetitions > 0)) fgInstance->PrintRepetitions();
+ fgInstance->fPrintRepetitions = on;
+}
+
+
+//_____________________________________________________________________________
+void AliLog::WriteToFile(const char* name, Int_t option)
{
// write the log object with the given name and option to the current file
// get the logging level for the given module and class
if (!fgInstance) new AliLog;
- TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
- if (obj) return obj->GetUniqueID();
- obj = fgInstance->fModuleDebugLevels.FindObject(module);
- if (obj) return obj->GetUniqueID();
+ if (className) {
+ TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
+ if (obj) return obj->GetUniqueID();
+ }
+ if (module) {
+ TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
+ if (obj) return obj->GetUniqueID();
+ }
return fgInstance->fGlobalLogLevel;
}
{
// print the given message
+ // don't print the message if it is repeated
+ if (fPrintRepetitions &&
+ (fLastType == type) &&
+ (message && (fLastMessage.CompareTo(message) == 0)) &&
+ ((module && (fLastModule.CompareTo(module) == 0)) ||
+ (!module && fLastModule.IsNull())) &&
+ ((className && (fLastClassName.CompareTo(className) == 0)) ||
+ (!className && fLastClassName.IsNull())) &&
+ ((function && (fLastFunction.CompareTo(function) == 0)) ||
+ (!function && fLastFunction.IsNull()))&&
+ ((file && (fLastFile.CompareTo(file) == 0)) ||
+ (!file && fLastFile.IsNull())) &&
+ (fLastLine == line)) {
+ fRepetitions++;
+ return;
+ }
+
+ // print number of repetitions
+ if (fRepetitions > 0) PrintRepetitions();
+
+ // remember this message
+ fRepetitions = 0;
+ fLastType = type;
+ fLastMessage = message;
+ fLastModule = module;
+ fLastClassName = className;
+ fLastFunction = function;
+ fLastFile = file;
+ fLastLine = line;
+
+ // print the message
FILE* stream = GetOutputStream(type);
static const char* typeNames[kMaxType] =
{"Fatal", "Error", "Warning", "Info", "Debug"};
if (fPrintType[type]) {
- fprintf(stream, "%s in ", typeNames[type]);
+ PrintString(type, stream, "%c-", typeNames[type][0]);
}
- fprintf(stream, "<");
if (fPrintModule[type] && module) {
- fprintf(stream, "%s/", module);
+ PrintString(type, stream, "%s/", module);
}
if (fPrintScope[type] && className) {
- fprintf(stream, "%s::", className);
+ PrintString(type, stream, "%s::", className);
}
if (message) {
- fprintf(stream, "%s>: %s", function, message);
+ PrintString(type, stream, "%s: %s", function, message);
} else {
- fprintf(stream, "%s>", function);
+ PrintString(type, stream, "%s", function);
}
if (fPrintLocation[type] && file) {
- fprintf(stream, " (%s:%.0d)", file, line);
+ PrintString(type, stream, " (%s:%.0d)", file, line);
}
if (message) {
- fprintf(stream, "\n");
+ PrintString(type, stream, "\n");
} else {
- fprintf(stream, ": ");
+ PrintString(type, stream, ": ");
}
+ if (fCallBacks[type]) (*(fCallBacks[type]))((EType_t)type, NULL);
+}
+
+//_____________________________________________________________________________
+void AliLog::PrintRepetitions()
+{
+// print number of repetitions
+
+ PrintString(fLastType, GetOutputStream(fLastType), " <message repeated %d time%s>\n",
+ fRepetitions, (fRepetitions > 1) ? "s" : "");
+ if (fCallBacks[fLastType]) (*(fCallBacks[fLastType]))((EType_t)fLastType, NULL);
}
//_____________________________________________________________________________
//_____________________________________________________________________________
-Int_t AliLog::RedirectStdoutTo(EType type, UInt_t level, const char* module,
+Int_t AliLog::RedirectStdoutTo(EType_t type, UInt_t level, const char* module,
const char* className, const char* function,
const char* file, Int_t line, Bool_t print)
{
}
//_____________________________________________________________________________
-Int_t AliLog::RedirectStderrTo(EType type, UInt_t level, const char* module,
+Int_t AliLog::RedirectStderrTo(EType_t type, UInt_t level, const char* module,
const char* className, const char* function,
const char* file, Int_t line, Bool_t print)
{
}
//_____________________________________________________________________________
-Int_t AliLog::RedirectTo(FILE* stream, EType type, UInt_t level,
+Int_t AliLog::RedirectTo(FILE* stream, EType_t type, UInt_t level,
const char* module, const char* className,
const char* function, const char* file, Int_t line,
Bool_t print)
if (stream != stderr) dup2(fileno(stderr), fileno(stream));
} else if (fOutputTypes[type] == 2) { // file
freopen(fFileNames[type], "a", stream);
+ } else if (fOutputTypes[type] == 3) { // external C++ stream
+ // redirection is not possible for external C++ streams
}
// print information
fflush(stdout);
dup2(original, fileno(stdout));
+ close(original);
}
//_____________________________________________________________________________
fflush(stderr);
dup2(original, fileno(stderr));
+ close(original);
}
//_____________________________________________________________________________
-ostream& AliLog::Stream(EType type, UInt_t level,
+ostream& AliLog::Stream(EType_t type, UInt_t level,
const char* module, const char* className,
const char* function, const char* file, Int_t line)
{
}
//_____________________________________________________________________________
-ostream& AliLog::GetStream(EType type, UInt_t level,
+ostream& AliLog::GetStream(EType_t type, UInt_t level,
const char* module, const char* className,
const char* function, const char* file, Int_t line)
{
return cerr;
} else if (fOutputTypes[type] == 2) {
return *fOutputStreams[type];
+ } else if (fOutputTypes[type] == 3) {
+ return *fOutputStreams[type];
}
return nullStream;
}
+void AliLog::SetStreamOutput(ostream* stream)
+{
+ // set an external stream as target for log messages of all types
+ // the external stream is completely handled by the caller, the
+ // AliLog class just writes to it
+
+ for (Int_t iType = kFatal; iType < kMaxType; iType++) {
+ SetStreamOutput((AliLog::EType_t)iType, stream);
+ }
+}
+
+void AliLog::SetStreamOutput(EType_t type, ostream* stream)
+{
+ // set an external stream as target for log messages of the given type
+ // the external stream is completely handled by the caller, the
+ // AliLog class just writes to it
+
+ if ((type < kFatal) || (type >= kMaxType)) return;
+ if (!fgInstance) new AliLog;
+ if (fgInstance->fOutputTypes[type] == 2) {
+ fgInstance->CloseFile(type);
+ }
+ fgInstance->fOutputTypes[type] = 3;
+ fgInstance->fFileNames[type] = "";
+ fgInstance->fOutputFiles[type] = NULL;
+ fgInstance->fOutputStreams[type] = stream;
+}
+
+void AliLog::SetLogNotification(AliLogNotification pCallBack)
+{
+ // set a notification callback function for log messages of all types
+
+ for (Int_t iType = kFatal; iType < kMaxType; iType++) {
+ SetLogNotification((AliLog::EType_t)iType, pCallBack);
+ }
+}
+
+void AliLog::SetLogNotification(EType_t type, AliLogNotification pCallBack)
+{
+ // set a notifications call back function for log messages of all types
+ // the callback fuction is invoced whenever an output was written
+ // Note: does not work for c++ streamer classes, the external stream
+ // has to handle this diectly (e.g. custom implementation of endl)
+
+ if ((type < kFatal) || (type >= kMaxType)) return;
+ if (!fgInstance) new AliLog;
+ fgInstance->fCallBacks[type]=pCallBack;
+}
+
+void AliLog::PrintString(Int_t type, FILE* stream, const char* format, ...)
+{
+ // this is the general method to print a log message using variadac args
+ // to the FILE* like (C - like) streams, e.g. stdout, stderr, or files
+ // opened by fopen.
+ // Only in case of an external c++ ostream type output, the message is
+ // written to that stream and the notifictaion callback is called.
+ // The message is printed by a normal vfprintf function otherwise
+
+ if (format==NULL) return;
+
+ va_list ap;
+ va_start(ap, format);
+ if (fOutputTypes[type] != 3) {
+ if (stream!=NULL) {
+ vfprintf(stream, format, ap);
+ }
+ } else {
+ // build the string and write everthing to the corresponding ostream
+ TString fmt(format);
+ TArrayC tgt(fmt.Length()*10); // just take a number
+#ifdef R__VA_COPY
+ va_list bap;
+ R__VA_COPY(bap, ap);
+#else
+#warning definition of R__VA_COPY has disappeared
+#endif //R__VA_COPY
+
+ Int_t iResult=0;
+ while (1) {
+ iResult=vsnprintf(tgt.GetArray(), tgt.GetSize(), format, ap);
+ if (iResult==-1) {
+ iResult=tgt.GetSize()*2;
+ } else if (iResult<tgt.GetSize()) {
+ break;
+ }
+#ifdef R__VA_COPY
+ if (iResult<10000) {
+ tgt.Set(iResult+1);
+ va_end(ap);
+ R__VA_COPY(ap, bap);
+ } else
+#endif //R__VA_COPY
+ {
+ tgt[tgt.GetSize()-1]=0;
+ break;
+ }
+ }
+#ifdef R__VA_COPY
+ va_end(bap);
+#endif //R__VA_COPY
+
+ if (fOutputStreams[type]) {
+ *(fOutputStreams[type]) << tgt.GetArray();
+ }
+ }
+ va_end(ap);
+}