nuclear@3: /************************************************************************************ nuclear@3: nuclear@3: PublicHeader: OVR nuclear@3: Filename : OVR_Log.h nuclear@3: Content : Logging support nuclear@3: Created : September 19, 2012 nuclear@3: Notes : nuclear@3: nuclear@3: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@3: nuclear@3: Use of this software is subject to the terms of the Oculus license nuclear@3: agreement provided at the time of installation or download, or which nuclear@3: otherwise accompanies this software in either electronic or hard copy form. nuclear@3: nuclear@3: ************************************************************************************/ nuclear@3: nuclear@3: #ifndef OVR_Log_h nuclear@3: #define OVR_Log_h nuclear@3: nuclear@3: #include "OVR_Types.h" nuclear@3: #include nuclear@3: nuclear@3: namespace OVR { nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Logging Constants nuclear@3: nuclear@3: // LogMaskConstants defined bit mask constants that describe what log messages nuclear@3: // should be displayed. nuclear@3: enum LogMaskConstants nuclear@3: { nuclear@3: LogMask_Regular = 0x100, nuclear@3: LogMask_Debug = 0x200, nuclear@3: LogMask_None = 0, nuclear@3: LogMask_All = LogMask_Regular|LogMask_Debug nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: // LogMessageType describes the type of the log message, controls when it is nuclear@3: // displayed and what prefix/suffix is given to it. Messages are subdivided into nuclear@3: // regular and debug logging types. Debug logging is only generated in debug builds. nuclear@3: // nuclear@3: // Log_Text - General output text displayed without prefix or new-line. nuclear@3: // Used in OVR libraries for general log flow messages nuclear@3: // such as "Device Initialized". nuclear@3: // nuclear@3: // Log_Error - Error message output with "Error: %s\n", intended for nuclear@3: // application/sample-level use only, in cases where an expected nuclear@3: // operation failed. OVR libraries should not use this internally, nuclear@3: // reporting status codes instead. nuclear@3: // nuclear@3: // Log_DebugText - Message without prefix or new lines; output in Debug build only. nuclear@3: // nuclear@3: // Log_Debug - Debug-build only message, formatted with "Debug: %s\n". nuclear@3: // Intended to comment on incorrect API usage that doesn't lead nuclear@3: // to crashes but can be avoided with proper use. nuclear@3: // There is no Debug Error on purpose, since real errors should nuclear@3: // be handled by API user. nuclear@3: // nuclear@3: // Log_Assert - Debug-build only message, formatted with "Assert: %s\n". nuclear@3: // Intended for severe unrecoverable conditions in library nuclear@3: // source code. Generated though OVR_ASSERT_MSG(c, "Text"). nuclear@3: nuclear@3: enum LogMessageType nuclear@3: { nuclear@3: // General Logging nuclear@3: Log_Text = LogMask_Regular | 0, nuclear@3: Log_Error = LogMask_Regular | 1, // "Error: %s\n". nuclear@3: nuclear@3: // Debug-only messages (not generated in release build) nuclear@3: Log_DebugText = LogMask_Debug | 0, nuclear@3: Log_Debug = LogMask_Debug | 1, // "Debug: %s\n". nuclear@3: Log_Assert = LogMask_Debug | 2, // "Assert: %s\n". nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: // LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types nuclear@3: #ifdef __GNUC__ nuclear@3: # define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b))) nuclear@3: #else nuclear@3: # define OVR_LOG_VAARG_ATTRIBUTE(a,b) nuclear@3: #endif nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Log nuclear@3: nuclear@3: // Log defines a base class interface that can be implemented to catch both nuclear@3: // debug and runtime messages. nuclear@3: // Debug logging can be overridden by calling Log::SetGlobalLog. nuclear@3: nuclear@3: class Log nuclear@3: { nuclear@3: friend class System; nuclear@3: public: nuclear@3: Log(unsigned logMask = LogMask_Debug) : LoggingMask(logMask) { } nuclear@3: virtual ~Log(); nuclear@3: nuclear@3: // Log formating buffer size used by default LogMessageVarg. Longer strings are truncated. nuclear@3: enum { MaxLogBufferMessageSize = 2048 }; nuclear@3: nuclear@3: unsigned GetLoggingMask() const { return LoggingMask; } nuclear@3: void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; } nuclear@3: nuclear@3: // This virtual function receives all the messages, nuclear@3: // developers should override this function in order to do custom logging nuclear@3: virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList); nuclear@3: nuclear@3: // Call the logging function with specific message type, with no type filtering. nuclear@3: void LogMessage(LogMessageType messageType, nuclear@3: const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4); nuclear@3: nuclear@3: nuclear@3: // Helper used by LogMessageVarg to format the log message, writing the resulting nuclear@3: // string into buffer. It formats text based on fmt and appends prefix/new line nuclear@3: // based on LogMessageType. nuclear@3: static void FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType, nuclear@3: const char* fmt, va_list argList); nuclear@3: nuclear@3: // Default log output implementation used by by LogMessageVarg. nuclear@3: // Debug flag may be used to re-direct output on some platforms, but doesn't nuclear@3: // necessarily disable it in release builds; that is the job of the called. nuclear@3: static void DefaultLogOutput(const char* textBuffer, bool debug); nuclear@3: nuclear@3: // Determines if the specified message type is for debugging only. nuclear@3: static bool IsDebugMessage(LogMessageType messageType) nuclear@3: { nuclear@3: return (messageType & LogMask_Debug) != 0; nuclear@3: } nuclear@3: nuclear@3: // *** Global APIs nuclear@3: nuclear@3: // Global Log registration APIs. nuclear@3: // - Global log is used for OVR_DEBUG messages. Set global log to null (0) nuclear@3: // to disable all logging. nuclear@3: static void SetGlobalLog(Log *log); nuclear@3: static Log* GetGlobalLog(); nuclear@3: nuclear@3: // Returns default log singleton instance. nuclear@3: static Log* GetDefaultLog(); nuclear@3: nuclear@3: // Applies logMask to the default log and returns a pointer to it. nuclear@3: // By default, only Debug logging is enabled, so to avoid SDK generating console nuclear@3: // messages in user app (those are always disabled in release build, nuclear@3: // even if the flag is set). This function is useful in System constructor. nuclear@3: static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug) nuclear@3: { nuclear@3: Log* log = GetDefaultLog(); nuclear@3: log->SetLoggingMask(logMask); nuclear@3: return log; nuclear@3: } nuclear@3: nuclear@3: private: nuclear@3: // Logging mask described by LogMaskConstants. nuclear@3: unsigned LoggingMask; nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Global Logging Functions and Debug Macros nuclear@3: nuclear@3: // These functions will output text to global log with semantics described by nuclear@3: // their LogMessageType. nuclear@3: void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@3: void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@3: nuclear@3: #ifdef OVR_BUILD_DEBUG nuclear@3: nuclear@3: // Debug build only logging. nuclear@3: void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@3: void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@3: void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@3: nuclear@3: // Macro to do debug logging, printf-style. nuclear@3: // An extra set of set of parenthesis must be used around arguments, nuclear@3: // as in: OVR_LOG_DEBUG(("Value %d", 2)). nuclear@3: #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0) nuclear@3: #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0) nuclear@3: nuclear@3: #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0) nuclear@3: nuclear@3: #else nuclear@3: nuclear@3: // If not in debug build, macros do nothing. nuclear@3: #define OVR_DEBUG_LOG(args) ((void)0) nuclear@3: #define OVR_DEBUG_LOG_TEXT(args) ((void)0) nuclear@3: #define OVR_ASSERT_LOG(c, args) ((void)0) nuclear@3: nuclear@3: #endif nuclear@3: nuclear@3: } // OVR nuclear@3: nuclear@3: #endif