Log Tutorial

# Introduction

The Eina Log module provides logging facilities for libraries and applications. It provides colored logging, basic logging levels (error, warning, debug, info, critical) and loggers - called logging domains - which will be covered in next sections.

# Basic Usage

Log messages can be displayed using the following macros:

- EINA_LOG_ERR(),
- EINA_LOG_INFO(),
- EINA_LOG_WARN(),
- EINA_LOG_DBG().

Here is an example:

//Compile with:
//gcc -Wall -o eina_log_02 eina_log_02.c `pkg-config --cflags --libs eina`
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
void test(int i)
{
EINA_LOG_DBG("Entering test");
if (i < 0)
{
EINA_LOG_ERR("Argument is negative");
return;
}
EINA_LOG_INFO("argument non negative");
EINA_LOG_DBG("Exiting test");
}
int main(void)
{
if (!eina_init())
{
printf("log during the initialization of Eina_Log module\n");
return EXIT_FAILURE;
}
eina_log_level_set(EINA_LOG_LEVEL_DBG);
test(-1);
test(0);
eina_shutdown();
return EXIT_SUCCESS;
}
Eina.h
Eina Utility library.
EINA_LOG_DBG
#define EINA_LOG_DBG(fmt,...)
Logs a message with level DEBUG on the default domain with the specified format.
Definition eina_log.h:400
eina_log_level_set
EINA_API void eina_log_level_set(int level)
Sets the default log level.
Definition eina_log.c:1733
EINA_LOG_ERR
#define EINA_LOG_ERR(fmt,...)
Logs a message with level ERROR on the default domain with the specified format.
Definition eina_log.h:376
EINA_LOG_INFO
#define EINA_LOG_INFO(fmt,...)
Logs a message with level INFO on the default domain with the specified format.
Definition eina_log.h:384
EINA_LOG_LEVEL_DBG
@ EINA_LOG_LEVEL_DBG
Debug log level.
Definition eina_log.h:461
eina_shutdown
EINA_API int eina_shutdown(void)
Shuts down the Eina library.
Definition eina_main.c:379
eina_init
EINA_API int eina_init(void)
Initializes the Eina library.
Definition eina_main.c:291

If you compiled Eina without debug mode, execution will yield only one log message, which is "argument is negative".

Here we introduce the concept of logging domains (or loggers), which might already be familiar to readers. It is basically a way to separate a set of log messages into a context (e.g. a module) and provide a way of controlling this set as a whole.

For example, suppose you have 3 different modules in your application and you want to get logging only from one of them (e.g. create some sort of filter). For achieving that, all you need to do is create a logging domain for each module so that all logging inside a module can be considered as a whole.

Logging domains are specified by a name, color applied to the name and the level. The first two (name and color) are set through code, that is, inside your application/module/library.

The level is used for controlling which messages should appear. It specifies the lowest level that should be displayed (e.g. a message with level 11 being logged on a domain with level set to 10 would be displayed, while a message with level 9 wouldn't).

The domain level is set during runtime (in contrast with the name and color) through the environment variable EINA_LOG_LEVELS. This variable expects a list in the form domain_name1:level1,domain_name2:level2,... . For example:

    EINA_LOG_LEVELS=mymodule1:5,mymodule2:2,mymodule3:0 ./myapp

This line would set mymodule1 level to 5, mymodule2 level to 2 and mymodule3 level to 0.

There's also a global logger to which EINA_LOG_(ERR, DBG, INFO, CRIT, WARN) macros do log on. It is a logger that is created internally by Eina Log with an empty name and can be used for general logging (where logging domains do not apply).

Since this global logger doesn't have a name, you can't set its level through EINA_LOG_LEVELS variable. Here we introduce a second environment variable that is a bit more special: EINA_LOG_LEVEL.

This variable specifies the level of the global logging domain and the level of domains that haven't been set through EINA_LOG_LEVELS. Here's an example:

    EINA_LOG_LEVEL=3 EINA_LOG_LEVELS=module1:10,module3:2 ./myapp

Supposing you have modules named "module1", "module2" and "module3", this line would result in module1 with level 10, module2 with level 3 and module3 with level 2. Note that module2's level wasn't specified, so it's level is set to the global level. This way we can easily apply filters to multiple domains with only one parameter (EINA_LOG_LEVEL=num).

The global level (EINA_LOG_LEVEL) can also be set through code, using eina_log_level_set() function.

While developing your libraries or applications, you may notice that EINA_LOG_DOM_(ERR, DBG, INFO, CRIT, WARN) macros also print out messages from eina itself. Here we introduce another environment variable that is a bit more special: EINA_LOG_LEVELS_GLOB.

This variable allows you to disable the logging of any/all code in eina itself. This is useful when developing your libraries or applications so that you can see your own domain's messages easier without having to sift through a lot of internal eina debug messages. Here's an example:

    EINA_LOG_LEVEL=3 EINA_LOG_LEVELS_GLOB=eina_*:0 ./myapp

This will disable eina_log output from all internal eina code thus allowing you to see your own domain messages easier.

# Advanced usage of print callbacks

The log module allows the user to change the way eina_log_print() displays the 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 a custom data can be passed to that callback, powerful display messages can be displayed.

It is suggested to not use FILE, func or LINE when writing that callback, but when defining macros (like EINA_LOG_ERR() and other macros).

Here is an example of custom callback, whose behavior can be changed at runtime:

//Compile with:
//gcc -Wall -o eina_log_03 eina_log_03.c `pkg-config --cflags --libs eina`
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
#define log(fmt, ...) \
eina_log_print(EINA_LOG_LEVEL_ERR, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
typedef struct _Data Data;
struct _Data
{
int to_stderr;
};
void print_cb(const Eina_Log_Domain *domain,
Eina_Log_Level level EINA_UNUSED,
const char *file,
const char *fnc,
int line,
const char *fmt,
void *data,
va_list args)
{
Data *d;
FILE *output;
char *str;
d = (Data*)data;
if (d->to_stderr)
{
output = stderr;
str = "stderr";
}
else
{
output = stdout;
str = "stdout";
}
fprintf(output, "%s:%s:%s (%d) %s: ",
domain->domain_str, file, fnc, line, str);
vfprintf(output, fmt, args);
putc('\n', output);
}
void test(Data *data, int i)
{
if (i < 0)
data->to_stderr = 0;
else
data->to_stderr = 1;
EINA_LOG_INFO("Log message...");
}
int main(void)
{
Data data;
if (!eina_init())
{
printf("log during the initialization of Eina_Log module\n");
return EXIT_FAILURE;
}
eina_log_print_cb_set(print_cb, &data);
test(&data, -1);
test(&data, 0);
eina_shutdown();
return EXIT_SUCCESS;
}
eina_log_print_cb_set
EINA_API void eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data)
Sets logging method to use.
Definition eina_log.c:1715
Eina_Log_Level
enum _Eina_Log_Level Eina_Log_Level
List of available logging levels.
Eina_Log_Domain
struct _Eina_Log_Domain Eina_Log_Domain
The domain used for logging.
Definition eina_log.h:407
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition eina_types.h:339
_Eina_Log_Domain::domain_str
const char * domain_str
Formatted string with color to print.
Definition eina_log.h:416