ovr_sdk

diff LibOVR/Src/Kernel/OVR_Log.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_Log.cpp	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,432 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +Filename    :   OVR_Log.cpp
     1.7 +Content     :   Logging support
     1.8 +Created     :   September 19, 2012
     1.9 +Notes       : 
    1.10 +
    1.11 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.12 +
    1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.15 +which is provided at the time of installation or download, or which 
    1.16 +otherwise accompanies this software in either electronic or hard copy form.
    1.17 +
    1.18 +You may obtain a copy of the License at
    1.19 +
    1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.21 +
    1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.23 +distributed under the License is distributed on an "AS IS" BASIS,
    1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.25 +See the License for the specific language governing permissions and
    1.26 +limitations under the License.
    1.27 +
    1.28 +************************************************************************************/
    1.29 +
    1.30 +#include "OVR_Log.h"
    1.31 +#include "OVR_Std.h"
    1.32 +#include <stdarg.h>
    1.33 +#include <stdio.h>
    1.34 +#include <time.h>
    1.35 +#include "../Kernel/OVR_System.h"
    1.36 +#include "../Kernel/OVR_DebugHelp.h"
    1.37 +#include "../Util/Util_SystemGUI.h"
    1.38 +
    1.39 +#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
    1.40 +#define WIN32_LEAN_AND_MEAN
    1.41 +#include <windows.h>
    1.42 +#elif defined(OVR_OS_ANDROID)
    1.43 +#include <android/log.h>
    1.44 +#elif defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) || defined(OVR_OS_UNIX)
    1.45 +#include <syslog.h>
    1.46 +#endif
    1.47 +
    1.48 +
    1.49 +class LogSubject : public OVR::SystemSingletonBase<LogSubject>
    1.50 +{
    1.51 +    static bool isShuttingDown;
    1.52 +
    1.53 +public:
    1.54 +
    1.55 +    LogSubject(){
    1.56 +        isShuttingDown = false;
    1.57 +        // Must be at end of function
    1.58 +        PushDestroyCallbacks();
    1.59 +    }
    1.60 +    
    1.61 +    virtual ~LogSubject(){} // Required because we use delete this below.
    1.62 +    
    1.63 +    virtual void OnThreadDestroy()
    1.64 +    {
    1.65 +        isShuttingDown = true;
    1.66 +    }
    1.67 +
    1.68 +    virtual void OnSystemDestroy()
    1.69 +    {
    1.70 +        delete this;
    1.71 +    }
    1.72 +
    1.73 +    static bool IsValid() {
    1.74 +        return isShuttingDown == false;
    1.75 +    }
    1.76 +
    1.77 +    OVR::Lock logSubjectLock;
    1.78 +    OVR::ObserverScope<OVR::Log::LogHandler> logSubject;
    1.79 +};
    1.80 +
    1.81 +bool LogSubject::isShuttingDown;
    1.82 +
    1.83 +OVR_DEFINE_SINGLETON(LogSubject);
    1.84 +
    1.85 +namespace OVR {
    1.86 +
    1.87 +    // Global Log pointer.
    1.88 +    Log* volatile OVR_GlobalLog = 0;
    1.89 +
    1.90 +//-----------------------------------------------------------------------------------
    1.91 +// ***** Log Implementation
    1.92 +
    1.93 +Log::Log(unsigned logMask) :
    1.94 +    LoggingMask(logMask)
    1.95 +{
    1.96 +#ifdef OVR_OS_WIN32
    1.97 +    hEventSource = RegisterEventSourceA(NULL, "OculusVR");
    1.98 +    OVR_ASSERT(hEventSource != NULL);
    1.99 +#endif
   1.100 +}
   1.101 +
   1.102 +Log::~Log()
   1.103 +{
   1.104 +#ifdef OVR_OS_WIN32
   1.105 +    if (hEventSource)
   1.106 +    {
   1.107 +        DeregisterEventSource(hEventSource);
   1.108 +    }
   1.109 +#endif
   1.110 +
   1.111 +    // Clear out global log
   1.112 +    if (this == OVR_GlobalLog)
   1.113 +    {
   1.114 +        // TBD: perhaps we should ASSERT if this happens before system shutdown?
   1.115 +        OVR_GlobalLog = 0;
   1.116 +    }
   1.117 +}
   1.118 +void Log::AddLogObserver(ObserverScope<LogHandler> *logObserver)
   1.119 +{
   1.120 +    if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
   1.121 +    {
   1.122 +        Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
   1.123 +        logObserver->GetPtr()->Observe(LogSubject::GetInstance()->logSubject);
   1.124 +    }
   1.125 +}
   1.126 +void Log::LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList)
   1.127 +{
   1.128 +    if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
   1.129 +    {
   1.130 +        // Invoke subject
   1.131 +        char  buffer[MaxLogBufferMessageSize];
   1.132 +        char* pBuffer = buffer;
   1.133 +        char* pAllocated = NULL;
   1.134 +
   1.135 +        #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
   1.136 +            va_list argListSaved;
   1.137 +            va_copy(argListSaved, argList);
   1.138 +        #endif
   1.139 +
   1.140 +        int result = FormatLog(pBuffer, MaxLogBufferMessageSize, Log_Text, fmt, argList);
   1.141 +
   1.142 +        if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
   1.143 +        {
   1.144 +            pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
   1.145 +            pBuffer = pAllocated;
   1.146 +
   1.147 +            #if !defined(OVR_CC_MSVC)
   1.148 +                va_end(argList); // The caller owns argList and will call va_end on it.
   1.149 +                va_copy(argList, argListSaved);
   1.150 +            #endif
   1.151 +
   1.152 +            FormatLog(pBuffer, (size_t)result + 1, Log_Text, fmt, argList);
   1.153 +        }
   1.154 +
   1.155 +        Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
   1.156 +        LogSubject::GetInstance()->logSubject.GetPtr()->Call(pBuffer, messageType);
   1.157 +
   1.158 +        delete[] pAllocated;
   1.159 +    }
   1.160 +}
   1.161 +
   1.162 +void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
   1.163 +{
   1.164 +    if ((messageType & LoggingMask) == 0)
   1.165 +        return;
   1.166 +#ifndef OVR_BUILD_DEBUG
   1.167 +    if (IsDebugMessage(messageType))
   1.168 +        return;
   1.169 +#endif
   1.170 +
   1.171 +    char  buffer[MaxLogBufferMessageSize];
   1.172 +    char* pBuffer = buffer;
   1.173 +    char* pAllocated = NULL;
   1.174 +
   1.175 +    #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
   1.176 +        va_list argListSaved;
   1.177 +        va_copy(argListSaved, argList);
   1.178 +    #endif
   1.179 +
   1.180 +    int result = FormatLog(pBuffer, MaxLogBufferMessageSize, messageType, fmt, argList);
   1.181 +
   1.182 +    if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
   1.183 +    {
   1.184 +        pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
   1.185 +        pBuffer = pAllocated;
   1.186 +
   1.187 +        #if !defined(OVR_CC_MSVC)
   1.188 +            va_end(argList); // The caller owns argList and will call va_end on it.
   1.189 +            va_copy(argList, argListSaved);
   1.190 +        #endif
   1.191 +
   1.192 +        FormatLog(pBuffer, (size_t)result + 1, messageType, fmt, argList);
   1.193 +    }
   1.194 +
   1.195 +    DefaultLogOutput(pBuffer, messageType, result);
   1.196 +    delete[] pAllocated;
   1.197 +}
   1.198 +
   1.199 +void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
   1.200 +{
   1.201 +    va_list argList;
   1.202 +    va_start(argList, pfmt);
   1.203 +    LogMessageVarg(messageType, pfmt, argList);
   1.204 +    va_end(argList);
   1.205 +}
   1.206 +
   1.207 +
   1.208 +// Return behavior is the same as ISO C vsnprintf: returns the required strlen of buffer (which will 
   1.209 +// be >= bufferSize if bufferSize is insufficient) or returns a negative value because the input was bad.
   1.210 +int Log::FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType,
   1.211 +                    const char* fmt, va_list argList)
   1.212 +{
   1.213 +    OVR_ASSERT(buffer && (bufferSize >= 10)); // Need to be able to at least print "Assert: \n" to it.
   1.214 +    if(!buffer || (bufferSize < 10))
   1.215 +        return -1;
   1.216 +
   1.217 +    int addNewline = 1;
   1.218 +    int prefixLength = 0;
   1.219 +
   1.220 +    switch(messageType)
   1.221 +    {
   1.222 +    case Log_Error:      OVR_strcpy(buffer, bufferSize, "Error: ");  prefixLength = 7; break;
   1.223 +    case Log_Debug:      OVR_strcpy(buffer, bufferSize, "Debug: ");  prefixLength = 7; break;
   1.224 +    case Log_Assert:     OVR_strcpy(buffer, bufferSize, "Assert: "); prefixLength = 8; break;
   1.225 +    case Log_Text:       buffer[0] = 0; addNewline = 0; break;
   1.226 +    case Log_DebugText:  buffer[0] = 0; addNewline = 0; break;
   1.227 +    default:             buffer[0] = 0; addNewline = 0; break;
   1.228 +    }
   1.229 +
   1.230 +    char*  buffer2       = buffer + prefixLength;
   1.231 +    size_t size2         = bufferSize - (size_t)prefixLength;
   1.232 +    int    messageLength = OVR_vsnprintf(buffer2, size2, fmt, argList);
   1.233 +
   1.234 +    if (addNewline)
   1.235 +    {
   1.236 +        if (messageLength < 0) // If there was a format error... 
   1.237 +        {
   1.238 +            // To consider: append <format error> to the buffer here.
   1.239 +            buffer2[0] = '\n'; // We are guaranteed to have capacity for this.
   1.240 +            buffer2[1] = '\0';
   1.241 +        }
   1.242 +        else
   1.243 +        {
   1.244 +            // If the printed string used all of the capacity or required more than the capacity,
   1.245 +            // Chop the output by one character so we can append the \n safely.
   1.246 +            int messageEnd = (messageLength >= (int)(size2 - 1)) ? (int)(size2 - 2) : messageLength;
   1.247 +            buffer2[messageEnd + 0] = '\n';
   1.248 +            buffer2[messageEnd + 1] = '\0';
   1.249 +        }
   1.250 +    }
   1.251 +
   1.252 +    if (messageLength >= 0) // If the format was OK...
   1.253 +        return prefixLength + messageLength + addNewline; // Return the required strlen of buffer.
   1.254 +
   1.255 +    return messageLength; // Else we cannot know what the required strlen is and return the error to the caller.
   1.256 +}
   1.257 +
   1.258 +void Log::DefaultLogOutput(const char* formattedText, LogMessageType messageType, int bufferSize)
   1.259 +{
   1.260 +    bool debug = IsDebugMessage(messageType);
   1.261 +    OVR_UNUSED(bufferSize);
   1.262 +
   1.263 +#if defined(OVR_OS_WIN32)
   1.264 +    // Under Win32, output regular messages to console if it exists; debug window otherwise.
   1.265 +    static DWORD dummyMode;
   1.266 +    static bool  hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
   1.267 +                              (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
   1.268 +
   1.269 +    if (!hasConsole || debug)
   1.270 +    {
   1.271 +        ::OutputDebugStringA(formattedText);
   1.272 +    }
   1.273 +
   1.274 +    fputs(formattedText, stdout);
   1.275 +
   1.276 +#elif defined(OVR_OS_MS) // Any other Microsoft OSs
   1.277 +
   1.278 +    ::OutputDebugStringA(formattedText);
   1.279 +
   1.280 +#elif defined(OVR_OS_ANDROID)
   1.281 +    // To do: use bufferSize to deal with the case that Android has a limited output length.
   1.282 +    __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
   1.283 +
   1.284 +#else
   1.285 +    fputs(formattedText, stdout);
   1.286 +
   1.287 +#endif
   1.288 +
   1.289 +    if (messageType == Log_Error)
   1.290 +    {
   1.291 +#if defined(OVR_OS_WIN32)
   1.292 +        if (!ReportEventA(hEventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, &formattedText, NULL))
   1.293 +        {
   1.294 +            OVR_ASSERT(false);
   1.295 +        }
   1.296 +#elif defined(OVR_OS_MS) // Any other Microsoft OSs
   1.297 +        // TBD
   1.298 +#elif defined(OVR_OS_ANDROID)
   1.299 +        // TBD
   1.300 +#elif defined(OVR_OS_MAC) || defined(OVR_OS_LINUX)
   1.301 +        syslog(LOG_ERR, "%s", formattedText);
   1.302 +#else
   1.303 +        // TBD
   1.304 +#endif
   1.305 +    }
   1.306 +
   1.307 +    // Just in case.
   1.308 +    OVR_UNUSED2(formattedText, debug);
   1.309 +}
   1.310 +
   1.311 +
   1.312 +//static
   1.313 +void Log::SetGlobalLog(Log *log)
   1.314 +{
   1.315 +    OVR_GlobalLog = log;
   1.316 +}
   1.317 +//static
   1.318 +Log* Log::GetGlobalLog()
   1.319 +{
   1.320 +// No global log by default?
   1.321 +//    if (!OVR_GlobalLog)
   1.322 +//        OVR_GlobalLog = GetDefaultLog();
   1.323 +    return OVR_GlobalLog;
   1.324 +}
   1.325 +
   1.326 +//static
   1.327 +Log* Log::GetDefaultLog()
   1.328 +{
   1.329 +    // Create default log pointer statically so that it can be used
   1.330 +    // even during startup.
   1.331 +    static Log defaultLog;
   1.332 +    return &defaultLog;
   1.333 +}
   1.334 +
   1.335 +
   1.336 +//-----------------------------------------------------------------------------------
   1.337 +// ***** Global Logging functions
   1.338 +
   1.339 +#if !defined(OVR_CC_MSVC)
   1.340 +// The reason for va_copy is because you can't use va_start twice on Linux
   1.341 +#define OVR_LOG_FUNCTION_IMPL(Name)  \
   1.342 +    void Log##Name(const char* fmt, ...) \
   1.343 +    {                                                                    \
   1.344 +        if (OVR_GlobalLog)                                               \
   1.345 +        {                                                                \
   1.346 +            va_list argList1;                                             \
   1.347 +            va_start(argList1, fmt);                                     \
   1.348 +            va_list argList2;                                             \
   1.349 +            va_copy(argList2, argList1);                                 \
   1.350 +            OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList2); \
   1.351 +            va_end(argList2);                                             \
   1.352 +            OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1);    \
   1.353 +            va_end(argList1);                                            \
   1.354 +        }                                                                \
   1.355 +    }
   1.356 +#else
   1.357 +#define OVR_LOG_FUNCTION_IMPL(Name)  \
   1.358 +    void Log##Name(const char* fmt, ...) \
   1.359 +    {                                                                    \
   1.360 +        if (OVR_GlobalLog)                                               \
   1.361 +        {                                                                \
   1.362 +            va_list argList1;                                             \
   1.363 +            va_start(argList1, fmt);                                     \
   1.364 +            OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList1); \
   1.365 +            OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1);    \
   1.366 +            va_end(argList1);                                            \
   1.367 +        }                                                                \
   1.368 +    }
   1.369 +#endif // #if !defined(OVR_OS_WIN32)
   1.370 +
   1.371 +OVR_LOG_FUNCTION_IMPL(Text)
   1.372 +OVR_LOG_FUNCTION_IMPL(Error)
   1.373 +
   1.374 +#ifdef OVR_BUILD_DEBUG
   1.375 +OVR_LOG_FUNCTION_IMPL(DebugText)
   1.376 +OVR_LOG_FUNCTION_IMPL(Debug)
   1.377 +OVR_LOG_FUNCTION_IMPL(Assert)
   1.378 +#endif
   1.379 +
   1.380 +
   1.381 +
   1.382 +// Assertion handler support
   1.383 +// To consider: Move this to an OVR_Types.cpp or OVR_Assert.cpp source file.
   1.384 +
   1.385 +static OVRAssertionHandler sOVRAssertionHandler = OVR::DefaultAssertionHandler;
   1.386 +static intptr_t sOVRAssertionHandlerUserParameter = 0;
   1.387 +
   1.388 +OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter)
   1.389 +{
   1.390 +    if(userParameter)
   1.391 +        *userParameter = sOVRAssertionHandlerUserParameter;
   1.392 +    return sOVRAssertionHandler;
   1.393 +}
   1.394 +
   1.395 +void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter)
   1.396 +{
   1.397 +    sOVRAssertionHandler = assertionHandler;
   1.398 +    sOVRAssertionHandlerUserParameter = userParameter;
   1.399 +}
   1.400 +
   1.401 +intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message)
   1.402 +{
   1.403 +    if(OVRIsDebuggerPresent())
   1.404 +    {
   1.405 +        OVR_DEBUG_BREAK;
   1.406 +    }
   1.407 +    else
   1.408 +    {
   1.409 +        #if defined(OVR_BUILD_DEBUG)
   1.410 +            // Print a stack trace of all threads.
   1.411 +            OVR::String s;
   1.412 +            OVR::String threadListOutput;
   1.413 +            static OVR::SymbolLookup symbolLookup;
   1.414 +
   1.415 +            s = "Failure: "; 
   1.416 +            s += message;
   1.417 +
   1.418 +            if(symbolLookup.Initialize() && symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our internal handling and retrieve starting at the assertion location (our caller) only.
   1.419 +            {
   1.420 +                s += "\r\n\r\n";
   1.421 +                s += threadListOutput;
   1.422 +            }
   1.423 +
   1.424 +            OVR::Util::DisplayMessageBox(title, s.ToCStr());
   1.425 +        #else
   1.426 +            OVR::Util::DisplayMessageBox(title, message);
   1.427 +        #endif
   1.428 +    }
   1.429 +    
   1.430 +    return 0;
   1.431 +}
   1.432 +
   1.433 +
   1.434 +
   1.435 +} // OVR