ovr_sdk

view 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 source
1 /************************************************************************************
3 Filename : OVR_Log.cpp
4 Content : Logging support
5 Created : September 19, 2012
6 Notes :
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 You may obtain a copy of the License at
17 http://www.oculusvr.com/licenses/LICENSE-3.2
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
25 ************************************************************************************/
27 #include "OVR_Log.h"
28 #include "OVR_Std.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include "../Kernel/OVR_System.h"
33 #include "../Kernel/OVR_DebugHelp.h"
34 #include "../Util/Util_SystemGUI.h"
36 #if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
39 #elif defined(OVR_OS_ANDROID)
40 #include <android/log.h>
41 #elif defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) || defined(OVR_OS_UNIX)
42 #include <syslog.h>
43 #endif
46 class LogSubject : public OVR::SystemSingletonBase<LogSubject>
47 {
48 static bool isShuttingDown;
50 public:
52 LogSubject(){
53 isShuttingDown = false;
54 // Must be at end of function
55 PushDestroyCallbacks();
56 }
58 virtual ~LogSubject(){} // Required because we use delete this below.
60 virtual void OnThreadDestroy()
61 {
62 isShuttingDown = true;
63 }
65 virtual void OnSystemDestroy()
66 {
67 delete this;
68 }
70 static bool IsValid() {
71 return isShuttingDown == false;
72 }
74 OVR::Lock logSubjectLock;
75 OVR::ObserverScope<OVR::Log::LogHandler> logSubject;
76 };
78 bool LogSubject::isShuttingDown;
80 OVR_DEFINE_SINGLETON(LogSubject);
82 namespace OVR {
84 // Global Log pointer.
85 Log* volatile OVR_GlobalLog = 0;
87 //-----------------------------------------------------------------------------------
88 // ***** Log Implementation
90 Log::Log(unsigned logMask) :
91 LoggingMask(logMask)
92 {
93 #ifdef OVR_OS_WIN32
94 hEventSource = RegisterEventSourceA(NULL, "OculusVR");
95 OVR_ASSERT(hEventSource != NULL);
96 #endif
97 }
99 Log::~Log()
100 {
101 #ifdef OVR_OS_WIN32
102 if (hEventSource)
103 {
104 DeregisterEventSource(hEventSource);
105 }
106 #endif
108 // Clear out global log
109 if (this == OVR_GlobalLog)
110 {
111 // TBD: perhaps we should ASSERT if this happens before system shutdown?
112 OVR_GlobalLog = 0;
113 }
114 }
115 void Log::AddLogObserver(ObserverScope<LogHandler> *logObserver)
116 {
117 if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
118 {
119 Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
120 logObserver->GetPtr()->Observe(LogSubject::GetInstance()->logSubject);
121 }
122 }
123 void Log::LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList)
124 {
125 if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
126 {
127 // Invoke subject
128 char buffer[MaxLogBufferMessageSize];
129 char* pBuffer = buffer;
130 char* pAllocated = NULL;
132 #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
133 va_list argListSaved;
134 va_copy(argListSaved, argList);
135 #endif
137 int result = FormatLog(pBuffer, MaxLogBufferMessageSize, Log_Text, fmt, argList);
139 if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
140 {
141 pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
142 pBuffer = pAllocated;
144 #if !defined(OVR_CC_MSVC)
145 va_end(argList); // The caller owns argList and will call va_end on it.
146 va_copy(argList, argListSaved);
147 #endif
149 FormatLog(pBuffer, (size_t)result + 1, Log_Text, fmt, argList);
150 }
152 Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
153 LogSubject::GetInstance()->logSubject.GetPtr()->Call(pBuffer, messageType);
155 delete[] pAllocated;
156 }
157 }
159 void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
160 {
161 if ((messageType & LoggingMask) == 0)
162 return;
163 #ifndef OVR_BUILD_DEBUG
164 if (IsDebugMessage(messageType))
165 return;
166 #endif
168 char buffer[MaxLogBufferMessageSize];
169 char* pBuffer = buffer;
170 char* pAllocated = NULL;
172 #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
173 va_list argListSaved;
174 va_copy(argListSaved, argList);
175 #endif
177 int result = FormatLog(pBuffer, MaxLogBufferMessageSize, messageType, fmt, argList);
179 if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
180 {
181 pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
182 pBuffer = pAllocated;
184 #if !defined(OVR_CC_MSVC)
185 va_end(argList); // The caller owns argList and will call va_end on it.
186 va_copy(argList, argListSaved);
187 #endif
189 FormatLog(pBuffer, (size_t)result + 1, messageType, fmt, argList);
190 }
192 DefaultLogOutput(pBuffer, messageType, result);
193 delete[] pAllocated;
194 }
196 void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
197 {
198 va_list argList;
199 va_start(argList, pfmt);
200 LogMessageVarg(messageType, pfmt, argList);
201 va_end(argList);
202 }
205 // Return behavior is the same as ISO C vsnprintf: returns the required strlen of buffer (which will
206 // be >= bufferSize if bufferSize is insufficient) or returns a negative value because the input was bad.
207 int Log::FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType,
208 const char* fmt, va_list argList)
209 {
210 OVR_ASSERT(buffer && (bufferSize >= 10)); // Need to be able to at least print "Assert: \n" to it.
211 if(!buffer || (bufferSize < 10))
212 return -1;
214 int addNewline = 1;
215 int prefixLength = 0;
217 switch(messageType)
218 {
219 case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); prefixLength = 7; break;
220 case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); prefixLength = 7; break;
221 case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); prefixLength = 8; break;
222 case Log_Text: buffer[0] = 0; addNewline = 0; break;
223 case Log_DebugText: buffer[0] = 0; addNewline = 0; break;
224 default: buffer[0] = 0; addNewline = 0; break;
225 }
227 char* buffer2 = buffer + prefixLength;
228 size_t size2 = bufferSize - (size_t)prefixLength;
229 int messageLength = OVR_vsnprintf(buffer2, size2, fmt, argList);
231 if (addNewline)
232 {
233 if (messageLength < 0) // If there was a format error...
234 {
235 // To consider: append <format error> to the buffer here.
236 buffer2[0] = '\n'; // We are guaranteed to have capacity for this.
237 buffer2[1] = '\0';
238 }
239 else
240 {
241 // If the printed string used all of the capacity or required more than the capacity,
242 // Chop the output by one character so we can append the \n safely.
243 int messageEnd = (messageLength >= (int)(size2 - 1)) ? (int)(size2 - 2) : messageLength;
244 buffer2[messageEnd + 0] = '\n';
245 buffer2[messageEnd + 1] = '\0';
246 }
247 }
249 if (messageLength >= 0) // If the format was OK...
250 return prefixLength + messageLength + addNewline; // Return the required strlen of buffer.
252 return messageLength; // Else we cannot know what the required strlen is and return the error to the caller.
253 }
255 void Log::DefaultLogOutput(const char* formattedText, LogMessageType messageType, int bufferSize)
256 {
257 bool debug = IsDebugMessage(messageType);
258 OVR_UNUSED(bufferSize);
260 #if defined(OVR_OS_WIN32)
261 // Under Win32, output regular messages to console if it exists; debug window otherwise.
262 static DWORD dummyMode;
263 static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
264 (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
266 if (!hasConsole || debug)
267 {
268 ::OutputDebugStringA(formattedText);
269 }
271 fputs(formattedText, stdout);
273 #elif defined(OVR_OS_MS) // Any other Microsoft OSs
275 ::OutputDebugStringA(formattedText);
277 #elif defined(OVR_OS_ANDROID)
278 // To do: use bufferSize to deal with the case that Android has a limited output length.
279 __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
281 #else
282 fputs(formattedText, stdout);
284 #endif
286 if (messageType == Log_Error)
287 {
288 #if defined(OVR_OS_WIN32)
289 if (!ReportEventA(hEventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, &formattedText, NULL))
290 {
291 OVR_ASSERT(false);
292 }
293 #elif defined(OVR_OS_MS) // Any other Microsoft OSs
294 // TBD
295 #elif defined(OVR_OS_ANDROID)
296 // TBD
297 #elif defined(OVR_OS_MAC) || defined(OVR_OS_LINUX)
298 syslog(LOG_ERR, "%s", formattedText);
299 #else
300 // TBD
301 #endif
302 }
304 // Just in case.
305 OVR_UNUSED2(formattedText, debug);
306 }
309 //static
310 void Log::SetGlobalLog(Log *log)
311 {
312 OVR_GlobalLog = log;
313 }
314 //static
315 Log* Log::GetGlobalLog()
316 {
317 // No global log by default?
318 // if (!OVR_GlobalLog)
319 // OVR_GlobalLog = GetDefaultLog();
320 return OVR_GlobalLog;
321 }
323 //static
324 Log* Log::GetDefaultLog()
325 {
326 // Create default log pointer statically so that it can be used
327 // even during startup.
328 static Log defaultLog;
329 return &defaultLog;
330 }
333 //-----------------------------------------------------------------------------------
334 // ***** Global Logging functions
336 #if !defined(OVR_CC_MSVC)
337 // The reason for va_copy is because you can't use va_start twice on Linux
338 #define OVR_LOG_FUNCTION_IMPL(Name) \
339 void Log##Name(const char* fmt, ...) \
340 { \
341 if (OVR_GlobalLog) \
342 { \
343 va_list argList1; \
344 va_start(argList1, fmt); \
345 va_list argList2; \
346 va_copy(argList2, argList1); \
347 OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList2); \
348 va_end(argList2); \
349 OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \
350 va_end(argList1); \
351 } \
352 }
353 #else
354 #define OVR_LOG_FUNCTION_IMPL(Name) \
355 void Log##Name(const char* fmt, ...) \
356 { \
357 if (OVR_GlobalLog) \
358 { \
359 va_list argList1; \
360 va_start(argList1, fmt); \
361 OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList1); \
362 OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \
363 va_end(argList1); \
364 } \
365 }
366 #endif // #if !defined(OVR_OS_WIN32)
368 OVR_LOG_FUNCTION_IMPL(Text)
369 OVR_LOG_FUNCTION_IMPL(Error)
371 #ifdef OVR_BUILD_DEBUG
372 OVR_LOG_FUNCTION_IMPL(DebugText)
373 OVR_LOG_FUNCTION_IMPL(Debug)
374 OVR_LOG_FUNCTION_IMPL(Assert)
375 #endif
379 // Assertion handler support
380 // To consider: Move this to an OVR_Types.cpp or OVR_Assert.cpp source file.
382 static OVRAssertionHandler sOVRAssertionHandler = OVR::DefaultAssertionHandler;
383 static intptr_t sOVRAssertionHandlerUserParameter = 0;
385 OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter)
386 {
387 if(userParameter)
388 *userParameter = sOVRAssertionHandlerUserParameter;
389 return sOVRAssertionHandler;
390 }
392 void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter)
393 {
394 sOVRAssertionHandler = assertionHandler;
395 sOVRAssertionHandlerUserParameter = userParameter;
396 }
398 intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message)
399 {
400 if(OVRIsDebuggerPresent())
401 {
402 OVR_DEBUG_BREAK;
403 }
404 else
405 {
406 #if defined(OVR_BUILD_DEBUG)
407 // Print a stack trace of all threads.
408 OVR::String s;
409 OVR::String threadListOutput;
410 static OVR::SymbolLookup symbolLookup;
412 s = "Failure: ";
413 s += message;
415 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.
416 {
417 s += "\r\n\r\n";
418 s += threadListOutput;
419 }
421 OVR::Util::DisplayMessageBox(title, s.ToCStr());
422 #else
423 OVR::Util::DisplayMessageBox(title, message);
424 #endif
425 }
427 return 0;
428 }
432 } // OVR