1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 5 * Copyright 2010 LunarG, Inc. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 30 31/** 32 * Logging facility for debug/info messages. 33 * _EGL_FATAL messages are printed to stderr 34 * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs. 35 */ 36 37 38#include <stdarg.h> 39#include <stdio.h> 40#include <stdlib.h> 41 42#include "egllog.h" 43#include "eglstring.h" 44#include "eglmutex.h" 45 46#define MAXSTRING 1000 47#define FALLBACK_LOG_LEVEL _EGL_WARNING 48 49 50static struct { 51 _EGLMutex mutex; 52 53 EGLBoolean initialized; 54 EGLint level; 55 _EGLLogProc logger; 56 EGLint num_messages; 57} logging = { 58 _EGL_MUTEX_INITIALIZER, 59 EGL_FALSE, 60 FALLBACK_LOG_LEVEL, 61 NULL, 62 0 63}; 64 65static const char *level_strings[] = { 66 /* the order is important */ 67 "fatal", 68 "warning", 69 "info", 70 "debug", 71 NULL 72}; 73 74 75/** 76 * Set the function to be called when there is a message to log. 77 * Note that the function will be called with an internal lock held. 78 * Recursive logging is not allowed. 79 */ 80void 81_eglSetLogProc(_EGLLogProc logger) 82{ 83 EGLint num_messages = 0; 84 85 _eglLockMutex(&logging.mutex); 86 87 if (logging.logger != logger) { 88 logging.logger = logger; 89 90 num_messages = logging.num_messages; 91 logging.num_messages = 0; 92 } 93 94 _eglUnlockMutex(&logging.mutex); 95 96 if (num_messages) 97 _eglLog(_EGL_DEBUG, 98 "New logger installed. " 99 "Messages before the new logger might not be available."); 100} 101 102 103/** 104 * Set the log reporting level. 105 */ 106void 107_eglSetLogLevel(EGLint level) 108{ 109 switch (level) { 110 case _EGL_FATAL: 111 case _EGL_WARNING: 112 case _EGL_INFO: 113 case _EGL_DEBUG: 114 _eglLockMutex(&logging.mutex); 115 logging.level = level; 116 _eglUnlockMutex(&logging.mutex); 117 break; 118 default: 119 break; 120 } 121} 122 123 124/** 125 * The default logger. It prints the message to stderr. 126 */ 127static void 128_eglDefaultLogger(EGLint level, const char *msg) 129{ 130 fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg); 131} 132 133 134/** 135 * Initialize the logging facility. 136 */ 137static void 138_eglInitLogger(void) 139{ 140 const char *log_env; 141 EGLint i, level = -1; 142 143 if (logging.initialized) 144 return; 145 146 log_env = getenv("EGL_LOG_LEVEL"); 147 if (log_env) { 148 for (i = 0; level_strings[i]; i++) { 149 if (_eglstrcasecmp(log_env, level_strings[i]) == 0) { 150 level = i; 151 break; 152 } 153 } 154 } 155 else { 156 level = FALLBACK_LOG_LEVEL; 157 } 158 159 logging.logger = _eglDefaultLogger; 160 logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL; 161 logging.initialized = EGL_TRUE; 162 163 /* it is fine to call _eglLog now */ 164 if (log_env && level < 0) { 165 _eglLog(_EGL_WARNING, 166 "Unrecognized EGL_LOG_LEVEL environment variable value. " 167 "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". " 168 "Got \"%s\". Falling back to \"%s\".", 169 log_env, level_strings[FALLBACK_LOG_LEVEL]); 170 } 171} 172 173 174/** 175 * Log a message with message logger. 176 * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG. 177 */ 178void 179_eglLog(EGLint level, const char *fmtStr, ...) 180{ 181 va_list args; 182 char msg[MAXSTRING]; 183 int ret; 184 185 /* one-time initialization; a little race here is fine */ 186 if (!logging.initialized) 187 _eglInitLogger(); 188 if (level > logging.level || level < 0) 189 return; 190 191 _eglLockMutex(&logging.mutex); 192 193 if (logging.logger) { 194 va_start(args, fmtStr); 195 ret = vsnprintf(msg, MAXSTRING, fmtStr, args); 196 if (ret < 0 || ret >= MAXSTRING) 197 strcpy(msg, "<message truncated>"); 198 va_end(args); 199 200 logging.logger(level, msg); 201 logging.num_messages++; 202 } 203 204 _eglUnlockMutex(&logging.mutex); 205 206 if (level == _EGL_FATAL) 207 exit(1); /* or abort()? */ 208} 209