egllog.c revision 4a49301e
14a49301eSmrg/**
24a49301eSmrg * Logging facility for debug/info messages.
34a49301eSmrg * _EGL_FATAL messages are printed to stderr
44a49301eSmrg * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
54a49301eSmrg */
64a49301eSmrg
74a49301eSmrg
84a49301eSmrg#include <stdarg.h>
94a49301eSmrg#include <stdio.h>
104a49301eSmrg#include <stdlib.h>
114a49301eSmrg#include <string.h>
124a49301eSmrg
134a49301eSmrg#include "egllog.h"
144a49301eSmrg#include "eglmutex.h"
154a49301eSmrg
164a49301eSmrg#define MAXSTRING 1000
174a49301eSmrg#define FALLBACK_LOG_LEVEL _EGL_WARNING
184a49301eSmrg
194a49301eSmrg
204a49301eSmrgstatic struct {
214a49301eSmrg   _EGLMutex mutex;
224a49301eSmrg
234a49301eSmrg   EGLBoolean initialized;
244a49301eSmrg   EGLint level;
254a49301eSmrg   _EGLLogProc logger;
264a49301eSmrg   EGLint num_messages;
274a49301eSmrg} logging = {
284a49301eSmrg   _EGL_MUTEX_INITIALIZER,
294a49301eSmrg   EGL_FALSE,
304a49301eSmrg   FALLBACK_LOG_LEVEL,
314a49301eSmrg   NULL,
324a49301eSmrg   0
334a49301eSmrg};
344a49301eSmrg
354a49301eSmrgstatic const char *level_strings[] = {
364a49301eSmrg   /* the order is important */
374a49301eSmrg   "fatal",
384a49301eSmrg   "warning",
394a49301eSmrg   "info",
404a49301eSmrg   "debug",
414a49301eSmrg   NULL
424a49301eSmrg};
434a49301eSmrg
444a49301eSmrg
454a49301eSmrg/**
464a49301eSmrg * Set the function to be called when there is a message to log.
474a49301eSmrg * Note that the function will be called with an internal lock held.
484a49301eSmrg * Recursive logging is not allowed.
494a49301eSmrg */
504a49301eSmrgvoid
514a49301eSmrg_eglSetLogProc(_EGLLogProc logger)
524a49301eSmrg{
534a49301eSmrg   EGLint num_messages = 0;
544a49301eSmrg
554a49301eSmrg   _eglLockMutex(&logging.mutex);
564a49301eSmrg
574a49301eSmrg   if (logging.logger != logger) {
584a49301eSmrg      logging.logger = logger;
594a49301eSmrg
604a49301eSmrg      num_messages = logging.num_messages;
614a49301eSmrg      logging.num_messages = 0;
624a49301eSmrg   }
634a49301eSmrg
644a49301eSmrg   _eglUnlockMutex(&logging.mutex);
654a49301eSmrg
664a49301eSmrg   if (num_messages)
674a49301eSmrg      _eglLog(_EGL_DEBUG,
684a49301eSmrg              "New logger installed. "
694a49301eSmrg              "Messages before the new logger might not be available.");
704a49301eSmrg}
714a49301eSmrg
724a49301eSmrg
734a49301eSmrg/**
744a49301eSmrg * Set the log reporting level.
754a49301eSmrg */
764a49301eSmrgvoid
774a49301eSmrg_eglSetLogLevel(EGLint level)
784a49301eSmrg{
794a49301eSmrg   switch (level) {
804a49301eSmrg   case _EGL_FATAL:
814a49301eSmrg   case _EGL_WARNING:
824a49301eSmrg   case _EGL_INFO:
834a49301eSmrg   case _EGL_DEBUG:
844a49301eSmrg      _eglLockMutex(&logging.mutex);
854a49301eSmrg      logging.level = level;
864a49301eSmrg      _eglUnlockMutex(&logging.mutex);
874a49301eSmrg      break;
884a49301eSmrg   default:
894a49301eSmrg      break;
904a49301eSmrg   }
914a49301eSmrg}
924a49301eSmrg
934a49301eSmrg
944a49301eSmrg/**
954a49301eSmrg * The default logger.  It prints the message to stderr.
964a49301eSmrg */
974a49301eSmrgstatic void
984a49301eSmrg_eglDefaultLogger(EGLint level, const char *msg)
994a49301eSmrg{
1004a49301eSmrg   fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
1014a49301eSmrg}
1024a49301eSmrg
1034a49301eSmrg
1044a49301eSmrg/**
1054a49301eSmrg * Initialize the logging facility.
1064a49301eSmrg */
1074a49301eSmrgstatic void
1084a49301eSmrg_eglInitLogger(void)
1094a49301eSmrg{
1104a49301eSmrg   const char *log_env;
1114a49301eSmrg   EGLint i, level = -1;
1124a49301eSmrg
1134a49301eSmrg   if (logging.initialized)
1144a49301eSmrg      return;
1154a49301eSmrg
1164a49301eSmrg   log_env = getenv("EGL_LOG_LEVEL");
1174a49301eSmrg   if (log_env) {
1184a49301eSmrg      for (i = 0; level_strings[i]; i++) {
1194a49301eSmrg         if (strcasecmp(log_env, level_strings[i]) == 0) {
1204a49301eSmrg            level = i;
1214a49301eSmrg            break;
1224a49301eSmrg         }
1234a49301eSmrg      }
1244a49301eSmrg   }
1254a49301eSmrg   else {
1264a49301eSmrg      level = FALLBACK_LOG_LEVEL;
1274a49301eSmrg   }
1284a49301eSmrg
1294a49301eSmrg   logging.logger = _eglDefaultLogger;
1304a49301eSmrg   logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
1314a49301eSmrg   logging.initialized = EGL_TRUE;
1324a49301eSmrg
1334a49301eSmrg   /* it is fine to call _eglLog now */
1344a49301eSmrg   if (log_env && level < 0) {
1354a49301eSmrg      _eglLog(_EGL_WARNING,
1364a49301eSmrg              "Unrecognized EGL_LOG_LEVEL environment variable value. "
1374a49301eSmrg              "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
1384a49301eSmrg              "Got \"%s\". Falling back to \"%s\".",
1394a49301eSmrg              log_env, level_strings[FALLBACK_LOG_LEVEL]);
1404a49301eSmrg   }
1414a49301eSmrg}
1424a49301eSmrg
1434a49301eSmrg
1444a49301eSmrg/**
1454a49301eSmrg * Log a message with message logger.
1464a49301eSmrg * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
1474a49301eSmrg */
1484a49301eSmrgvoid
1494a49301eSmrg_eglLog(EGLint level, const char *fmtStr, ...)
1504a49301eSmrg{
1514a49301eSmrg   va_list args;
1524a49301eSmrg   char msg[MAXSTRING];
1534a49301eSmrg
1544a49301eSmrg   /* one-time initialization; a little race here is fine */
1554a49301eSmrg   if (!logging.initialized)
1564a49301eSmrg      _eglInitLogger();
1574a49301eSmrg   if (level > logging.level || level < 0)
1584a49301eSmrg      return;
1594a49301eSmrg
1604a49301eSmrg   _eglLockMutex(&logging.mutex);
1614a49301eSmrg
1624a49301eSmrg   if (logging.logger) {
1634a49301eSmrg      va_start(args, fmtStr);
1644a49301eSmrg      vsnprintf(msg, MAXSTRING, fmtStr, args);
1654a49301eSmrg      va_end(args);
1664a49301eSmrg
1674a49301eSmrg      logging.logger(level, msg);
1684a49301eSmrg      logging.num_messages++;
1694a49301eSmrg   }
1704a49301eSmrg
1714a49301eSmrg   _eglUnlockMutex(&logging.mutex);
1724a49301eSmrg
1734a49301eSmrg   if (level == _EGL_FATAL)
1744a49301eSmrg      exit(1); /* or abort()? */
1754a49301eSmrg}
176