egl: Improve logging facility.
Add _eglSetLogger and _eglSetLogLevel to allow drivers to change the message logger or report level. Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
This commit is contained in:
@@ -18,9 +18,10 @@ struct _egl_global _eglGlobal =
|
||||
0, /* NumDrivers */
|
||||
{ NULL }, /* Drivers */
|
||||
2, /* NumAtExitCalls */
|
||||
{ /* AtExitCalls */
|
||||
_eglFiniDisplay,
|
||||
_eglUnloadDrivers
|
||||
{
|
||||
/* default AtExitCalls, called in reverse order */
|
||||
_eglUnloadDrivers, /* always called last */
|
||||
_eglFiniDisplay
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -9,47 +9,140 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "egllog.h"
|
||||
#include "eglmutex.h"
|
||||
|
||||
#define MAXSTRING 1000
|
||||
#define FALLBACK_LOG_LEVEL _EGL_WARNING
|
||||
#define FALLBACK_LOG_LEVEL_STR "warning"
|
||||
|
||||
static EGLint ReportingLevel = -1;
|
||||
#define FALLBACK_LOG_LEVEL _EGL_WARNING
|
||||
|
||||
|
||||
static void
|
||||
log_level_initialize(void)
|
||||
static struct {
|
||||
_EGLMutex mutex;
|
||||
|
||||
EGLBoolean initialized;
|
||||
EGLint level;
|
||||
_EGLLogProc logger;
|
||||
EGLint num_messages;
|
||||
} logging = {
|
||||
_EGL_MUTEX_INITIALIZER,
|
||||
EGL_FALSE,
|
||||
FALLBACK_LOG_LEVEL,
|
||||
NULL,
|
||||
0
|
||||
};
|
||||
|
||||
static const char *level_strings[] = {
|
||||
/* the order is important */
|
||||
"fatal",
|
||||
"warning",
|
||||
"info",
|
||||
"debug",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the function to be called when there is a message to log.
|
||||
* Note that the function will be called with an internal lock held.
|
||||
* Recursive logging is not allowed.
|
||||
*/
|
||||
void
|
||||
_eglSetLogProc(_EGLLogProc logger)
|
||||
{
|
||||
char *log_env = getenv("EGL_LOG_LEVEL");
|
||||
EGLint num_messages = 0;
|
||||
|
||||
if (log_env == NULL) {
|
||||
ReportingLevel = FALLBACK_LOG_LEVEL;
|
||||
_eglLockMutex(&logging.mutex);
|
||||
|
||||
if (logging.logger != logger) {
|
||||
logging.logger = logger;
|
||||
|
||||
num_messages = logging.num_messages;
|
||||
logging.num_messages = 0;
|
||||
}
|
||||
else if (strcasecmp(log_env, "fatal") == 0) {
|
||||
ReportingLevel = _EGL_FATAL;
|
||||
}
|
||||
else if (strcasecmp(log_env, "warning") == 0) {
|
||||
ReportingLevel = _EGL_WARNING;
|
||||
}
|
||||
else if (strcasecmp(log_env, "info") == 0) {
|
||||
ReportingLevel = _EGL_INFO;
|
||||
}
|
||||
else if (strcasecmp(log_env, "debug") == 0) {
|
||||
ReportingLevel = _EGL_DEBUG;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Unrecognized EGL_LOG_LEVEL environment variable value. "
|
||||
"Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
|
||||
"Got \"%s\". Falling back to \"%s\".\n",
|
||||
log_env, FALLBACK_LOG_LEVEL_STR);
|
||||
ReportingLevel = FALLBACK_LOG_LEVEL;
|
||||
|
||||
_eglUnlockMutex(&logging.mutex);
|
||||
|
||||
if (num_messages)
|
||||
_eglLog(_EGL_DEBUG,
|
||||
"New logger installed. "
|
||||
"Messages before the new logger might not be available.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the log reporting level.
|
||||
*/
|
||||
void
|
||||
_eglSetLogLevel(EGLint level)
|
||||
{
|
||||
switch (level) {
|
||||
case _EGL_FATAL:
|
||||
case _EGL_WARNING:
|
||||
case _EGL_INFO:
|
||||
case _EGL_DEBUG:
|
||||
_eglLockMutex(&logging.mutex);
|
||||
logging.level = level;
|
||||
_eglUnlockMutex(&logging.mutex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a message to stderr.
|
||||
* The default logger. It prints the message to stderr.
|
||||
*/
|
||||
static void
|
||||
_eglDefaultLogger(EGLint level, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the logging facility.
|
||||
*/
|
||||
static void
|
||||
_eglInitLogger(void)
|
||||
{
|
||||
const char *log_env;
|
||||
EGLint i, level = -1;
|
||||
|
||||
if (logging.initialized)
|
||||
return;
|
||||
|
||||
log_env = getenv("EGL_LOG_LEVEL");
|
||||
if (log_env) {
|
||||
for (i = 0; level_strings[i]; i++) {
|
||||
if (strcasecmp(log_env, level_strings[i]) == 0) {
|
||||
level = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
level = FALLBACK_LOG_LEVEL;
|
||||
}
|
||||
|
||||
logging.logger = _eglDefaultLogger;
|
||||
logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
|
||||
logging.initialized = EGL_TRUE;
|
||||
|
||||
/* it is fine to call _eglLog now */
|
||||
if (log_env && level < 0) {
|
||||
_eglLog(_EGL_WARNING,
|
||||
"Unrecognized EGL_LOG_LEVEL environment variable value. "
|
||||
"Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
|
||||
"Got \"%s\". Falling back to \"%s\".",
|
||||
log_env, level_strings[FALLBACK_LOG_LEVEL]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a message with message logger.
|
||||
* \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
|
||||
*/
|
||||
void
|
||||
@@ -57,40 +150,26 @@ _eglLog(EGLint level, const char *fmtStr, ...)
|
||||
{
|
||||
va_list args;
|
||||
char msg[MAXSTRING];
|
||||
const char *levelStr;
|
||||
static int log_level_initialized = 0;
|
||||
|
||||
if (!log_level_initialized) {
|
||||
log_level_initialize();
|
||||
log_level_initialized = 1;
|
||||
}
|
||||
/* one-time initialization; a little race here is fine */
|
||||
if (!logging.initialized)
|
||||
_eglInitLogger();
|
||||
if (level > logging.level || level < 0)
|
||||
return;
|
||||
|
||||
if (level <= ReportingLevel) {
|
||||
switch (level) {
|
||||
case _EGL_FATAL:
|
||||
levelStr = "Fatal";
|
||||
break;
|
||||
case _EGL_WARNING:
|
||||
levelStr = "Warning";
|
||||
break;
|
||||
case _EGL_INFO:
|
||||
levelStr = "Info";
|
||||
break;
|
||||
case _EGL_DEBUG:
|
||||
levelStr = "Debug";
|
||||
break;
|
||||
default:
|
||||
levelStr = "";
|
||||
}
|
||||
_eglLockMutex(&logging.mutex);
|
||||
|
||||
if (logging.logger) {
|
||||
va_start(args, fmtStr);
|
||||
vsnprintf(msg, MAXSTRING, fmtStr, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stderr, "libEGL %s: %s\n", levelStr, msg);
|
||||
|
||||
if (level == _EGL_FATAL) {
|
||||
exit(1); /* or abort()? */
|
||||
}
|
||||
logging.logger(level, msg);
|
||||
logging.num_messages++;
|
||||
}
|
||||
|
||||
_eglUnlockMutex(&logging.mutex);
|
||||
|
||||
if (level == _EGL_FATAL)
|
||||
exit(1); /* or abort()? */
|
||||
}
|
||||
|
@@ -9,6 +9,17 @@
|
||||
#define _EGL_DEBUG 3 /* useful info for debugging */
|
||||
|
||||
|
||||
typedef void (*_EGLLogProc)(EGLint level, const char *msg);
|
||||
|
||||
|
||||
extern void
|
||||
_eglSetLogProc(_EGLLogProc logger);
|
||||
|
||||
|
||||
extern void
|
||||
_eglSetLogLevel(EGLint level);
|
||||
|
||||
|
||||
extern void
|
||||
_eglLog(EGLint level, const char *fmtStr, ...);
|
||||
|
||||
|
Reference in New Issue
Block a user