egllog.c revision 848b8605
1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2008 VMware, Inc.
4848b8605Smrg * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5848b8605Smrg * Copyright 2010 LunarG, Inc.
6848b8605Smrg * All Rights Reserved.
7848b8605Smrg *
8848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9848b8605Smrg * copy of this software and associated documentation files (the
10848b8605Smrg * "Software"), to deal in the Software without restriction, including
11848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
12848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
13848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
14848b8605Smrg * the following conditions:
15848b8605Smrg *
16848b8605Smrg * The above copyright notice and this permission notice (including the
17848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
18848b8605Smrg * of the Software.
19848b8605Smrg *
20848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26848b8605Smrg * DEALINGS IN THE SOFTWARE.
27848b8605Smrg *
28848b8605Smrg **************************************************************************/
29848b8605Smrg
30848b8605Smrg
31848b8605Smrg/**
32848b8605Smrg * Logging facility for debug/info messages.
33848b8605Smrg * _EGL_FATAL messages are printed to stderr
34848b8605Smrg * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
35848b8605Smrg */
36848b8605Smrg
37848b8605Smrg
38848b8605Smrg#include <stdarg.h>
39848b8605Smrg#include <stdio.h>
40848b8605Smrg#include <stdlib.h>
41848b8605Smrg
42848b8605Smrg#include "egllog.h"
43848b8605Smrg#include "eglstring.h"
44848b8605Smrg#include "eglmutex.h"
45848b8605Smrg
46848b8605Smrg#define MAXSTRING 1000
47848b8605Smrg#define FALLBACK_LOG_LEVEL _EGL_WARNING
48848b8605Smrg
49848b8605Smrg
50848b8605Smrgstatic struct {
51848b8605Smrg   _EGLMutex mutex;
52848b8605Smrg
53848b8605Smrg   EGLBoolean initialized;
54848b8605Smrg   EGLint level;
55848b8605Smrg   _EGLLogProc logger;
56848b8605Smrg   EGLint num_messages;
57848b8605Smrg} logging = {
58848b8605Smrg   _EGL_MUTEX_INITIALIZER,
59848b8605Smrg   EGL_FALSE,
60848b8605Smrg   FALLBACK_LOG_LEVEL,
61848b8605Smrg   NULL,
62848b8605Smrg   0
63848b8605Smrg};
64848b8605Smrg
65848b8605Smrgstatic const char *level_strings[] = {
66848b8605Smrg   /* the order is important */
67848b8605Smrg   "fatal",
68848b8605Smrg   "warning",
69848b8605Smrg   "info",
70848b8605Smrg   "debug",
71848b8605Smrg   NULL
72848b8605Smrg};
73848b8605Smrg
74848b8605Smrg
75848b8605Smrg/**
76848b8605Smrg * Set the function to be called when there is a message to log.
77848b8605Smrg * Note that the function will be called with an internal lock held.
78848b8605Smrg * Recursive logging is not allowed.
79848b8605Smrg */
80848b8605Smrgvoid
81848b8605Smrg_eglSetLogProc(_EGLLogProc logger)
82848b8605Smrg{
83848b8605Smrg   EGLint num_messages = 0;
84848b8605Smrg
85848b8605Smrg   _eglLockMutex(&logging.mutex);
86848b8605Smrg
87848b8605Smrg   if (logging.logger != logger) {
88848b8605Smrg      logging.logger = logger;
89848b8605Smrg
90848b8605Smrg      num_messages = logging.num_messages;
91848b8605Smrg      logging.num_messages = 0;
92848b8605Smrg   }
93848b8605Smrg
94848b8605Smrg   _eglUnlockMutex(&logging.mutex);
95848b8605Smrg
96848b8605Smrg   if (num_messages)
97848b8605Smrg      _eglLog(_EGL_DEBUG,
98848b8605Smrg              "New logger installed. "
99848b8605Smrg              "Messages before the new logger might not be available.");
100848b8605Smrg}
101848b8605Smrg
102848b8605Smrg
103848b8605Smrg/**
104848b8605Smrg * Set the log reporting level.
105848b8605Smrg */
106848b8605Smrgvoid
107848b8605Smrg_eglSetLogLevel(EGLint level)
108848b8605Smrg{
109848b8605Smrg   switch (level) {
110848b8605Smrg   case _EGL_FATAL:
111848b8605Smrg   case _EGL_WARNING:
112848b8605Smrg   case _EGL_INFO:
113848b8605Smrg   case _EGL_DEBUG:
114848b8605Smrg      _eglLockMutex(&logging.mutex);
115848b8605Smrg      logging.level = level;
116848b8605Smrg      _eglUnlockMutex(&logging.mutex);
117848b8605Smrg      break;
118848b8605Smrg   default:
119848b8605Smrg      break;
120848b8605Smrg   }
121848b8605Smrg}
122848b8605Smrg
123848b8605Smrg
124848b8605Smrg/**
125848b8605Smrg * The default logger.  It prints the message to stderr.
126848b8605Smrg */
127848b8605Smrgstatic void
128848b8605Smrg_eglDefaultLogger(EGLint level, const char *msg)
129848b8605Smrg{
130848b8605Smrg   fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
131848b8605Smrg}
132848b8605Smrg
133848b8605Smrg
134848b8605Smrg/**
135848b8605Smrg * Initialize the logging facility.
136848b8605Smrg */
137848b8605Smrgstatic void
138848b8605Smrg_eglInitLogger(void)
139848b8605Smrg{
140848b8605Smrg   const char *log_env;
141848b8605Smrg   EGLint i, level = -1;
142848b8605Smrg
143848b8605Smrg   if (logging.initialized)
144848b8605Smrg      return;
145848b8605Smrg
146848b8605Smrg   log_env = getenv("EGL_LOG_LEVEL");
147848b8605Smrg   if (log_env) {
148848b8605Smrg      for (i = 0; level_strings[i]; i++) {
149848b8605Smrg         if (_eglstrcasecmp(log_env, level_strings[i]) == 0) {
150848b8605Smrg            level = i;
151848b8605Smrg            break;
152848b8605Smrg         }
153848b8605Smrg      }
154848b8605Smrg   }
155848b8605Smrg   else {
156848b8605Smrg      level = FALLBACK_LOG_LEVEL;
157848b8605Smrg   }
158848b8605Smrg
159848b8605Smrg   logging.logger = _eglDefaultLogger;
160848b8605Smrg   logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
161848b8605Smrg   logging.initialized = EGL_TRUE;
162848b8605Smrg
163848b8605Smrg   /* it is fine to call _eglLog now */
164848b8605Smrg   if (log_env && level < 0) {
165848b8605Smrg      _eglLog(_EGL_WARNING,
166848b8605Smrg              "Unrecognized EGL_LOG_LEVEL environment variable value. "
167848b8605Smrg              "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
168848b8605Smrg              "Got \"%s\". Falling back to \"%s\".",
169848b8605Smrg              log_env, level_strings[FALLBACK_LOG_LEVEL]);
170848b8605Smrg   }
171848b8605Smrg}
172848b8605Smrg
173848b8605Smrg
174848b8605Smrg/**
175848b8605Smrg * Log a message with message logger.
176848b8605Smrg * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
177848b8605Smrg */
178848b8605Smrgvoid
179848b8605Smrg_eglLog(EGLint level, const char *fmtStr, ...)
180848b8605Smrg{
181848b8605Smrg   va_list args;
182848b8605Smrg   char msg[MAXSTRING];
183848b8605Smrg   int ret;
184848b8605Smrg
185848b8605Smrg   /* one-time initialization; a little race here is fine */
186848b8605Smrg   if (!logging.initialized)
187848b8605Smrg      _eglInitLogger();
188848b8605Smrg   if (level > logging.level || level < 0)
189848b8605Smrg      return;
190848b8605Smrg
191848b8605Smrg   _eglLockMutex(&logging.mutex);
192848b8605Smrg
193848b8605Smrg   if (logging.logger) {
194848b8605Smrg      va_start(args, fmtStr);
195848b8605Smrg      ret = vsnprintf(msg, MAXSTRING, fmtStr, args);
196848b8605Smrg      if (ret < 0 || ret >= MAXSTRING)
197848b8605Smrg         strcpy(msg, "<message truncated>");
198848b8605Smrg      va_end(args);
199848b8605Smrg
200848b8605Smrg      logging.logger(level, msg);
201848b8605Smrg      logging.num_messages++;
202848b8605Smrg   }
203848b8605Smrg
204848b8605Smrg   _eglUnlockMutex(&logging.mutex);
205848b8605Smrg
206848b8605Smrg   if (level == _EGL_FATAL)
207848b8605Smrg      exit(1); /* or abort()? */
208848b8605Smrg}
209