nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: PublicHeader: OVR nuclear@0: Filename : OVR_Log.h nuclear@0: Content : Logging support nuclear@0: Created : September 19, 2012 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_Log_h nuclear@0: #define OVR_Log_h nuclear@0: nuclear@0: #include "OVR_Types.h" nuclear@0: #include "../Kernel/OVR_Delegates.h" nuclear@0: #include "../Kernel//OVR_Observer.h" nuclear@0: #include nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Logging Constants nuclear@0: nuclear@0: // LogMaskConstants defined bit mask constants that describe what log messages nuclear@0: // should be displayed. nuclear@0: enum LogMaskConstants nuclear@0: { nuclear@0: LogMask_Regular = 0x100, nuclear@0: LogMask_Debug = 0x200, nuclear@0: LogMask_None = 0, nuclear@0: LogMask_All = LogMask_Regular|LogMask_Debug nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // LogMessageType describes the type of the log message, controls when it is nuclear@0: // displayed and what prefix/suffix is given to it. Messages are subdivided into nuclear@0: // regular and debug logging types. Debug logging is only generated in debug builds. nuclear@0: // nuclear@0: // Log_Text - General output text displayed without prefix or new-line. nuclear@0: // Used in OVR libraries for general log flow messages nuclear@0: // such as "Device Initialized". nuclear@0: // nuclear@0: // Log_Error - Error message output with "Error: %s\n", intended for nuclear@0: // application/sample-level use only, in cases where an expected nuclear@0: // operation failed. OVR libraries should not use this internally, nuclear@0: // reporting status codes instead. nuclear@0: // nuclear@0: // Log_DebugText - Message without prefix or new lines; output in Debug build only. nuclear@0: // nuclear@0: // Log_Debug - Debug-build only message, formatted with "Debug: %s\n". nuclear@0: // Intended to comment on incorrect API usage that doesn't lead nuclear@0: // to crashes but can be avoided with proper use. nuclear@0: // There is no Debug Error on purpose, since real errors should nuclear@0: // be handled by API user. nuclear@0: // nuclear@0: // Log_Assert - Debug-build only message, formatted with "Assert: %s\n". nuclear@0: // Intended for severe unrecoverable conditions in library nuclear@0: // source code. Generated though OVR_ASSERT_MSG(c, "Text"). nuclear@0: nuclear@0: enum LogMessageType nuclear@0: { nuclear@0: // General Logging nuclear@0: Log_Text = LogMask_Regular | 0, nuclear@0: Log_Error = LogMask_Regular | 1, // "Error: %s\n". nuclear@0: nuclear@0: // Debug-only messages (not generated in release build) nuclear@0: Log_DebugText = LogMask_Debug | 0, nuclear@0: Log_Debug = LogMask_Debug | 1, // "Debug: %s\n". nuclear@0: Log_Assert = LogMask_Debug | 2, // "Assert: %s\n". nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types nuclear@0: #ifdef __GNUC__ nuclear@0: # define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b))) nuclear@0: #else nuclear@0: # define OVR_LOG_VAARG_ATTRIBUTE(a,b) nuclear@0: #endif nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Log nuclear@0: nuclear@0: // Log defines a base class interface that can be implemented to catch both nuclear@0: // debug and runtime messages. nuclear@0: // Debug logging can be overridden by calling Log::SetGlobalLog. nuclear@0: nuclear@0: class Log nuclear@0: { nuclear@0: friend class System; nuclear@0: nuclear@0: #ifdef OVR_OS_WIN32 nuclear@0: void* hEventSource; nuclear@0: #endif nuclear@0: nuclear@0: public: nuclear@0: Log(unsigned logMask = LogMask_Debug); nuclear@0: virtual ~Log(); nuclear@0: nuclear@0: typedef Delegate2 LogHandler; nuclear@0: nuclear@0: // The following is deprecated, as there is no longer a max log buffer message size. nuclear@0: enum { MaxLogBufferMessageSize = 4096 }; nuclear@0: nuclear@0: unsigned GetLoggingMask() const { return LoggingMask; } nuclear@0: void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; } nuclear@0: nuclear@0: // Internal nuclear@0: // Invokes observers, then calls LogMessageVarg() nuclear@0: static void LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList); nuclear@0: nuclear@0: // This virtual function receives all the messages, nuclear@0: // developers should override this function in order to do custom logging nuclear@0: virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList); nuclear@0: nuclear@0: static void AddLogObserver(ObserverScope *logObserver); nuclear@0: nuclear@0: // Call the logging function with specific message type, with no type filtering. nuclear@0: void LogMessage(LogMessageType messageType, nuclear@0: const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4); nuclear@0: nuclear@0: nuclear@0: // Helper used by LogMessageVarg to format the log message, writing the resulting nuclear@0: // string into buffer. It formats text based on fmt and appends prefix/new line nuclear@0: // based on LogMessageType. Return behavior is the same as ISO C vsnprintf: returns the nuclear@0: // required strlen of buffer (which will be >= bufferSize if bufferSize is insufficient) nuclear@0: // or returns a negative value because the input was bad. nuclear@0: static int FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType, nuclear@0: const char* fmt, va_list argList); nuclear@0: nuclear@0: // Default log output implementation used by by LogMessageVarg. nuclear@0: // Debug flag may be used to re-direct output on some platforms, but doesn't nuclear@0: // necessarily disable it in release builds; that is the job of the called. nuclear@0: void DefaultLogOutput(const char* textBuffer, LogMessageType messageType, int bufferSize = -1); nuclear@0: nuclear@0: // Determines if the specified message type is for debugging only. nuclear@0: static bool IsDebugMessage(LogMessageType messageType) nuclear@0: { nuclear@0: return (messageType & LogMask_Debug) != 0; nuclear@0: } nuclear@0: nuclear@0: // *** Global APIs nuclear@0: nuclear@0: // Global Log registration APIs. nuclear@0: // - Global log is used for OVR_DEBUG messages. Set global log to null (0) nuclear@0: // to disable all logging. nuclear@0: static void SetGlobalLog(Log *log); nuclear@0: static Log* GetGlobalLog(); nuclear@0: nuclear@0: // Returns default log singleton instance. nuclear@0: static Log* GetDefaultLog(); nuclear@0: nuclear@0: // Applies logMask to the default log and returns a pointer to it. nuclear@0: // By default, only Debug logging is enabled, so to avoid SDK generating console nuclear@0: // messages in user app (those are always disabled in release build, nuclear@0: // even if the flag is set). This function is useful in System constructor. nuclear@0: static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug) nuclear@0: { nuclear@0: Log* log = GetDefaultLog(); nuclear@0: log->SetLoggingMask(logMask); nuclear@0: return log; nuclear@0: } nuclear@0: nuclear@0: private: nuclear@0: // Logging mask described by LogMaskConstants. nuclear@0: unsigned LoggingMask; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Global Logging Functions and Debug Macros nuclear@0: nuclear@0: // These functions will output text to global log with semantics described by nuclear@0: // their LogMessageType. nuclear@0: void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@0: void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@0: nuclear@0: #ifdef OVR_BUILD_DEBUG nuclear@0: nuclear@0: // Debug build only logging. nuclear@0: void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@0: void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@0: void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); nuclear@0: nuclear@0: // Macro to do debug logging, printf-style. nuclear@0: // An extra set of set of parenthesis must be used around arguments, nuclear@0: // as in: OVR_DEBUG_LOG(("Value %d", 2)). nuclear@0: #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0) nuclear@0: #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0) nuclear@0: nuclear@0: // Conditional logging. It logs when the condition 'c' is true. nuclear@0: #define OVR_DEBUG_LOG_COND(c, args) do { if ((c)) { OVR::LogDebug args; } } while(0) nuclear@0: #define OVR_DEBUG_LOG_TEXT_COND(c, args) do { if ((c)) { OVR::LogDebugText args; } } while(0) nuclear@0: nuclear@0: // Conditional logging & asserting. It asserts/logs when the condition 'c' is NOT true. nuclear@0: #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0) nuclear@0: nuclear@0: #else nuclear@0: nuclear@0: // If not in debug build, macros do nothing. nuclear@0: #define OVR_DEBUG_LOG(args) ((void)0) nuclear@0: #define OVR_DEBUG_LOG_TEXT(args) ((void)0) nuclear@0: #define OVR_DEBUG_LOG_COND(c, args) ((void)0) nuclear@0: #define OVR_DEBUG_LOG_TEXT_COND(args) ((void)0) nuclear@0: #define OVR_ASSERT_LOG(c, args) ((void)0) nuclear@0: nuclear@0: #endif nuclear@0: nuclear@0: } // OVR nuclear@0: nuclear@0: #endif