Eina Logging

EFL uses a common method to log error messages, called Eina_Log, which allows you to adjust the verbosity of the logs using environment variables.

The Eina_Log module provides logging facilities for libraries and applications. It provides colored logging, basic logging levels (error, warning, debug, info, critical) and logging domains, or loggers. For those unfamiliar with this term, it offers a way to separate a set of log messages into a specific context (e.g. a module) and provides a way of controlling this set as a whole.

Available Log Levels

Level Number Macro
Critical 0 EINA_LOG_CRIT()
Error 1 EINA_LOG_ERR()
Warning 2 EINA_LOG_WARN()
Info 3 EINA_LOG_INFO()
Debug 4 EINA_LOG_DBG()

The log level is used to control which messages should appear. It specifies the lowest level that should be displayed, i.e. a message with level 2 being logged on a domain with level set to 3 would be displayed while a message with level 4 wouldn't.

Setting the Log Level

Eina provides eina_log_print(), a standard function to manage all logging messages. This function may be called directly or using helper macros including EINA_LOG_DBG(), EINA_LOG_ERR() or those that take a specific domain as an argument as with EINA_LOG_DOM_DBG() and EINA_LOG_DOM_ERR(). Internally, eina_log_print() will call the function defined with eina_log_print_cb_set(), which defaults to eina_log_print_cb_stderr() but may be changed to do whatever you need such as networking or syslog logging.

The logging system is thread-safe once initialized with eina_log_threads_enable(). The thread that calls this function first is considered "main thread" and other threads will have their thread ID (pthread_self()) printed in the log message so it is easy to detect from where the messages are coming.

The different logging levels serve to customize the amount of debugging information and may be used to automatically call abort() once a message of a given level is printed. This is controlled by the environment variable EINA_LOG_ABORT and the level to be considered critical with EINA_LOG_ABORT_LEVEL. These can be changed with eina_log_abort_on_critical_set() and eina_log_abort_on_critical_level_set().

The default maximum level to print is defined by the environment variable EINA_LOG_LEVEL but may be set per-domain with EINA_LOG_LEVELS. It will default to EINA_LOG_ERR. This can be changed with eina_log_level_set().

To use the log system Eina must be initialized with eina_init() and later shut down with eina_shutdown().

Controlling Print Callbacks

The log module allows the user to change the way eina_log_print() displays messages. It suffices to pass to eina_log_print_cb_set() the function used to display the message. That function must be of type #Eina_Log_Print_Cb. As custom data can be passed to that callback, customized messages can be displayed.

It is suggested to not use __FILE__, __FUNCTION__ or __LINE__ when writing that callback, but when defining macros like EINA_LOG_ERR() and others.

Logging Example

The following example, available for download from the Enlightenment Project git repository, demonstrates the control of logging from within an application.

#define EFL_EO_API_SUPPORT 1
#define EFL_BETA_API_SUPPORT 1
 
#include <stdio.h>
 
#include <Eina.h>
#include <Efl_Core.h>
 
/*
 * Efl Core Log examples.
 *
 * This demo shows how to log at various levels and to change what log is shown.
 * You can also use a custom log printer in your app as shown in _log_custom.
 */
 
static double
_divide(int num, int denom)
{
   if (denom == 0)
     EINA_LOG_CRIT("Attempt to divide by 0\n");
   else
     {
        if (denom < 0)
          EINA_LOG_WARN("Possible undesirable effect, divide by negative number");
 
        double ret = ((double) num / denom);
        EINA_LOG_INFO("%d / %d = %f\n", num, denom, ret);
        return ret;
     }
 
   return -1;
}
 
static void
_divides()
{
   _divide(5, 1);
   _divide(5, -1);
   _divide(5, 0);
}
 
static void
_log_levels()
{
   printf("Executing with default logging\n");
   _divides();
 
   eina_log_level_set(EINA_LOG_LEVEL_WARN);
   printf("Executing with WARN level\n"); // same as EINA_LOG_LEVEL = 2
   _divides();
 
   eina_log_level_set(EINA_LOG_LEVEL_INFO);
   printf("Executing with INFO on\n"); // same as EINA_LOG_LEVEL = 3
   _divides();
}
 
void _print_cb(const Eina_Log_Domain *domain EINA_UNUSED, Eina_Log_Level level,
              const char *file, const char *fnc, int line,
              const char *fmt, void *data EINA_UNUSED, va_list args)
{
   fprintf(stdout, "LOG %d <%s (%s:%d)> ", level, fnc, file, line);
   vfprintf(stdout, fmt, args);
   putc('\n', stdout);
}
 
static void
_log_custom()
{
   printf("Executing with custom log printer\n");
   eina_log_print_cb_set(_print_cb, NULL);
   _divides();
}
 
EAPI_MAIN void
efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
{
   _log_levels();
   _log_custom();
 
   efl_exit(0);
}
EFL_MAIN()

Further Reading

Error Logging
A reference for controlling log levels at runtime.