Hello,
This patch contains an initial implementation of logging domains for eina
error module. Please be aware that this a very rough version and there are
lots of things that must be improved.
The patch is also with lots of fprintf's that I was using for debugging,
please ignore them. When we're ready to apply, I'll cleanup everything.
For testing the new domain features, I added three unit tests and fixed
eina_rectangle test that was preventing me from building eina_error test.
You can also see examples of how logging domains will be used on these tests
(registering, logging, unregistering).
There are also a few things that I wasn't sure and I'd really appreciate
some help:
- Logging priorities (EINA_ERROR_LEVEL and domain level): is the code
with the correct priorities? (lines 1064 to 1071 of eina_error.c)
- Domain slots: from the tests results, it looks like the slot code is
working, but I'm not sure it doesn't have a case which will break
- Levels: is INT32_MAX a good value for the UNKNOWN level (which is
basically just a placeholder. Whenever you log and it's UNKNOWN, your domain
will use global level)
- Old API: I redirected the old API to a global logger which is
registered on eina_error_init(). Is this OK?
--
André Dieb Martins
Embedded Systems and Pervasive Computing Lab (Embedded)
Electrical Engineering Department (DEE)
Center of Electrical Engineering and Informatics (CEEI)
Federal University of Campina Grande (UFCG)
Blog: http://genuinepulse.blogspot.com/
Index: src/tests/eina_test_rectangle.c
===================================================================
--- src/tests/eina_test_rectangle.c (revision 41406)
+++ src/tests/eina_test_rectangle.c (working copy)
@@ -36,7 +36,7 @@
eina_rectangle_init();
- pool = eina_rectangle_pool_add(256, 256);
+ pool = eina_rectangle_pool_new(256, 256);
fail_if(pool == NULL);
eina_rectangle_pool_data_set(pool, rects);
@@ -66,7 +66,7 @@
fail_if(eina_rectangle_pool_request(pool, 16, 16) == NULL);
- eina_rectangle_pool_delete(pool);
+ eina_rectangle_pool_free(pool);
eina_rectangle_shutdown();
}
Index: src/tests/eina_test_error.c
===================================================================
--- src/tests/eina_test_error.c (revision 41406)
+++ src/tests/eina_test_error.c (working copy)
@@ -77,10 +77,85 @@
}
END_TEST
+START_TEST(eina_error_domains_macros)
+{
+ eina_error_init();
+
+ Eina_Error_Domain_Index i = eina_error_domain_register("MyDomain", EINA_COLOR_GREEN);
+ fail_if(i == -1);
+
+ EINA_ERROR_PERR_DOM(i, "An error\n");
+ EINA_ERROR_PINFO_DOM(i, "An info\n");
+ EINA_ERROR_PWARN_DOM(i, "A warning\n");
+ EINA_ERROR_PDBG_DOM(i, "A debug\n");
+
+ eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_registry)
+{
+ eina_error_init();
+
+ int i;
+ Eina_Error_Domain_Index idx[50];
+
+ for (i = 0; i < 50; i++)
+ {
+ idx[i] = eina_error_domain_register("Test", EINA_COLOR_GREEN);
+ fail_if(idx[i] == -1);
+ }
+
+ for (i = 0; i < 50; i++)
+ eina_error_domain_unregister(idx[i]);
+
+ eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_slot_reuse)
+{
+ eina_error_init();
+
+ // Create 9 domains
+ Eina_Error_Domain_Index idx[9];
+ int i;
+
+ for (i = 0; i < 9; i++)
+ {
+ idx[i] = eina_error_domain_register("Test1", EINA_COLOR_GREEN);
+ fail_if(idx[i] == -1);
+ }
+
+ // Slot 0 by default contains the global logger. The above code created
+ // domains for slots indexes from 1 to 9.
+ //
+ // The global logger allocated the first 8 initial slots. The 8th domain
+ // registered on the for loop will create 8 more slots.
+ //
+ // Test will just unregister a domain between 1 and 9 and assure that a new
+ // domain register will be placed on the available slot and not at the end.
+
+ Eina_Error_Domain_Index removed = idx[5];
+ eina_error_domain_unregister(removed);
+
+ Eina_Error_Domain_Index new = eina_error_domain_register("Test1", EINA_COLOR_GREEN);
+
+ // Check for slot reuse
+ fail_if(new != idx[5]);
+
+ eina_error_shutdown();
+}
+END_TEST
+
+
void
eina_test_error(TCase *tc)
{
tcase_add_test(tc, eina_error_init_shutdown);
tcase_add_test(tc, eina_error_errno);
tcase_add_test(tc, eina_error_macro);
+ tcase_add_test(tc, eina_error_domains_macros);
+ tcase_add_test(tc, eina_error_domains_registry);
+ tcase_add_test(tc, eina_error_domains_slot_reuse);
}
Index: src/include/eina_error.h
===================================================================
--- src/include/eina_error.h (revision 41406)
+++ src/include/eina_error.h (working copy)
@@ -20,9 +20,19 @@
#define EINA_ERROR_H_
#include <stdarg.h>
+#include <stdint.h>
#include "eina_types.h"
+#include "eina_inlist.h"
+#define EINA_COLOR_RED "\033[31;1m"
+#define EINA_COLOR_BLUE "\033[34;1m"
+#define EINA_COLOR_GREEN "\033[32;1m"
+#define EINA_COLOR_YELLOW "\033[33;1m"
+#define EINA_COLOR_WHITE "\033[37;1m"
+#define EINA_COLOR_LIGHTBLUE "\033[36;1m"
+#define EINA_COLOR_NOTHING "\033[0m"
+
/**
* @addtogroup Eina_Tools_Group Tools
*
@@ -35,6 +45,18 @@
* @{
*/
+#define EINA_ERROR_PERR_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_ERR, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PINFO_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_INFO, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PDBG_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PWARN_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_WARN, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
/**
* @def EINA_ERROR_PERR(fmt, ...)
* Print the error message described with the formatted string @a fmt
@@ -71,6 +93,32 @@
#define EINA_ERROR_PDBG(fmt, ...) \
eina_error_print(EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+typedef struct _Eina_Error_Domain Eina_Error_Domain;
+typedef struct _Eina_Error_Domain_Level_Pending Eina_Error_Domain_Level_Pending;
+typedef int Eina_Error_Domain_Index;
+
+struct _Eina_Error_Domain
+{
+ EINA_INLIST;
+
+ unsigned int level; /**< Max level to log */
+ const char *name; /**< Domain name */
+ const char *domain_str; /**< Formatted string with color to print */
+ const char *color;
+
+ /* Private */
+ int deleted : 1; /**< Flags deletion of domain, a free slot */
+};
+
+struct _Eina_Error_Domain_Level_Pending
+{
+ EINA_INLIST;
+
+ const char *name;
+ unsigned int level;
+};
+
+
/**
* @typedef Eina_Error_Level
* List of available error levels.
@@ -86,7 +134,8 @@
EINA_ERROR_LEVEL_WARN, /**< Warning error level */
EINA_ERROR_LEVEL_INFO, /**< Information error level */
EINA_ERROR_LEVEL_DBG, /**< Debug error level */
- EINA_ERROR_LEVELS /**< Count of error level */
+ EINA_ERROR_LEVELS, /**< Count of error level */
+ EINA_ERROR_LEVEL_UNKNOWN = INT32_MAX
} Eina_Error_Level;
/**
@@ -95,6 +144,7 @@
*/
typedef int Eina_Error;
+
/**
* @typedef Eina_Error_Print_Cb
* Type for print callbacks.
@@ -103,6 +153,10 @@
const char *fnc, int line, const char *fmt, void *data,
va_list args);
+typedef void (*Eina_Error_Dom_Print_Cb)(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file,
+ const char *fnc, int line, const char *fmt, void *data,
+ va_list args);
+
/**
* @var EINA_ERROR_OUT_OF_MEMORY
* Error identifier corresponding to a lack of memory.
@@ -129,6 +183,13 @@
EAPI void eina_error_print_cb_set(Eina_Error_Print_Cb cb, void *data) EINA_ARG_NONNULL(1);
EAPI void eina_error_log_level_set(Eina_Error_Level level);
+EAPI Eina_Error_Domain_Index eina_error_domain_register(const char *name, const char *color);
+EAPI void eina_error_domain_unregister(Eina_Error_Domain_Index i);
+
+EAPI void eina_error_dom_print(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file, const char *function, int line, const char *fmt, ...) EINA_ARG_NONNULL(2, 3, 5);
+EAPI void eina_error_dom_print_cb_stdout(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args);
+EAPI void eina_error_dom_print_cb_file(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args);
+
/**
* @}
*/
Index: src/lib/eina_error.c
===================================================================
--- src/lib/eina_error.c (revision 41406)
+++ src/lib/eina_error.c (working copy)
@@ -381,18 +381,31 @@
*/
static int _eina_error_init_count = 0;
+
+static int _disable_color = 0;
+
+/*
+ * List of domains registered
+ */
+static Eina_Error_Domain **_error_domains = NULL;
+static int _error_domains_count = 0;
+/*
+ * List of levels for domains set by the user before the domains are registered,
+ * updates the domain levels on the first log and clears itself.
+ */
+static Eina_Inlist *_pending_list = NULL;
+static int _pending_list_count = 0;
+
+/*
+ * List of errors registered
+ */
static Eina_Inlist *_error_list = NULL;
static int _error_list_count = 0;
static Eina_Error _err;
static Eina_Error_Print_Cb _print_cb = eina_error_print_cb_stdout;
+static Eina_Error_Dom_Print_Cb _dom_print_cb = eina_error_dom_print_cb_stdout;
static void *_print_cb_data = NULL;
-#define RED "\033[31;1m"
-#define GREEN "\033[32;1m"
-#define YELLOW "\033[33;1m"
-#define WHITE "\033[37;1m"
-#define NOTHING "\033[0m"
-
#ifdef DEBUG
static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_DBG;
#else
@@ -400,12 +413,124 @@
#endif
static const char *_colors[EINA_ERROR_LEVELS] = {
- RED, // EINA_ERROR_LEVEL_ERR
- YELLOW, // EINA_ERROR_LEVEL_WARN
- NOTHING, // EINA_ERROR_LEVEL_INFO
- GREEN, // EINA_ERROR_LEVEL_DBG
+ EINA_COLOR_RED, // EINA_ERROR_LEVEL_ERR
+ EINA_COLOR_YELLOW, // EINA_ERROR_LEVEL_WARN
+ EINA_COLOR_NOTHING, // EINA_ERROR_LEVEL_INFO
+ EINA_COLOR_GREEN, // EINA_ERROR_LEVEL_DBG
};
+static const char *
+eina_error_domain_str_get(const char *name, int name_len, const char *color, int color_len)
+{
+ const char *d;
+
+ if (color && color_len)
+ {
+ d = malloc(sizeof(char) * (color_len + name_len + strlen(EINA_COLOR_WHITE) + 1));
+ memcpy((char *)d, color, color_len);
+ memcpy((char *)(d + color_len), name, name_len);
+ memcpy((char *)(d + color_len + name_len), EINA_COLOR_WHITE, strlen(EINA_COLOR_WHITE));
+ ((char *)d)[color_len + name_len + strlen(EINA_COLOR_WHITE)] = '\0';
+ }
+ else
+ {
+ d = malloc(sizeof(char) * (name_len + 1));
+ memcpy((char *)d, name, name_len);
+ ((char *)d)[name_len] = '\0';
+ }
+ return d;
+}
+
+static Eina_Error_Domain *
+eina_error_domain_new(const char *name, const char *color)
+{
+ Eina_Error_Domain *d;
+ size_t len;
+
+ d = malloc(sizeof(Eina_Error_Domain));
+ if (!d) return NULL;
+
+ d->level = EINA_ERROR_LEVEL_UNKNOWN;
+ d->deleted = 0;
+
+ if (color)
+ {
+ d->color = malloc(sizeof(char)*(strlen(color)+1));
+ memcpy((char *)d->color, color, strlen(color));
+ ((char *)d->color)[strlen(color)] = '\0';
+ }
+ else
+ d->color = NULL;
+
+ if (name)
+ {
+ len = strlen(name);
+ d->name = malloc(sizeof(char)*(len + 1));
+ memcpy((char *)d->name, name, len);
+ ((char *)d->name)[len] = '\0';
+ if (color)
+ d->domain_str = eina_error_domain_str_get(name, len, color, strlen(color));
+ else
+ d->domain_str = eina_error_domain_str_get(name, len, NULL, 0);
+ }
+ else
+ {
+ d->name = NULL;
+ d->domain_str = NULL;
+ }
+
+ return d;
+}
+
+static void
+eina_error_domain_free(Eina_Error_Domain *d)
+{
+ if (!d) return;
+
+ if (d->name)
+ free((char *)d->name);
+ if (d->domain_str)
+ free((char *)d->domain_str);
+
+ free(d);
+}
+
+static void eina_error_domain_parse_pendings(void)
+{
+ Eina_Error_Domain_Level_Pending *p;
+ char *l;
+ const char *start, *end;
+ char *tmp;
+
+ if (!(l = getenv("EINA_ERROR_DOMAIN_LEVELS")))
+ {
+ return;
+ }
+
+ // Form name:level,name1:level1,name2:level2,...
+ start = l;
+ while (1)
+ {
+ end = strchr(start, ':');
+ if (!end) break;
+
+ // Parse name
+ p = malloc(sizeof(Eina_Error_Domain_Level_Pending) + end - start);
+ p->name = (char *)p + sizeof(Eina_Error_Domain_Level_Pending);
+ memcpy((char *)p->name, start, end-start);
+ ((char *)p->name)[end - start] = '\0';
+
+ // Parse level
+ p->level = strtol((char *)(end + 1), &tmp, 10);
+
+ _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
+ _pending_list_count++;
+
+ fprintf(stderr, "Parsed %s level %d\n", p->name, p->level);
+ start = tmp + 1;
+ }
+}
+
/**
* @endcond
*/
@@ -490,6 +615,8 @@
EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0;
+EAPI int EINA_ERROR_DOMAIN_GLOBAL = 0;
+
/**
* @endcond
*/
@@ -524,18 +651,30 @@
*/
EAPI int eina_error_init(void)
{
- if (!_eina_error_init_count)
- {
- char *level;
- /* TODO register the eina's basic errors */
- if ((level = getenv("EINA_ERROR_LEVEL")))
- {
- _error_level = atoi(level);
- }
- EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory");
- }
- /* get all the modules */
- return ++_eina_error_init_count;
+ if (!_eina_error_init_count)
+ {
+ char *level;
+ char *tmp;
+
+ /* TODO register the eina's basic errors */
+ if ((level = getenv("EINA_ERROR_LEVEL")))
+ _error_level = atoi(level);
+ else
+ _error_level = EINA_ERROR_LEVEL_UNKNOWN;
+
+ EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory");
+
+ // Register UNKNOWN domain, the default logger
+ EINA_ERROR_DOMAIN_GLOBAL = eina_error_domain_register(NULL, NULL);
+
+ // Check if color is disabled
+ if ((tmp = getenv("EINA_ERROR_COLOR_DISABLE")))
+ if (atoi(tmp) == 1) _disable_color = 1;
+
+ eina_error_domain_parse_pendings();
+ }
+
+ return ++_eina_error_init_count;
}
/**
@@ -568,6 +707,21 @@
free(tmp);
}
_error_list_count = 0;
+
+ while (_error_domains_count--)
+ {
+ if (_error_domains[_error_domains_count])
+ eina_error_domain_free(_error_domains[_error_domains_count]);
+ }
+ free(_error_domains);
+
+ while (_pending_list)
+ {
+ tmp = _pending_list;
+ _pending_list = _pending_list->next;
+ free(tmp);
+ }
+
}
return _eina_error_init_count;
}
@@ -733,10 +887,7 @@
const char *fnc, int line, const char *fmt, __UNUSED__ void *data,
va_list args)
{
- printf("%s", _colors[level]);
- printf("[%s:%d] %s() ", file, line, fnc);
- printf("%s", _colors[EINA_ERROR_LEVEL_INFO]);
- vprintf(fmt, args);
+ eina_error_dom_print_cb_stdout(EINA_ERROR_DOMAIN_GLOBAL, level, file, fnc, line, fmt, data, args);
}
/**
@@ -760,10 +911,7 @@
const char *fnc, int line, const char *fmt, void *data,
va_list args)
{
- FILE *f = data;
-
- fprintf(f, "[%s:%d] %s() ", file, line, fnc);
- vfprintf(f, fmt, args);
+ eina_error_dom_print_cb_file(EINA_ERROR_DOMAIN_GLOBAL, level, file, fnc, line, fmt, data, args);
}
/**
@@ -795,6 +943,144 @@
_error_level = level;
}
+/*
+ * @param name Domain name
+ * @param color Color of the domain name
+ *
+ * @return Domain index that will be used as the DOMAIN parameter on log
+ * macros.
+ */
+EAPI Eina_Error_Domain_Index
+eina_error_domain_register(const char *name, const char *color)
+{
+ Eina_Error_Domain_Level_Pending *pending;
+ int i, id;
+
+ for (i = 0; i < _error_domains_count; i++)
+ {
+ if (!_error_domains[i])
+ {
+ // NULL slot
+ fprintf(stderr, "Found a null slot at idx %d\n", i);
+ _error_domains[i] = eina_error_domain_new(name, color);
+ if (!(_error_domains[i])) return -1;
+ goto finish_register;
+ }
+ if (_error_domains[i]->deleted)
+ {
+ // Found a flagged slot
+ fprintf(stderr, "Found a deleted flag slot at %d\n", i);
+ eina_error_domain_free(_error_domains[i]);
+ _error_domains[i] = eina_error_domain_new(name, color);
+ if (!_error_domains[i]) return -1;
+ goto finish_register;
+ }
+ }
+
+ // Did not found a slot, realloc 8 more slots. Also works on the first time
+ // when the array doesn't exist yet.
+ _error_domains = realloc(_error_domains, sizeof(Eina_Error_Domain)*8);
+
+ // Flag empty slots.
+ for (id = _error_domains_count; id <= _error_domains_count + 8; id++)
+ {
+ _error_domains[id] = NULL;
+ }
+
+ _error_domains_count += 8;
+
+ // Use the index of the for loop. If it reached the end with no slots,
+ // then we gotta insert on i+1. If it's 0, then the array is empty and
+ // we should insert on 0.
+ if (i) _error_domains[++i] = eina_error_domain_new(name, color);
+ else _error_domains[i] = eina_error_domain_new(name, color);
+
+
+finish_register:
+ EINA_INLIST_FOREACH(_pending_list, pending)
+ {
+ if (!strcmp(pending->name, name))
+ {
+ fprintf(stderr, "Updating domain %s level from %d to %d\n", name, _error_domains[i]->level, pending->level);
+ _error_domains[i]->level = pending->level;
+ _pending_list = eina_inlist_remove(_pending_list, EINA_INLIST_GET(pending));
+ break;
+ }
+ }
+
+ // Check if level is still UNKNOWN, set it to global
+ if (_error_domains[i]->level == EINA_ERROR_LEVEL_UNKNOWN)
+ _error_domains[i]->level = _error_level;
+
+ return i;
+}
+
+EAPI void
+eina_error_domain_unregister(Eina_Error_Domain_Index i)
+{
+ if (i >= _error_domains_count) return;
+ _error_domains[i]->deleted = 1;
+}
+
+EAPI void
+eina_error_dom_print_cb_stdout(Eina_Error_Domain_Index i, Eina_Error_Level level,
+ const char *file, const char *fnc, int line, const char *fmt,
+ __UNUSED__ void *data, va_list args)
+{
+ Eina_Error_Domain *d;
+ d = _error_domains[i];
+
+ if (!d) return;
+
+ printf("%s\t%s%s:%d %s()%s ", (d->domain_str) ? d->domain_str : ((d->name) ? d->name : ""),
+ (!_disable_color) ? _colors[level] : "",
+ file, line, fnc,
+ (!_disable_color) ? _colors[EINA_ERROR_LEVEL_INFO] : "");
+ vprintf(fmt, args);
+}
+
+EAPI void
+eina_error_dom_print_cb_file(Eina_Error_Domain_Index i, Eina_Error_Level level,
+ const char *file, const char *fnc, int line, const char *fmt,
+ void *data, va_list args)
+{
+ // Workaround to use var level.
+ Eina_Error_Level x = level;
+ x++;
+
+ FILE *f = data;
+ Eina_Error_Domain *d;
+ d = _error_domains[i];
+ fprintf(f, "%s\t%s:%d %s() ", (d->name) ? d->name : "", file, line, fnc);
+ vfprintf(f, fmt, args);
+}
+
+EAPI void
+eina_error_dom_print(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file,
+ const char *fnc, int line, const char *fmt, ...)
+{
+ va_list args;
+
+ if (level > _error_level)
+ {
+ return;
+ }
+ else if (level > _error_domains[i]->level)
+ {
+ return;
+ }
+
+ EINA_SAFETY_ON_NULL_RETURN(file);
+ EINA_SAFETY_ON_NULL_RETURN(fnc);
+ EINA_SAFETY_ON_NULL_RETURN(fmt);
+
+ va_start(args, fmt);
+ _dom_print_cb(i, level, file, fnc, line, fmt, _print_cb_data, args);
+ va_end(args);
+
+ if (getenv("EINA_ERROR_ABORT")) abort();
+}
+
/**
* @}
*/
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge
This is your chance to win up to $100,000 in prizes! For a limited time,
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel