Log Tutorial

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files
- Examples

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 on 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;
}
test(-1);
test(0);
eina_shutdown();
return EXIT_SUCCESS;
}

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 on 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, FUNCTION 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__, __FUNCTION__, __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;
}