8f3bae2243d9e512a591bf3c836163137def0d5f
[profile/ivi/mesa.git] / src / egl / main / egllog.c
1 /**
2  * Logging facility for debug/info messages.
3  * _EGL_FATAL messages are printed to stderr
4  * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
5  */
6
7
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "egllog.h"
14 #include "eglstring.h"
15 #include "eglmutex.h"
16
17 #define MAXSTRING 1000
18 #define FALLBACK_LOG_LEVEL _EGL_WARNING
19
20
21 static struct {
22    _EGLMutex mutex;
23
24    EGLBoolean initialized;
25    EGLint level;
26    _EGLLogProc logger;
27    EGLint num_messages;
28 } logging = {
29    _EGL_MUTEX_INITIALIZER,
30    EGL_FALSE,
31    FALLBACK_LOG_LEVEL,
32    NULL,
33    0
34 };
35
36 static const char *level_strings[] = {
37    /* the order is important */
38    "fatal",
39    "warning",
40    "info",
41    "debug",
42    NULL
43 };
44
45
46 /**
47  * Set the function to be called when there is a message to log.
48  * Note that the function will be called with an internal lock held.
49  * Recursive logging is not allowed.
50  */
51 void
52 _eglSetLogProc(_EGLLogProc logger)
53 {
54    EGLint num_messages = 0;
55
56    _eglLockMutex(&logging.mutex);
57
58    if (logging.logger != logger) {
59       logging.logger = logger;
60
61       num_messages = logging.num_messages;
62       logging.num_messages = 0;
63    }
64
65    _eglUnlockMutex(&logging.mutex);
66
67    if (num_messages)
68       _eglLog(_EGL_DEBUG,
69               "New logger installed. "
70               "Messages before the new logger might not be available.");
71 }
72
73
74 /**
75  * Set the log reporting level.
76  */
77 void
78 _eglSetLogLevel(EGLint level)
79 {
80    switch (level) {
81    case _EGL_FATAL:
82    case _EGL_WARNING:
83    case _EGL_INFO:
84    case _EGL_DEBUG:
85       _eglLockMutex(&logging.mutex);
86       logging.level = level;
87       _eglUnlockMutex(&logging.mutex);
88       break;
89    default:
90       break;
91    }
92 }
93
94
95 /**
96  * The default logger.  It prints the message to stderr.
97  */
98 static void
99 _eglDefaultLogger(EGLint level, const char *msg)
100 {
101    fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
102 }
103
104
105 /**
106  * Initialize the logging facility.
107  */
108 static void
109 _eglInitLogger(void)
110 {
111    const char *log_env;
112    EGLint i, level = -1;
113
114    if (logging.initialized)
115       return;
116
117    log_env = getenv("EGL_LOG_LEVEL");
118    if (log_env) {
119       for (i = 0; level_strings[i]; i++) {
120          if (_eglstrcasecmp(log_env, level_strings[i]) == 0) {
121             level = i;
122             break;
123          }
124       }
125    }
126    else {
127       level = FALLBACK_LOG_LEVEL;
128    }
129
130    logging.logger = _eglDefaultLogger;
131    logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
132    logging.initialized = EGL_TRUE;
133
134    /* it is fine to call _eglLog now */
135    if (log_env && level < 0) {
136       _eglLog(_EGL_WARNING,
137               "Unrecognized EGL_LOG_LEVEL environment variable value. "
138               "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
139               "Got \"%s\". Falling back to \"%s\".",
140               log_env, level_strings[FALLBACK_LOG_LEVEL]);
141    }
142 }
143
144
145 /**
146  * Log a message with message logger.
147  * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
148  */
149 void
150 _eglLog(EGLint level, const char *fmtStr, ...)
151 {
152    va_list args;
153    char msg[MAXSTRING];
154
155    /* one-time initialization; a little race here is fine */
156    if (!logging.initialized)
157       _eglInitLogger();
158    if (level > logging.level || level < 0)
159       return;
160
161    _eglLockMutex(&logging.mutex);
162
163    if (logging.logger) {
164       va_start(args, fmtStr);
165       vsnprintf(msg, MAXSTRING, fmtStr, args);
166       va_end(args);
167
168       logging.logger(level, msg);
169       logging.num_messages++;
170    }
171
172    _eglUnlockMutex(&logging.mutex);
173
174    if (level == _EGL_FATAL)
175       exit(1); /* or abort()? */
176 }