/* $Id$ */
-///
-/// class for logging debug, info and error messages
-///
-
-#include <TObject.h>
+#include <TClass.h>
#include <TObjArray.h>
+#include <TObject.h>
#include <TString.h>
+// deprecation macro
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define ALIROOT_DEPRECATED(func) func __attribute__ ((deprecated))
+#elif defined(_MSC_VER) && _MSC_VER >= 1300
+#define ALIROOT_DEPRECATED(func) __declspec(deprecated) func
+# else
+#define ALIROOT_DEPRECATED(func) func
+#endif
-class AliLog: public TObject {
+/**
+ * class for logging debug, info and error messages
+ */
+class AliLog: public TObject
+{
public:
- AliLog();
- virtual ~AliLog();
- static AliLog* Instance() {return fgInstance;}
- enum EType {kFatal = 0, kError, kWarning, kInfo, kDebug, kMaxType};
+ // Log4j log levels: TRACE, DEBUG, INFO, WARN, ERROR, FATAL
+ enum EType_t {kFatal = 0, kError, kWarning, kInfo, kDebug, kMaxType};
+ typedef void (*AliLogNotification)(EType_t type, const char* message );
+
+ // NB: singleton constructor & destructor should not be public!
+ // ALIROOT_DEPRECATED(AliLog());
+ // ALIROOT_DEPRECATED(virtual ~AliLog());
+ // NB: singleton deprecated static instance method
+ // ALIROOT_DEPRECATED(static AliLog* Instance() {return fgInstance;};)
+
+ // get root logger singleton instance
+ static AliLog *GetRootLogger();
+
+ // delete root logger singleton instance
+ static void DeleteRootLogger();
+
+ // NB: the following functions should not be static
+ // NB: deprecated: logging configuration should be made through to a configuration file
static void EnableDebug(Bool_t enabled);
- static void SetGlobalLogLevel(EType type);
+ static void SetGlobalLogLevel(EType_t type);
static Int_t GetGlobalLogLevel();
static void SetGlobalDebugLevel(Int_t level);
static Int_t GetGlobalDebugLevel();
static void ClearClassDebugLevel(const char* className);
static void SetStandardOutput();
- static void SetStandardOutput(EType type);
+ static void SetStandardOutput(EType_t type);
static void SetErrorOutput();
- static void SetErrorOutput(EType type);
+ static void SetErrorOutput(EType_t type);
static void SetFileOutput(const char* fileName);
- static void SetFileOutput(EType type, const char* fileName);
+ static void SetFileOutput(EType_t type, const char* fileName);
+ static void SetStreamOutput(ostream* stream);
+ static void SetStreamOutput(EType_t type, ostream* stream);
+ static void SetLogNotification(AliLogNotification pCallBack);
+ static void SetLogNotification(EType_t type, AliLogNotification pCallBack);
static void Flush();
static void SetHandleRootMessages(Bool_t on);
static void SetPrintType(Bool_t on);
- static void SetPrintType(EType type, Bool_t on);
+ static void SetPrintType(EType_t type, Bool_t on);
static void SetPrintModule(Bool_t on);
- static void SetPrintModule(EType type, Bool_t on);
+ static void SetPrintModule(EType_t type, Bool_t on);
static void SetPrintScope(Bool_t on);
- static void SetPrintScope(EType type, Bool_t on);
+ static void SetPrintScope(EType_t type, Bool_t on);
static void SetPrintLocation(Bool_t on);
- static void SetPrintLocation(EType type, Bool_t on);
+ static void SetPrintLocation(EType_t type, Bool_t on);
- static void Write(const char* name, Int_t option = 0);
+ static void SetPrintRepetitions(Bool_t on);
+
+ static void WriteToFile(const char* name, Int_t option = 0);
// the following public methods are used by the preprocessor macros
// and should not be called directly
const char* module, const char* className,
const char* function, const char* file, Int_t line);
- static Int_t RedirectStdoutTo(EType type, UInt_t level, const char* module,
+ static Int_t 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);
- static Int_t RedirectStderrTo(EType type, UInt_t level, const char* module,
+ static Int_t 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);
static void RestoreStdout(Int_t original);
static void RestoreStderr(Int_t original);
- static ostream& Stream(EType type, UInt_t level,
+ static ostream& Stream(EType_t type, UInt_t level,
const char* module, const char* className,
const char* function, const char* file, Int_t line);
private:
+
+ // constructor is made private for implementing a singleton
+ AliLog();
+ virtual ~AliLog();
+
+ // NOT IMPLEMENTED?
AliLog(const AliLog& log);
AliLog& operator = (const AliLog& log);
const char* function,
const char* file, Int_t line);
- Int_t RedirectTo(FILE* stream, EType type, UInt_t level,
+ void PrintString(Int_t type, FILE* stream, const char* format, ...);
+ void PrintRepetitions();
+
+ Int_t 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);
- ostream& GetStream(EType type, UInt_t level,
+ ostream& GetStream(EType_t type, UInt_t level,
const char* module, const char* className,
const char* function, const char* file, Int_t line);
enum {kDebugOffset = kDebug-1};
static AliLog* fgInstance; //! pointer to current instance
-
static Bool_t fgDebugEnabled; // flag for debug en-/disabling
UInt_t fGlobalLogLevel; // global logging level
Int_t fOutputTypes[kMaxType]; // types of output streams
TString fFileNames[kMaxType]; // file names
FILE* fOutputFiles[kMaxType]; //! log output files
- ofstream* fOutputStreams[kMaxType]; //! log output streams
+ ostream* fOutputStreams[kMaxType]; //! log output streams
Bool_t fPrintType[kMaxType]; // print type on/off
Bool_t fPrintModule[kMaxType]; // print module on/off
Bool_t fPrintScope[kMaxType]; // print scope/class name on/off
Bool_t fPrintLocation[kMaxType]; // print file and line on/off
+ Bool_t fPrintRepetitions; // print number of repetitions instead of repeated message on/off
+
+ Int_t fRepetitions; //! counter of repetitions
+ UInt_t fLastType; //! type of last message
+ TString fLastMessage; //! last message
+ TString fLastModule; //! module name of last message
+ TString fLastClassName; //! class name of last message
+ TString fLastFunction; //! function name of last message
+ TString fLastFile; //! file name of last message
+ Int_t fLastLine; //! line number of last message
+ AliLogNotification fCallBacks[kMaxType]; //! external notification callback
+
ClassDef(AliLog, 1) // class for logging debug, info and error messages
};
-// module name
-#ifdef __MODULE__
-#define MODULENAME() __MODULE__
+// module name macro
+#ifdef _MODULE_
+#define MODULENAME() _MODULE_
#else
#define MODULENAME() "NoModule"
#endif
-// function name
+// function name macro
#if defined(__GNUC__) || defined(__ICC) || defined(__ECC) || defined(__APPLE__)
#define FUNCTIONNAME() __FUNCTION__
-#elif defined(__HP_aCC) || defined(__alpha) || defined(__DECCXX)
-#define FUNCTIONNAME() __FUNC__
+// #elif defined(__HP_aCC) || defined(__alpha) || defined(__DECCXX)
+// #define FUNCTIONNAME() __FUNC__
#else
#define FUNCTIONNAME() "???"
#endif
#define AliDebugClass(level, message)
#define AliDebugGeneral(scope, level, message)
#else
-#define AliDebug(level, message) {if (AliLog::IsDebugEnabled()) AliLog::Debug(level, message, MODULENAME(), ClassName(), FUNCTIONNAME(), __FILE__, __LINE__);}
-#define AliDebugClass(level, message) {if (AliLog::IsDebugEnabled()) AliLog::Debug(level, message, MODULENAME(), Class()->GetName(), FUNCTIONNAME(), __FILE__, __LINE__);}
-#define AliDebugGeneral(scope, level, message) {if (AliLog::IsDebugEnabled()) AliLog::Debug(level, message, MODULENAME(), scope, FUNCTIONNAME(), __FILE__, __LINE__);}
+
+// inspired by log4cxx code (see log4cxx/Logger.h)
+// implements GCC branch prediction for increasing logging performance
+#if !defined(ALIROOT_UNLIKELY)
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+/**
+Provides optimization hint to the compiler
+to optimize for the expression being false.
+@param expr boolean expression.
+@returns value of expression.
+*/
+#define ALIROOT_UNLIKELY(expr) __builtin_expect(expr, 0)
+#else
+/**
+Provides optimization hint to the compiler
+to optimize for the expression being false.
+@param expr boolean expression.
+@returns value of expression.
+**/
+#define ALIROOT_UNLIKELY(expr) expr
+#endif
+#endif
+
+/**
+Logs a message to a specified logger with the DEBUG level.
+
+@param logLevel the debug level.
+@param message message to print in the following format: Form(message).
+ Note, that message should contain balanced parenthesis, like
+ <code>AliDebug(1, Form("Failed to decode line %d of %s", line, filename));</code>
+*/
+#define AliDebug(logLevel, message) \
+ do { if (ALIROOT_UNLIKELY(AliLog::IsDebugEnabled() && AliLog::GetDebugLevel(MODULENAME(), ClassName()) >= logLevel)) {\
+ AliLog::Debug(logLevel, message, MODULENAME(), ClassName(), FUNCTIONNAME(), __FILE__, __LINE__); }} while (0)
+
+/**
+Logs a message to a specified logger with the DEBUG level.
+
+@param logLevel the debug level.
+@param message message to print in the following format: Form(message).
+ Note, that message should contain balanced parenthesis, like
+ <code>AliDebug(1, Form("Failed to decode line %d of %s", line, filename));</code>
+*/
+#define AliDebugClass(logLevel, message) \
+ do { if (ALIROOT_UNLIKELY(AliLog::IsDebugEnabled() && AliLog::GetDebugLevel(MODULENAME(), Class()->GetName()) >= logLevel)) {\
+ AliLog::Debug(logLevel, message, MODULENAME(), Class()->GetName(), FUNCTIONNAME(), __FILE__, __LINE__); }} while (0)
+
+/**
+Logs a message to a specified logger with the DEBUG level.
+
+@param scope the logging scope.
+@param logLevel the debug level.
+@param message message to print in the following format: Form(message).
+ Note, that message should contain balanced parenthesis, like
+ <code>AliDebug(1, Form("Failed to decode line %d of %s", line, filename));</code>
+*/
+#define AliDebugGeneral(scope, logLevel, message) \
+ do { if (ALIROOT_UNLIKELY(AliLog::IsDebugEnabled() && AliLog::GetDebugLevel(MODULENAME(), scope) >= logLevel)) {\
+ AliLog::Debug(logLevel, message, MODULENAME(), scope, FUNCTIONNAME(), __FILE__, __LINE__); }} while (0)
+
#endif
// redirection to debug
#define AliInfoClassStream() AliLog::Stream(AliLog::kInfo, 0, MODULENAME(), Class()->GetName(), FUNCTIONNAME(), __FILE__, __LINE__)
#define AliInfoGeneralStream(scope) AliLog::Stream(AliLog::kInfo, 0, MODULENAME(), scope, FUNCTIONNAME(), __FILE__, __LINE__)
-
// warning messages
#ifdef LOG_NO_WARNING
#define AliWarning(message)