egl: Improve logging facility.
authorChia-I Wu <olvaffe@gmail.com>
Tue, 29 Sep 2009 08:11:06 +0000 (16:11 +0800)
committerBrian Paul <brianp@vmware.com>
Tue, 13 Oct 2009 18:00:37 +0000 (12:00 -0600)
Add _eglSetLogger and _eglSetLogLevel to allow drivers to change the
message logger or report level.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
src/egl/main/eglglobals.c
src/egl/main/egllog.c
src/egl/main/egllog.h

index 30d9fe97b4e10bba380a15fa9d4d42999a9a4101..443d0f072cfee087ea259d0fcca1f1d688f54b60 100644 (file)
@@ -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
    },
 };
 
index 23eb523eebe462e776a5cdbe03740fc1e7341228..11a9bf7275cd3dcf76bb34a50003318b3ec75d4d 100644 (file)
 #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"
+#define FALLBACK_LOG_LEVEL _EGL_WARNING
 
-static EGLint ReportingLevel = -1;
 
+static struct {
+   _EGLMutex mutex;
 
-static void
-log_level_initialize(void)
+   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;
-   }
-   else if (strcasecmp(log_env, "fatal") == 0) {
-      ReportingLevel = _EGL_FATAL;
-   }
-   else if (strcasecmp(log_env, "warning") == 0) {
-      ReportingLevel = _EGL_WARNING;
+   _eglLockMutex(&logging.mutex);
+
+   if (logging.logger != logger) {
+      logging.logger = logger;
+
+      num_messages = logging.num_messages;
+      logging.num_messages = 0;
    }
-   else if (strcasecmp(log_env, "info") == 0) {
-      ReportingLevel = _EGL_INFO;
+
+   _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;
    }
-   else if (strcasecmp(log_env, "debug") == 0) {
-      ReportingLevel = _EGL_DEBUG;
+}
+
+
+/**
+ * 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 {
-      fprintf(stderr, "Unrecognized EGL_LOG_LEVEL environment variable value. "
+      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\".\n",
-              log_env, FALLBACK_LOG_LEVEL_STR);
-      ReportingLevel = FALLBACK_LOG_LEVEL;
+              "Got \"%s\". Falling back to \"%s\".",
+              log_env, level_strings[FALLBACK_LOG_LEVEL]);
    }
 }
 
 
 /**
- * Log a message to stderr.
+ * 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()? */
 }
index 2fa352f155d43bad7d98497855fbad5177905fe4..83c8bb72a6e5580b96c91cb99565da5e55361f29 100644 (file)
@@ -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, ...);