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