/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #ifndef nslog_h__ #define nslog_h__ /** * LOGGING SERVICE * * We all know and love PR_LOG, but let's face it, it has some deficiencies: * - can't direct output for different logs to different places, * - isn't scriptable, * - can't control printing format, including indentation, * - it's ugly. * We've solved these problems with xpcom logging facility, nslog, the new modern * equivalent. Here's how you use it: * * #include "nslog.h" * * // First declare a new log: * NS_IMPL_LOG(Foo) * * // Then define PRINTF and FLUSH routines for your log module: * #define PRINTF NS_LOG_PRINT(Foo) * #define FLUSH NS_LOG_FLUSH(Foo) * * void main() { * // Then use it like this: * PRINTF("hello world %d", 42); * * FLUSH(); // not necessary, but might be useful for synchronization * } * * The above log statement will print something like this: * * a33e50 Foo hello world 42 * * The hex number at the beginning of the line indicates the ID of the thread * executing the PRINTF statement. The name of the log appears next. * * A cool feature of how these macros work is that when NS_DISABLE_LOGGING is * defined, all the logging code macro-expands to nothing. * * You can also cause it to indent its output to help you log recursive execution: * * int fact(int n) { * NS_LOG_WITH_INDENT(Foo, "fact"); * PRINTF("calling fact of %d\n", n); * if (n == 0) return 1; * int result = n * fact(n - 1); * PRINTF("fact of %d is %d\n", n, result); * return result; * } * * Calling fact(3) will produce a log that looks like this: * * 8e28b0 Foo [ Begin fact * 8e28b0 Foo | calling fact of 3 * 8e28b0 Foo | [ Begin fact * 8e28b0 Foo | | calling fact of 2 * 8e28b0 Foo | | [ Begin fact * 8e28b0 Foo | | | calling fact of 1 * 8e28b0 Foo | | | [ Begin fact * 8e28b0 Foo | | | | calling fact of 0 * 8e28b0 Foo | | | ] End fact * 8e28b0 Foo | | | fact of 1 is 1 * 8e28b0 Foo | | ] End fact * 8e28b0 Foo | | fact of 2 is 2 * 8e28b0 Foo | ] End fact * 8e28b0 Foo | fact of 3 is 6 * 8e28b0 Foo ] End fact * * If the second argument to NS_LOG_WITH_INDENT is nsnull, you don't get the * Begin/End statements: * * 8e28b0 Foo | calling fact of 3 * 8e28b0 Foo | | calling fact of 2 * 8e28b0 Foo | | | calling fact of 1 * 8e28b0 Foo | | | | calling fact of 0 * 8e28b0 Foo | | | fact of 1 is 1 * 8e28b0 Foo | | fact of 2 is 2 * 8e28b0 Foo | fact of 3 is 6 * * You can control where the output of the log goes by setting its * log event sink to an appropriate nsILogEventSink. By default the * file log event sink does the following: * - outputs to stderr * - outputs to the platform's debug output for errors * New log event sinks can be instantiated via the component manager: * * #ifdef NS_ENABLE_LOGGING * nsComponentManager::CreateInstance(kFileLogEventSinkCID, * nsnull, * NS_GET_IID(nsIFileLogEventSink), * &logEventSink); * logEventSink->InitFromFILE("stdout", stdout); * Foo->SetLogEventSink(logEventSink); * #endif * * or the application can implement its own nsILogEventSink. */ #include "prlog.h" // include prlog.h because we're going to override it's ancient macros #include "nsDebug.h" #include "nsILoggingService.h" #include "nsCOMPtr.h" #if (defined(DEBUG) || defined(NS_DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) // enable logging by default #define NS_ENABLE_LOGGING #endif #ifdef NS_DISABLE_LOGGING // override, if you want DEBUG, but *not* logging (for some reason) #undef NS_ENABLE_LOGGING #endif #ifdef NS_ENABLE_LOGGING //////////////////////////////////////////////////////////////////////////////// PR_EXTERN(nsILog*) NS_GetLog(const char* name, PRUint32 controlFlags = 0); //////////////////////////////////////////////////////////////////////////////// /** * nsLogIndent: This class allows indentation to occur in a block scope. The * automatic destructor takes care of resetting the indentation. Use the * NS_LOG_WITH_INDENT macro. */ class NS_COM nsLogIndent { public: nsLogIndent(nsILog* log, const char* msg); ~nsLogIndent(); protected: nsILog* mLog; const char* mHeaderMsg; }; //////////////////////////////////////////////////////////////////////////////// // macros #define NS_DECL_LOG(_log) \ extern nsILog* _log; #define NS_IMPL_LOG(_log) \ nsILog* _log = NS_GetLog(#_log); #define NS_IMPL_LOG_ENABLED(_log) \ nsILog* _log = NS_GetLog(#_log, nsILog::DEFAULT_ENABLED); #define NS_LOG_ENABLED(_log) \ ((_log) && (_log)->Test()) #define NS_LOG_PRINTF(_log) \ (!NS_LOG_ENABLED(_log)) ? NS_OK : (_log)->Printf #define NS_LOG_FLUSH(_log) (_log)->Flush #define NS_LOG_WITH_INDENT(_log, _msg) nsLogIndent _indent_##_log(_log, _msg) #define NS_LOG_BEGIN_INDENT(_log) ((_log)->IncreaseIndent()) #define NS_LOG_END_INDENT(_log) ((_log)->DecreaseIndent()) #else // !NS_ENABLE_LOGGING inline void nsNoop(...) {} #define NS_DECL_LOG(_log) /* nothing */ #define NS_IMPL_LOG(_log) /* nothing */ #define NS_IMPL_LOG_ENABLED(_log) /* nothing */ #define NS_LOG_ENABLED(_log) 0 #define NS_LOG_PRINTF(_log) nsNoop #define NS_LOG_FLUSH(_log) nsNoop #define NS_LOG_WITH_INDENT(_log, _msg) ((void)0) #define NS_LOG_BEGIN_INDENT(_log) ((void)0) #define NS_LOG_END_INDENT(_log) ((void)0) #endif // !NS_ENABLE_LOGGING // Redefine NSPR's logging system: #undef PR_LOG_TEST #define PR_LOG_TEST(_log, _level) NS_LOG_ENABLED(_log) #undef PR_LOG #define PR_LOG(_log, _level, _args) NS_LOG_PRINTF(_log) _args #define PRLogModuleInfo #error use_NS_DECL_LOG_instead #define PR_NewLogModule #error use_NS_IMPL_LOG_instead #undef PR_ASSERT #define PR_ASSERT(x) NS_ASSERTION(x, #x) #define printf use_NS_LOG_PRINTF_instead #define fprintf use_NS_LOG_PRINTF_instead //////////////////////////////////////////////////////////////////////////////// #endif // nslog_h__