]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - STEER/AliLog.cxx
OADB classes and root files for the physics selection
[u/mrichter/AliRoot.git] / STEER / AliLog.cxx
index 40b64969e71bc228d7958585c1bf2589d889accb..5258eb8d0428302ad60842e9408dc455978b0a18 100644 (file)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#include <cstdlib>
+#include <strings.h>
+#include <Riostream.h>
 #include <TError.h>
 #include <TNamed.h>
 #include <TSystem.h>
+#include <TEnv.h>
+#include <TArrayC.h>
+#include <Varargs.h> // platform independent definition of va_copy
 
 #include "AliLog.h"
 
 ClassImp(AliLog)
 
-
+// implementation of a singleton here
 AliLog* AliLog::fgInstance = NULL;
 
 Bool_t AliLog::fgDebugEnabled = kTRUE;
 
+/**
+ * get root logger singleton instance
+ */
+AliLog *AliLog::GetRootLogger()
+{
+       if (fgInstance == NULL)
+       {
+               // creating singleton
+               fgInstance =  new AliLog;
+       }
 
-//_____________________________________________________________________________
+       return fgInstance;
+}
+
+/**
+ * delete the root logger singleton instance
+ */
+void AliLog::DeleteRootLogger()
+{
+       if (fgInstance != NULL)
+       {
+               delete fgInstance;
+               fgInstance = NULL;
+       }
+}
+
+/**
+ * default private constructor
+ */
 AliLog::AliLog() :
   TObject(),
   fGlobalLogLevel(kInfo),
   fModuleDebugLevels(),
-  fClassDebugLevels()
+  fClassDebugLevels(),
+  fPrintRepetitions(kTRUE),
+  fRepetitions(0),
+  fLastType(0),
+  fLastMessage(),
+  fLastModule(),
+  fLastClassName(),
+  fLastFunction(),
+  fLastFile(),
+  fLastLine(0)
 {
 // default constructor: set default values
 
-  for (Int_t iType = kFatal; iType < kMaxType; iType++) {
+  for (Int_t iType = kFatal; iType < kMaxType; iType++)
+  {
     fOutputTypes[iType] = 0;
     fFileNames[iType] = "";
     fOutputFiles[iType] = NULL;
+    fOutputStreams[iType] = NULL;
+    fCallBacks[iType]=NULL;
 
     fPrintType[iType] = kTRUE;
     fPrintModule[iType] = kFALSE;
@@ -65,45 +110,74 @@ AliLog::AliLog() :
     fPrintLocation[iType] = (iType == kDebug);  
   }
 
-  SetHandleRootMessages(kTRUE);
-
+  // TO BE REVIEWED
   // replace the previous instance by this one
   if (fgInstance) delete fgInstance;
   fgInstance = this;
+
+  SetHandleRootMessages(kTRUE);
+
+  // read the .rootrc settings
+  ReadEnvSettings();
 }
 
-//_____________________________________________________________________________
+/**
+ * private destructor
+ */
 AliLog::~AliLog()
 {
 // destructor: clean up and reset instance pointer
 
-  for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++) {
+  if (fRepetitions > 0) PrintRepetitions();
+
+  for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++)
+  {
     if (fModuleDebugLevels[i]) fModuleDebugLevels[i]->Delete();
   }
+
   fClassDebugLevels.Delete();
-  for (Int_t i = 0; i < fClassDebugLevels.GetEntriesFast(); i++) {
+
+  for (Int_t i = 0; i < fClassDebugLevels.GetEntriesFast(); i++)
+  {
     if (fClassDebugLevels[i]) fClassDebugLevels[i]->Delete();
   }
+
   fClassDebugLevels.Delete();
 
-  for (Int_t iType = kFatal; iType < kMaxType; iType++) {
+  for (Int_t iType = kFatal; iType < kMaxType; iType++)
+  {
     CloseFile(iType);
   }
+
   fflush(stderr);
   fflush(stdout);
 
   fgInstance = NULL;
 }
 
+// NOT IMPLEMENTED!?
 //_____________________________________________________________________________
 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
 
   Fatal("AliLog", "copy constructor not implemented");
 }
 
+// NOT IMPLEMENTED!?
 //_____________________________________________________________________________
 AliLog& AliLog::operator = (const AliLog& /*log*/)
 {
@@ -114,13 +188,200 @@ AliLog& AliLog::operator = (const AliLog& /*log*/)
 }
 
 
+/**
+ * gSystem see TSystem.h
+ * gEnv see TEnv.h
+ *
+ * LOG_NO_DEBUG: fgDebugEnabled <- false
+ * AliRoot.AliLog.EnableDebug
+ * AliRoot.AliLog.GlobalLogLevel
+ */
+//_____________________________________________________________________________
+void AliLog::ReadEnvSettings()
+{
+// load settings from the root configuration file (.rootrc)
+// and from environment variables
+
+  static const char* typeNames[kMaxType] = {"kFatal", "kError", "kWarning", "kInfo", "kDebug"};
+
+  // debug en- or disabling
+  if (gSystem->Getenv("LOG_NO_DEBUG"))
+  {
+    fgDebugEnabled = kFALSE;
+  }
+  else if (gEnv->Defined("AliRoot.AliLog.EnableDebug"))
+  {
+    fgDebugEnabled = gEnv->GetValue("AliRoot.AliLog.EnableDebug", fgDebugEnabled);
+    AliInfo(Form("debug %sabled", ((fgDebugEnabled) ? "en" : "dis")));
+  }
+
+  // global log level
+  if (gEnv->Defined("AliRoot.AliLog.GlobalLogLevel"))
+  {
+    const char* type = gEnv->GetValue("AliRoot.AliLog.GlobalLogLevel", "");
+
+    for (Int_t iType = kFatal; iType < kMaxType; iType++)
+    {
+      if (strcmp(type, typeNames[iType]) == 0) fGlobalLogLevel = iType;
+    }
+
+    AliDebug(3, Form("global log level set to %d", fGlobalLogLevel));
+  }
+
+  // global debug level
+  if (gEnv->Defined("AliRoot.AliLog.GlobalDebugLevel"))
+  {
+    Int_t level = gEnv->GetValue("AliRoot.AliLog.GlobalDebugLevel", Int_t(fGlobalLogLevel - kDebugOffset));
+    if (level < -kDebugOffset) level = kDebugOffset;
+    fGlobalLogLevel = kDebugOffset + level;
+    AliDebug(3, Form("global debug level set to %d", fGlobalLogLevel - kDebugOffset));
+  }
+
+  // module debug level
+  if (gEnv->Defined("AliRoot.AliLog.ModuleDebugLevel"))
+  {
+    TString levels = gEnv->GetValue("AliRoot.AliLog.ModuleDebugLevel", "");
+    char* p = const_cast<char*>(levels.Data());
+
+    while (const char* module = strtok(p, " "))
+    {
+      p = NULL;
+      char* pos = const_cast<char*>(index(module, ':'));
+      if (!pos) continue;
+      *(pos++) = '\0';
+      Int_t level = atoi(pos);
+      SetModuleDebugLevel(module, level);
+      AliDebug(3, Form("debug level for module %s set to %d", module, level));
+    }
+  }
+
+  // class debug level
+  if (gEnv->Defined("AliRoot.AliLog.ClassDebugLevel"))
+  {
+    TString levels = gEnv->GetValue("AliRoot.AliLog.ClassDebugLevel", "");
+    char* p = const_cast<char*>(levels.Data());
+
+    while (const char* className = strtok(p, " "))
+    {
+      p = NULL;
+      char* pos = const_cast<char*>(index(className, ':'));
+      if (!pos) continue;
+      *(pos++) = '\0';
+      Int_t level = atoi(pos);
+      SetClassDebugLevel(className, level);
+      AliDebug(3, Form("debug level for class %s set to %d", className, level));
+    }
+  }
+
+  // general output stream
+  if (gEnv->Defined("AliRoot.AliLog.Output"))
+  {
+    TString stream = gEnv->GetValue("AliRoot.AliLog.Output", "Standard");
+
+    if (stream.CompareTo("standard", TString::kIgnoreCase) == 0)
+    {
+      SetStandardOutput();
+      AliDebug(3, "output stream set to standard output for all types");
+    }
+    else if (stream.CompareTo("error", TString::kIgnoreCase) == 0)
+    {
+      SetErrorOutput();
+      AliDebug(3, "output stream set to error output for all types");
+    }
+    else if (!stream.IsNull())
+    {
+      SetFileOutput(stream);
+      AliDebug(3, Form("output stream set to file %s for all types", stream.Data()));
+    }
+  }
+
+  // individual output streams
+  for (Int_t iType = kFatal; iType < kMaxType; iType++)
+  {
+    TString name("AliRoot.AliLog.Output.");
+    name += &typeNames[iType][1];
+
+    if (gEnv->Defined(name))
+    {
+      TString stream = gEnv->GetValue(name, "Standard");
+
+      if (stream.CompareTo("standard", TString::kIgnoreCase) == 0)
+      {
+        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_t(iType));
+        AliDebug(3, Form("output stream set to error output for type %s", typeNames[iType]));
+      }
+      else if (!stream.IsNull())
+      {
+        SetFileOutput(EType_t(iType), stream);
+        AliDebug(3, Form("output stream set to file %s for type %s", stream.Data(), typeNames[iType]));
+      }
+    }
+  }
+
+  // handling of root error messages
+  if (gEnv->Defined("AliRoot.AliLog.HandleRootMessages"))
+  {
+    Bool_t on = gEnv->GetValue("AliRoot.AliLog.HandleRootMessages", kTRUE);
+    SetHandleRootMessages(on);
+    AliDebug(3, Form("handling of root messages %sabled", ((on) ? "en" : "dis")));
+  }
+
+  // printout settings
+  static const char* settingNames[4] = {"Type", "Module", "Scope", "Location"};
+  Bool_t* settings[] = {fPrintType, fPrintModule, fPrintScope, fPrintLocation};
+
+  for (Int_t iSetting = 0; iSetting < 4; iSetting++)
+  {
+    TString name("AliRoot.AliLog.Print");
+    name += settingNames[iSetting];
+
+    if (gEnv->Defined(name))
+    {
+      Bool_t on = gEnv->GetValue(name, settings[iSetting][0]);
+
+      for (Int_t iType = kFatal; iType < kMaxType; iType++)
+      {
+        settings[iSetting][iType] = on;
+      }
+      AliDebug(3, Form("printing of %s %sabled for all types", settingNames[iSetting], ((on) ? "en" : "dis")));
+    }
+
+    for (Int_t iType = kFatal; iType < kMaxType; iType++)
+    {
+      TString nameType = name + "." + &typeNames[iType][1];
+
+      if (gEnv->Defined(nameType))
+      {
+        Bool_t on = gEnv->GetValue(nameType, settings[iSetting][iType]);
+        settings[iSetting][iType] = on;
+        AliDebug(3, Form("printing of %s %sabled for type %s", settingNames[iSetting], ((on) ? "en" : "dis"), 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::RootErrorHandler(Int_t level, Bool_t abort, 
                              const char* location, const char* message)
 {
 // new error handler for messages from root
 
-  switch (level) {
+  switch (level)
+  {
   case ::kFatal    : level = kFatal; break;
   case ::kSysError :
     DefaultErrorHandler(level, abort, location, message);
@@ -137,6 +398,7 @@ void AliLog::RootErrorHandler(Int_t level, Bool_t abort,
 }
 
 
+// DEPRECATED: USE A CONFIGURATION FILE INSTEAD
 //_____________________________________________________________________________
 void AliLog::EnableDebug(Bool_t enabled)
 {
@@ -146,10 +408,11 @@ void AliLog::EnableDebug(Bool_t enabled)
 }
 
 //_____________________________________________________________________________
-void AliLog::SetGlobalLogLevel(EType type)
+void AliLog::SetGlobalLogLevel(EType_t type)
 {
 // set the global debug level
 
+  // TO BE DELETED
   if (!fgInstance) new AliLog; 
   fgInstance->fGlobalLogLevel = type;
 }
@@ -252,7 +515,7 @@ void AliLog::SetStandardOutput()
 }
 
 //_____________________________________________________________________________
-void AliLog::SetStandardOutput(EType type)
+void AliLog::SetStandardOutput(EType_t type)
 {
 // write log messages of the given type to the standard output (stdout)
 
@@ -275,7 +538,7 @@ void AliLog::SetErrorOutput()
 }
 
 //_____________________________________________________________________________
-void AliLog::SetErrorOutput(EType type)
+void AliLog::SetErrorOutput(EType_t type)
 {
 // write log messages of the given type to the error output (stderr)
 
@@ -299,11 +562,12 @@ void AliLog::SetFileOutput(const char* fileName)
     fgInstance->fOutputTypes[iType] = 2;
     fgInstance->fFileNames[iType] = fileName;
     fgInstance->fOutputFiles[iType] = NULL;
+    fgInstance->fOutputStreams[iType] = NULL;
   }
 }
 
 //_____________________________________________________________________________
-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
 
@@ -316,6 +580,7 @@ void AliLog::SetFileOutput(EType type, const char* fileName)
   fgInstance->fOutputTypes[type] = 2;
   fgInstance->fFileNames[type] = fileName;
   fgInstance->fOutputFiles[type] = NULL;
+  fgInstance->fOutputStreams[type] = NULL;
 }
 
 //_____________________________________________________________________________
@@ -330,9 +595,15 @@ void AliLog::CloseFile(Int_t type)
        closeFile = kFALSE;
       }
     }
-    if (closeFile) fclose(fOutputFiles[type]);
+    if (closeFile) {
+      fclose(fOutputFiles[type]);
+      ofstream* stream=reinterpret_cast<ofstream*>(fOutputStreams[type]);
+      stream->close();
+      delete fOutputStreams[type];
+    }
   }
   fOutputFiles[type] = NULL;
+  fOutputStreams[type] = NULL;
   fFileNames[type] = "";
   fOutputTypes[type] = 0;
 }
@@ -342,23 +613,30 @@ FILE* AliLog::GetOutputStream(Int_t type)
 {
 // get the output stream for the given type of messages
 
+  if (type > kDebug) type = kDebug;
   if (fOutputTypes[type] == 0) return stdout;
   else if (fOutputTypes[type] == 1) return stderr;
   else if (fOutputTypes[type] == 2) {
     if (!fOutputFiles[type]) {
       FILE* file = NULL;
+      ostream* stream = NULL;
       if (!fFileNames[type].IsNull()) {
        for (Int_t iType = kFatal; iType < kMaxType; iType++) {
          if ((iType != type) && 
              (fFileNames[iType].CompareTo(fFileNames[type]) == 0) &&
              fOutputFiles[iType]) {
            file = fOutputFiles[iType];
+           stream = fOutputStreams[iType];
            break;
          }
        }
-       if (!file) file = fopen(fFileNames[type], "a");
+       if (!file) {
+         file = fopen(fFileNames[type], "a");
+         stream = new ofstream(fFileNames[type], ios::app);
+       }
       }
       fOutputFiles[type] = file;
+      fOutputStreams[type] = stream;
       if (!file) CloseFile(type);
     }
     if (fOutputFiles[type]) return fOutputFiles[type];
@@ -376,6 +654,7 @@ void AliLog::Flush()
   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
     if (fgInstance->fOutputFiles[iType]) {
       fflush(fgInstance->fOutputFiles[iType]);
+      fgInstance->fOutputStreams[iType]->flush();
     }
   }
   fflush(stderr);
@@ -388,6 +667,7 @@ void AliLog::SetHandleRootMessages(Bool_t on)
 {
 // enable or disable the handling of messages form root
 
+  if (!fgInstance) new AliLog;
   if (on) {
     SetErrorHandler(RootErrorHandler);
   } else {
@@ -408,7 +688,7 @@ void AliLog::SetPrintType(Bool_t on)
 }
 
 //_____________________________________________________________________________
-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
 
@@ -429,7 +709,7 @@ void AliLog::SetPrintModule(Bool_t on)
 }
 
 //_____________________________________________________________________________
-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
 
@@ -450,7 +730,7 @@ void AliLog::SetPrintScope(Bool_t on)
 }
 
 //_____________________________________________________________________________
-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
@@ -473,7 +753,7 @@ void AliLog::SetPrintLocation(Bool_t on)
 }
 
 //_____________________________________________________________________________
-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
@@ -485,7 +765,19 @@ void AliLog::SetPrintLocation(EType type, Bool_t on)
 
 
 //_____________________________________________________________________________
-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
 
@@ -500,10 +792,14 @@ UInt_t AliLog::GetLogLevel(const char* module, const char* className) const
 // 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;
 }
 
@@ -516,6 +812,83 @@ Int_t AliLog::GetDebugLevel(const char* module, const char* className)
   return fgInstance->GetLogLevel(module, className) - kDebugOffset;
 }
 
+//_____________________________________________________________________________
+void AliLog::PrintMessage(UInt_t type, const char* message, 
+                          const char* module, const char* className,
+                          const char* function, const char* file, Int_t line)
+{
+// 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]) {
+    PrintString(type, stream, "%c-", typeNames[type][0]);
+  }
+  if (fPrintModule[type] && module) {
+    PrintString(type, stream, "%s/", module);
+  }
+  if (fPrintScope[type] && className) {
+    PrintString(type, stream, "%s::", className);
+  }
+  if (message) {
+    PrintString(type, stream, "%s: %s", function, message);
+  } else {
+    PrintString(type, stream, "%s", function);
+  }
+  if (fPrintLocation[type] && file) {
+    PrintString(type, stream, " (%s:%.0d)", file, line);
+  }
+  if (message) {
+    PrintString(type, stream, "\n");
+  } else {
+    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);
+}
+
 //_____________________________________________________________________________
 void AliLog::Message(UInt_t level, const char* message, 
                     const char* module, const char* className,
@@ -526,28 +899,13 @@ void AliLog::Message(UInt_t level, const char* message,
   if (!fgInstance) new AliLog;
 
   // get the message type
-  static const char* typeNames[kMaxType] = 
-    {"Fatal", "Error", "Warning", "Info", "Debug"};
   UInt_t type = level;
   if (type >= kMaxType) type = kMaxType - 1;
 
   // print the message if the debug level allows
   if (level <= fgInstance->GetLogLevel(module, className)) {
-    if (fgInstance->fPrintType[type]) {
-      fprintf(fgInstance->GetOutputStream(type), "%s in ", typeNames[type]);
-    }
-    fprintf(fgInstance->GetOutputStream(type), "<");
-    if (fgInstance->fPrintModule[type] && module) {
-      fprintf(fgInstance->GetOutputStream(type), "%s/", module);
-    }
-    if (fgInstance->fPrintScope[type] && className) {
-      fprintf(fgInstance->GetOutputStream(type), "%s::", className);
-    }
-    fprintf(fgInstance->GetOutputStream(type), "%s>: %s", function, message);
-    if (fgInstance->fPrintLocation[type] && file) {
-      fprintf(fgInstance->GetOutputStream(type), " (%s:%.0d)", file, line);
-    }
-    fprintf(fgInstance->GetOutputStream(type), "\n");
+    fgInstance->PrintMessage(type, message, 
+                             module, className, function, file, line);
   }
 
   // abort in case of a fatal message
@@ -573,3 +931,239 @@ void AliLog::Debug(UInt_t level, const char* message,
   level += kDebugOffset;
   Message(level, message, module, className, function, file, line);
 }
+
+
+//_____________________________________________________________________________
+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)
+{
+// redirect the standard output to the stream of the given type
+
+  if (!fgInstance) new AliLog;
+  return fgInstance->RedirectTo(stdout, type, level, module, className, 
+                                function, file, line, print);
+}
+
+//_____________________________________________________________________________
+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)
+{
+// redirect the standard error output to the stream of the given type
+
+  if (!fgInstance) new AliLog;
+  return fgInstance->RedirectTo(stderr, type, level, module, className, 
+                                function, file, line, print);
+}
+
+//_____________________________________________________________________________
+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)
+{
+// redirect the standard (error) output stream to the stream of the given type
+
+  // get the original file descriptor to be able to restore it later
+  Int_t original = dup(fileno(stream));
+  fflush(stream);
+
+  // flush the stream of the selected type
+  FILE* newStream = GetOutputStream(type);
+  fflush(newStream);
+
+  // redirect stream
+  if ((type == kDebug) && (level > 0)) level--;
+  if (type + level > GetLogLevel(module, className)) { // /dev/null
+    freopen("/dev/null", "a", stream);
+  } else if (fOutputTypes[type] == 0) {         // stdout
+    if (stream != stdout) dup2(fileno(stdout), fileno(stream));
+  } else if (fOutputTypes[type] == 1) {         // stderr
+    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
+  if (print) {
+    PrintMessage(type, NULL, module, className, function, file, line);
+    fflush(newStream);
+  }
+
+  return original;
+}
+
+//_____________________________________________________________________________
+void AliLog::RestoreStdout(Int_t original)
+{
+// restore the standard output
+
+  fflush(stdout);
+  dup2(original, fileno(stdout));  
+  close(original);
+}
+
+//_____________________________________________________________________________
+void AliLog::RestoreStderr(Int_t original)
+{
+// restore the standard error output
+
+  fflush(stderr);
+  dup2(original, fileno(stderr));  
+  close(original);
+}
+
+
+//_____________________________________________________________________________
+ostream& AliLog::Stream(EType_t type, UInt_t level,
+                        const char* module, const char* className,
+                        const char* function, const char* file, Int_t line)
+{
+// get the stream object for the given output type
+
+  if (!fgInstance) new AliLog;
+  return fgInstance->GetStream(type, level, module, className, 
+                               function, file, line);
+}
+
+//_____________________________________________________________________________
+ostream& AliLog::GetStream(EType_t type, UInt_t level,
+                           const char* module, const char* className,
+                           const char* function, const char* file, Int_t line)
+{
+// get the stream object for the given output type
+
+  if ((type == kDebug) && (level > 0)) level--;
+  Bool_t noOutput = (type + level > GetLogLevel(module, className));
+
+  if (!noOutput) {
+    PrintMessage(type, NULL, module, className, function, file, line);
+  }
+  fflush(GetOutputStream(type));
+
+  static ofstream nullStream("/dev/null");
+  if (noOutput) {
+    return nullStream;
+  } else if (fOutputTypes[type] == 0) {
+    return cout;
+  } else if (fOutputTypes[type] == 1) {
+    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);
+}