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