1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe (at) 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 50 static 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 65 static 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 */ 80 void 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 */ 106 void 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 */ 127 static 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 */ 137 static 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 */ 178 void 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