1 /* EINA - EFL data type library
2 * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric Bail, Andre Dieb
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
31 #if defined HAVE_EXECINFO_H && defined HAVE_BACKTRACE && defined HAVE_BACKTRACE_SYMBOLS
32 # include <execinfo.h>
33 # define EINA_LOG_BACKTRACE
40 #ifdef EFL_HAVE_POSIX_THREADS
48 #include "eina_config.h"
49 #include "eina_private.h"
50 #include "eina_inlist.h"
52 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
53 #include "eina_safety_checks.h"
57 * + printing logs to stdout or stderr can be implemented
58 * using a queue, useful for multiple threads printing
59 * + add a wrapper for assert?
62 /*============================================================================*
64 *============================================================================*/
70 #define EINA_LOG_ENV_ABORT "EINA_LOG_ABORT"
71 #define EINA_LOG_ENV_ABORT_LEVEL "EINA_LOG_ABORT_LEVEL"
72 #define EINA_LOG_ENV_LEVEL "EINA_LOG_LEVEL"
73 #define EINA_LOG_ENV_LEVELS "EINA_LOG_LEVELS"
74 #define EINA_LOG_ENV_LEVELS_GLOB "EINA_LOG_LEVELS_GLOB"
75 #define EINA_LOG_ENV_COLOR_DISABLE "EINA_LOG_COLOR_DISABLE"
76 #define EINA_LOG_ENV_FILE_DISABLE "EINA_LOG_FILE_DISABLE"
77 #define EINA_LOG_ENV_FUNCTION_DISABLE "EINA_LOG_FUNCTION_DISABLE"
78 #define EINA_LOG_ENV_BACKTRACE "EINA_LOG_BACKTRACE"
80 #ifdef EINA_ENABLE_LOG
82 // Structure for storing domain level settings passed from the command line
83 // that will be matched with application-defined domains.
84 typedef struct _Eina_Log_Domain_Level_Pending Eina_Log_Domain_Level_Pending;
85 struct _Eina_Log_Domain_Level_Pending
94 * List of levels for domains set by the user before the domains are registered,
95 * updates the domain levels on the first log and clears itself.
97 static Eina_Inlist *_pending_list = NULL;
98 static Eina_Inlist *_glob_list = NULL;
100 // Disable color flag (can be changed through the env var
101 // EINA_LOG_ENV_COLOR_DISABLE).
102 static Eina_Bool _disable_color = EINA_FALSE;
103 static Eina_Bool _disable_file = EINA_FALSE;
104 static Eina_Bool _disable_function = EINA_FALSE;
105 static Eina_Bool _abort_on_critical = EINA_FALSE;
106 static int _abort_level_on_critical = EINA_LOG_LEVEL_CRITICAL;
108 #ifdef EINA_LOG_BACKTRACE
109 static int _backtrace_level = -1;
112 #ifdef EFL_HAVE_THREADS
114 static Eina_Bool _threads_enabled = EINA_FALSE;
115 static Eina_Bool _threads_inited = EINA_FALSE;
117 # ifdef EFL_HAVE_POSIX_THREADS
119 typedef pthread_t Thread;
121 static pthread_t _main_thread;
123 # define SELF() pthread_self()
124 # define IS_MAIN(t) pthread_equal(t, _main_thread)
125 # define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
126 # define CHECK_MAIN(...) \
128 if (!IS_MAIN(pthread_self())) { \
130 "ERR: not main thread! current=%lu, main=%lu\n", \
131 (unsigned long)pthread_self(), \
132 (unsigned long)_main_thread); \
133 return __VA_ARGS__; \
137 # ifdef EFL_HAVE_POSIX_THREADS_SPINLOCK
139 static pthread_spinlock_t _log_lock;
141 static Eina_Bool _eina_log_spinlock_init(void)
143 if (pthread_spin_init(&_log_lock, PTHREAD_PROCESS_PRIVATE) == 0)
147 "ERROR: pthread_spin_init(%p, PTHREAD_PROCESS_PRIVATE): %s\n",
148 &_log_lock, strerror(errno));
152 # define LOG_LOCK() \
153 if (_threads_enabled) \
156 fprintf(stderr, "+++LOG LOG_LOCKED! [%s, %lu]\n", \
157 __FUNCTION__, (unsigned long)pthread_self()); } \
158 if (EINA_UNLIKELY(_threads_enabled)) { \
159 pthread_spin_lock(&_log_lock); } \
161 # define LOG_UNLOCK() \
162 if (_threads_enabled) \
164 if (EINA_UNLIKELY(_threads_enabled)) { \
165 pthread_spin_unlock(&_log_lock); } \
168 "---LOG LOG_UNLOCKED! [%s, %lu]\n", \
169 __FUNCTION__, (unsigned long)pthread_self()); } \
171 # define INIT() _eina_log_spinlock_init()
172 # define SHUTDOWN() pthread_spin_destroy(&_log_lock)
174 # else /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
176 static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
177 # define LOG_LOCK() if(_threads_enabled) {pthread_mutex_lock(&_log_mutex); }
178 # define LOG_UNLOCK() if(_threads_enabled) {pthread_mutex_unlock(&_log_mutex); }
180 # define SHUTDOWN() do {} while (0)
182 # endif /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
184 # else /* EFL_HAVE_WIN32_THREADS */
186 typedef DWORD Thread;
188 static DWORD _main_thread;
190 # define SELF() GetCurrentThreadId()
191 # define IS_MAIN(t) (t == _main_thread)
192 # define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
193 # define CHECK_MAIN(...) \
195 if (!IS_MAIN(GetCurrentThreadId())) { \
197 "ERR: not main thread! current=%lu, main=%lu\n", \
198 GetCurrentThreadId(), _main_thread); \
199 return __VA_ARGS__; \
203 static HANDLE _log_mutex = NULL;
205 # define LOG_LOCK() if(_threads_enabled) WaitForSingleObject(_log_mutex, INFINITE)
206 # define LOG_UNLOCK() if(_threads_enabled) ReleaseMutex(_log_mutex)
207 # define INIT() ((_log_mutex = CreateMutex(NULL, FALSE, NULL)) ? 1 : 0)
208 # define SHUTDOWN() if (_log_mutex) CloseHandle(_log_mutex)
210 # endif /* EFL_HAVE_WIN32_THREADS */
212 #else /* ! EFL_HAVE_THREADS */
214 # define LOG_LOCK() do {} while (0)
215 # define LOG_UNLOCK() do {} while (0)
216 # define IS_MAIN(t) (1)
217 # define IS_OTHER(t) (0)
218 # define CHECK_MAIN(...) do {} while (0)
220 # define SHUTDOWN() do {} while (0)
222 #endif /* ! EFL_HAVE_THREADS */
225 // List of domains registered
226 static Eina_Log_Domain *_log_domains = NULL;
227 static unsigned int _log_domains_count = 0;
228 static size_t _log_domains_allocated = 0;
230 // Default function for printing on domains
231 static Eina_Log_Print_Cb _print_cb = eina_log_print_cb_stderr;
232 static void *_print_cb_data = NULL;
235 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_DBG;
237 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_CRITICAL;
239 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_ERR;
242 /* NOTE: if you change this, also change:
243 * eina_log_print_level_name_get()
244 * eina_log_print_level_name_color_get()
246 static const char *_names[] = {
255 /* TODO: query win32_def_attr on eina_log_init() */
256 static int win32_def_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
258 /* NOTE: can't use eina_log from inside this function */
260 eina_log_win32_color_convert(const char *color, const char **endptr)
265 if (endptr) *endptr = color;
267 if (color[0] != '\033') return 0;
268 if (color[1] != '[') return 0;
274 int code = strtol(p, &end, 10);
278 //fputs("empty color string\n", stderr);
279 if (endptr) *endptr = end;
280 attr = 0; /* assume it was not color, must end with 'm' */
286 if (code == 0) attr = win32_def_attr;
287 else if (code == 1) attr |= FOREGROUND_INTENSITY;
288 else if (code == 4) attr |= COMMON_LVB_UNDERSCORE;
289 else if (code == 7) attr |= COMMON_LVB_REVERSE_VIDEO;
290 else if ((code >= 30) && (code <= 37))
292 /* clear foreground */
293 attr &= ~(FOREGROUND_RED |
298 attr |= FOREGROUND_RED;
300 attr |= FOREGROUND_GREEN;
302 attr |= FOREGROUND_RED | FOREGROUND_GREEN;
304 attr |= FOREGROUND_BLUE;
306 attr |= FOREGROUND_RED | FOREGROUND_BLUE;
308 attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
310 attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
312 else if ((code >= 40) && (code <= 47))
314 /* clear background */
315 attr &= ~(BACKGROUND_RED |
320 attr |= BACKGROUND_RED;
322 attr |= BACKGROUND_GREEN;
324 attr |= BACKGROUND_RED | BACKGROUND_GREEN;
326 attr |= BACKGROUND_BLUE;
328 attr |= BACKGROUND_RED | BACKGROUND_BLUE;
330 attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
332 attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
338 if (endptr) *endptr = end + 1;
341 else if (*end == ';')
345 //fprintf(stderr, "unexpected char in color string: %s\n", end);
346 attr = 0; /* assume it was not color */
347 if (endptr) *endptr = end;
356 eina_log_win32_color_get(const char *color)
358 return eina_log_win32_color_convert(color, NULL);
362 static inline unsigned int
363 eina_log_pid_get(void)
365 return (unsigned int)getpid();
369 eina_log_print_level_name_get(int level, const char **p_name)
372 /* NOTE: if you change this, also change
373 * eina_log_print_level_name_color_get()
374 * eina_log_level_name_get() (at eina_inline_log.x)
376 if (EINA_UNLIKELY(level < 0))
378 snprintf(buf, sizeof(buf), "%03d", level);
381 else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
383 snprintf(buf, sizeof(buf), "%03d", level);
387 *p_name = _names[level];
392 eina_log_print_level_name_color_get(int level,
397 /* NOTE: if you change this, also change:
398 * eina_log_print_level_name_get()
400 if (EINA_UNLIKELY(level < 0))
402 snprintf(buf, sizeof(buf), "%03d", level);
405 else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
407 snprintf(buf, sizeof(buf), "%03d", level);
411 *p_name = _names[level];
413 *p_color = eina_log_win32_color_get(eina_log_level_color_get(level));
417 eina_log_print_level_name_color_get(int level,
419 const char **p_color)
422 /* NOTE: if you change this, also change:
423 * eina_log_print_level_name_get()
425 if (EINA_UNLIKELY(level < 0))
427 snprintf(buf, sizeof(buf), "%03d", level);
430 else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
432 snprintf(buf, sizeof(buf), "%03d", level);
436 *p_name = _names[level];
438 *p_color = eina_log_level_color_get(level);
442 #define DECLARE_LEVEL_NAME(level) const char *name; \
443 eina_log_print_level_name_get(level, &name)
445 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name; int color; \
446 eina_log_print_level_name_color_get(level, &name, &color)
448 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name, *color; \
449 eina_log_print_level_name_color_get(level, &name, &color)
452 /** No threads, No color */
454 eina_log_print_prefix_NOthreads_NOcolor_file_func(FILE *fp,
455 const Eina_Log_Domain *d,
456 Eina_Log_Level level,
461 DECLARE_LEVEL_NAME(level);
462 fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(),
463 d->domain_str, file, line, fnc);
467 eina_log_print_prefix_NOthreads_NOcolor_NOfile_func(FILE *fp,
468 const Eina_Log_Domain *d,
469 Eina_Log_Level level,
470 const char *file __UNUSED__,
474 DECLARE_LEVEL_NAME(level);
475 fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str,
480 eina_log_print_prefix_NOthreads_NOcolor_file_NOfunc(FILE *fp,
481 const Eina_Log_Domain *d,
482 Eina_Log_Level level,
484 const char *fnc __UNUSED__,
487 DECLARE_LEVEL_NAME(level);
488 fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str,
492 /* No threads, color */
494 eina_log_print_prefix_NOthreads_color_file_func(FILE *fp,
495 const Eina_Log_Domain *d,
496 Eina_Log_Level level,
501 DECLARE_LEVEL_NAME_COLOR(level);
503 fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(),
504 d->domain_str, file, line, fnc);
506 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
508 fprintf(fp, "%s", name);
509 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
510 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
512 SetConsoleTextAttribute(GetStdHandle(
514 eina_log_win32_color_get(d->domain_str));
515 fprintf(fp, "%s", d->name);
516 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
517 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
518 fprintf(fp, " %s:%d ", file, line);
519 SetConsoleTextAttribute(GetStdHandle(
521 FOREGROUND_INTENSITY | FOREGROUND_RED |
522 FOREGROUND_GREEN | FOREGROUND_BLUE);
523 fprintf(fp, "%s()", fnc);
524 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
525 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
528 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
529 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
530 color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
535 eina_log_print_prefix_NOthreads_color_NOfile_func(FILE *fp,
536 const Eina_Log_Domain *d,
537 Eina_Log_Level level,
538 const char *file __UNUSED__,
542 DECLARE_LEVEL_NAME_COLOR(level);
544 fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str,
547 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
549 fprintf(fp, "%s", name);
550 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
551 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
553 SetConsoleTextAttribute(GetStdHandle(
555 eina_log_win32_color_get(d->domain_str));
556 fprintf(fp, "%s", d->name);
557 SetConsoleTextAttribute(GetStdHandle(
559 FOREGROUND_INTENSITY | FOREGROUND_RED |
560 FOREGROUND_GREEN | FOREGROUND_BLUE);
561 fprintf(fp, "%s()", fnc);
562 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
563 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
566 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
567 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
568 color, name, eina_log_pid_get(), d->domain_str, fnc);
573 eina_log_print_prefix_NOthreads_color_file_NOfunc(FILE *fp,
574 const Eina_Log_Domain *d,
575 Eina_Log_Level level,
577 const char *fnc __UNUSED__,
580 DECLARE_LEVEL_NAME_COLOR(level);
582 fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str,
585 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
587 fprintf(fp, "%s", name);
588 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
589 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
591 SetConsoleTextAttribute(GetStdHandle(
593 eina_log_win32_color_get(d->domain_str));
594 fprintf(fp, "%s", d->name);
595 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
596 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
597 fprintf(fp, " %s:%d ", file, line);
599 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d ",
600 color, name, eina_log_pid_get(), d->domain_str, file, line);
604 /** threads, No color */
605 #ifdef EFL_HAVE_THREADS
607 eina_log_print_prefix_threads_NOcolor_file_func(FILE *fp,
608 const Eina_Log_Domain *d,
609 Eina_Log_Level level,
616 DECLARE_LEVEL_NAME(level);
620 fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d %s() ",
621 name, eina_log_pid_get(), d->domain_str,
622 (unsigned long)cur, file, line, fnc);
625 fprintf(fp, "%s<%u>:%s %s:%d %s() ",
626 name, eina_log_pid_get(), d->domain_str, file, line, fnc);
630 eina_log_print_prefix_threads_NOcolor_NOfile_func(FILE *fp,
631 const Eina_Log_Domain *d,
632 Eina_Log_Level level,
633 const char *file __UNUSED__,
639 DECLARE_LEVEL_NAME(level);
643 fprintf(fp, "%s<%u>:%s[T:%lu] %s() ",
644 name, eina_log_pid_get(), d->domain_str,
645 (unsigned long)cur, fnc);
648 fprintf(fp, "%s<%u>:%s %s() ",
649 name, eina_log_pid_get(), d->domain_str, fnc);
653 eina_log_print_prefix_threads_NOcolor_file_NOfunc(FILE *fp,
654 const Eina_Log_Domain *d,
655 Eina_Log_Level level,
657 const char *fnc __UNUSED__,
662 DECLARE_LEVEL_NAME(level);
666 fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d ",
667 name, eina_log_pid_get(), d->domain_str, (unsigned long)cur,
672 fprintf(fp, "%s<%u>:%s %s:%d ",
673 name, eina_log_pid_get(), d->domain_str, file, line);
678 eina_log_print_prefix_threads_color_file_func(FILE *fp,
679 const Eina_Log_Domain *d,
680 Eina_Log_Level level,
687 DECLARE_LEVEL_NAME_COLOR(level);
692 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
694 fprintf(fp, "%s", name);
695 SetConsoleTextAttribute(GetStdHandle(
697 FOREGROUND_RED | FOREGROUND_GREEN |
700 SetConsoleTextAttribute(GetStdHandle(
702 eina_log_win32_color_get(d->domain_str));
703 fprintf(fp, "%s[T:", d->name);
704 SetConsoleTextAttribute(GetStdHandle(
706 FOREGROUND_RED | FOREGROUND_GREEN |
709 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
710 FOREGROUND_GREEN | FOREGROUND_BLUE);
711 fprintf(fp, "%lu", (unsigned long)cur);
712 SetConsoleTextAttribute(GetStdHandle(
714 FOREGROUND_RED | FOREGROUND_GREEN |
716 fprintf(fp, "] %s:%d ", file, line);
717 SetConsoleTextAttribute(GetStdHandle(
719 FOREGROUND_INTENSITY | FOREGROUND_RED |
720 FOREGROUND_GREEN | FOREGROUND_BLUE);
721 fprintf(fp, "%s()", fnc);
722 SetConsoleTextAttribute(GetStdHandle(
724 FOREGROUND_RED | FOREGROUND_GREEN |
728 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
729 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d "
730 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
731 color, name, eina_log_pid_get() ,d->domain_str,
732 (unsigned long)cur, file, line, fnc);
738 eina_log_print_prefix_NOthreads_color_file_func(fp,
745 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
746 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
747 color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
752 eina_log_print_prefix_threads_color_NOfile_func(FILE *fp,
753 const Eina_Log_Domain *d,
754 Eina_Log_Level level,
755 const char *file __UNUSED__,
761 DECLARE_LEVEL_NAME_COLOR(level);
766 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
768 fprintf(fp, "%s", name);
769 SetConsoleTextAttribute(GetStdHandle(
771 FOREGROUND_RED | FOREGROUND_GREEN |
774 SetConsoleTextAttribute(GetStdHandle(
776 eina_log_win32_color_get(d->domain_str));
777 fprintf(fp, "%s[T:", d->name);
778 SetConsoleTextAttribute(GetStdHandle(
780 FOREGROUND_RED | FOREGROUND_GREEN |
783 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
784 FOREGROUND_GREEN | FOREGROUND_BLUE);
785 fprintf(fp, "%lu", (unsigned long)cur);
786 SetConsoleTextAttribute(GetStdHandle(
788 FOREGROUND_INTENSITY | FOREGROUND_RED |
789 FOREGROUND_GREEN | FOREGROUND_BLUE);
790 fprintf(fp, "%s()", fnc);
791 SetConsoleTextAttribute(GetStdHandle(
793 FOREGROUND_RED | FOREGROUND_GREEN |
797 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
798 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] "
799 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
800 color, name, eina_log_pid_get(), d->domain_str,
801 (unsigned long)cur, fnc);
807 eina_log_print_prefix_NOthreads_color_NOfile_func(fp,
814 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
815 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
816 color, name, eina_log_pid_get(), d->domain_str, fnc);
821 eina_log_print_prefix_threads_color_file_NOfunc(FILE *fp,
822 const Eina_Log_Domain *d,
823 Eina_Log_Level level,
825 const char *fnc __UNUSED__,
830 DECLARE_LEVEL_NAME_COLOR(level);
835 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
837 fprintf(fp, "%s", name);
838 SetConsoleTextAttribute(GetStdHandle(
840 FOREGROUND_RED | FOREGROUND_GREEN |
843 SetConsoleTextAttribute(GetStdHandle(
845 eina_log_win32_color_get(d->domain_str));
846 fprintf(fp, "%s[T:", d->name);
847 SetConsoleTextAttribute(GetStdHandle(
849 FOREGROUND_RED | FOREGROUND_GREEN |
852 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
853 FOREGROUND_GREEN | FOREGROUND_BLUE);
854 fprintf(fp, "%lu", (unsigned long)cur);
855 SetConsoleTextAttribute(GetStdHandle(
857 FOREGROUND_RED | FOREGROUND_GREEN |
859 fprintf(fp, "] %s:%d ", file, line);
861 fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
862 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d ",
863 color, name, eina_log_pid_get(), d->domain_str,
864 (unsigned long)cur, file, line);
870 eina_log_print_prefix_NOthreads_color_file_NOfunc(fp,
877 fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d ",
878 color, name, d->domain_str, file, line);
881 #endif /* EFL_HAVE_THREADS */
883 static void (*_eina_log_print_prefix)(FILE *fp, const Eina_Log_Domain *d,
884 Eina_Log_Level level, const char *file,
887 eina_log_print_prefix_NOthreads_color_file_func;
890 eina_log_print_prefix_update(void)
892 if (_disable_file && _disable_function)
894 fprintf(stderr, "ERROR: cannot have " EINA_LOG_ENV_FILE_DISABLE " and "
895 EINA_LOG_ENV_FUNCTION_DISABLE " set at the same time, will "
896 "just disable function.\n");
900 #define S(NOthread, NOcolor, NOfile, NOfunc) \
901 _eina_log_print_prefix = \
902 eina_log_print_prefix_ ## NOthread ## threads_ ## NOcolor ## color_ ## \
904 ## file_ ## NOfunc ## func
906 #ifdef EFL_HAVE_THREADS
907 if (_threads_enabled)
913 else if (_disable_function)
922 else if (_disable_function)
937 else if (_disable_function)
946 else if (_disable_function)
956 * Creates a colored domain name string.
959 eina_log_domain_str_get(const char *name, const char *color)
968 name_len = strlen(name);
969 color_len = strlen(color);
971 malloc(sizeof(char) *
972 (color_len + name_len + strlen(EINA_COLOR_RESET) + 1));
976 memcpy((char *)d, color, color_len);
977 memcpy((char *)(d + color_len), name, name_len);
978 memcpy((char *)(d + color_len + name_len), EINA_COLOR_RESET,
979 strlen(EINA_COLOR_RESET));
980 ((char *)d)[color_len + name_len + strlen(EINA_COLOR_RESET)] = '\0';
989 * Setups a new logging domain to the name and color specified. Note that this
990 * constructor acts upon an pre-allocated object.
992 static Eina_Log_Domain *
993 eina_log_domain_new(Eina_Log_Domain *d, const char *name, const char *color)
995 EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
996 EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
998 d->level = EINA_LOG_LEVEL_UNKNOWN;
999 d->deleted = EINA_FALSE;
1001 if ((color) && (!_disable_color))
1002 d->domain_str = eina_log_domain_str_get(name, color);
1004 d->domain_str = eina_log_domain_str_get(name, NULL);
1006 d->name = strdup(name);
1007 d->namelen = strlen(name);
1013 * Frees internal strings of a log domain, keeping the log domain itself as a
1014 * slot for next domain registers.
1017 eina_log_domain_free(Eina_Log_Domain *d)
1019 EINA_SAFETY_ON_NULL_RETURN(d);
1022 free((char *)d->domain_str);
1025 free((char *)d->name);
1029 * Parses domain levels passed through the env var.
1032 eina_log_domain_parse_pendings(void)
1036 if (!(start = getenv(EINA_LOG_ENV_LEVELS)))
1039 // name1:level1,name2:level2,name3:level3,...
1042 Eina_Log_Domain_Level_Pending *p;
1047 end = strchr(start, ':');
1051 // Parse level, keep going if failed
1052 level = strtol((char *)(end + 1), &tmp, 10);
1053 if (tmp == (end + 1))
1057 p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1061 p->namelen = end - start;
1062 memcpy((char *)p->name, start, end - start);
1063 ((char *)p->name)[end - start] = '\0';
1066 _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
1069 start = strchr(tmp, ',');
1078 eina_log_domain_parse_pending_globs(void)
1082 if (!(start = getenv(EINA_LOG_ENV_LEVELS_GLOB)))
1085 // name1:level1,name2:level2,name3:level3,...
1088 Eina_Log_Domain_Level_Pending *p;
1093 end = strchr(start, ':');
1097 // Parse level, keep going if failed
1098 level = strtol((char *)(end + 1), &tmp, 10);
1099 if (tmp == (end + 1))
1103 p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1107 p->namelen = 0; /* not that useful */
1108 memcpy((char *)p->name, start, end - start);
1109 ((char *)p->name)[end - start] = '\0';
1112 _glob_list = eina_inlist_append(_glob_list, EINA_INLIST_GET(p));
1115 start = strchr(tmp, ',');
1124 eina_log_domain_register_unlocked(const char *name, const char *color)
1126 Eina_Log_Domain_Level_Pending *pending = NULL;
1130 for (i = 0; i < _log_domains_count; i++)
1132 if (_log_domains[i].deleted)
1134 // Found a flagged slot, free domain_str and replace slot
1135 eina_log_domain_new(&_log_domains[i], name, color);
1136 goto finish_register;
1140 if (_log_domains_count >= _log_domains_allocated)
1142 Eina_Log_Domain *tmp;
1146 // special case for init, eina itself will allocate a dozen of domains
1149 // grow 8 buckets to minimize reallocs
1150 size = _log_domains_allocated + 8;
1152 tmp = realloc(_log_domains, sizeof(Eina_Log_Domain) * size);
1158 _log_domains_allocated = size;
1164 // Use an allocated slot
1165 eina_log_domain_new(&_log_domains[i], name, color);
1166 _log_domains_count++;
1169 namelen = _log_domains[i].namelen;
1171 EINA_INLIST_FOREACH(_pending_list, pending)
1173 if ((namelen == pending->namelen) && (strcmp(pending->name, name) == 0))
1175 _log_domains[i].level = pending->level;
1180 if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1182 EINA_INLIST_FOREACH(_glob_list, pending)
1184 if (!fnmatch(pending->name, name, 0))
1186 _log_domains[i].level = pending->level;
1192 // Check if level is still UNKNOWN, set it to global
1193 if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1194 _log_domains[i].level = _log_level;
1199 static inline Eina_Bool
1200 eina_log_term_color_supported(const char *term)
1210 /* list of known to support color terminals,
1211 * take from gentoo's portage.
1214 case 'x': /* xterm and xterm-color */
1215 return ((strncmp(tail, "term", sizeof("term") - 1) == 0) &&
1216 ((tail[sizeof("term") - 1] == '\0') ||
1217 (strcmp(tail + sizeof("term") - 1, "-color") == 0)));
1219 case 'E': /* Eterm */
1220 case 'a': /* aterm */
1221 case 'k': /* kterm */
1222 return (strcmp(tail, "term") == 0);
1224 case 'r': /* xrvt or rxvt-unicode */
1225 return ((strncmp(tail, "xvt", sizeof("xvt") - 1) == 0) &&
1226 ((tail[sizeof("xvt") - 1] == '\0') ||
1227 (strcmp(tail + sizeof("xvt") - 1, "-unicode") == 0)));
1229 case 's': /* screen */
1230 return (strcmp(tail, "creen") == 0);
1232 case 'g': /* gnome */
1233 return (strcmp(tail, "nome") == 0);
1235 case 'i': /* interix */
1236 return (strcmp(tail, "nterix") == 0);
1244 eina_log_domain_unregister_unlocked(int domain)
1248 if ((unsigned int)domain >= _log_domains_count)
1251 d = &_log_domains[domain];
1252 eina_log_domain_free(d);
1257 eina_log_print_unlocked(int domain,
1258 Eina_Log_Level level,
1267 #ifdef EINA_SAFETY_CHECKS
1268 if (EINA_UNLIKELY((unsigned int)domain >= _log_domains_count) ||
1269 EINA_UNLIKELY(domain < 0))
1271 if (file && fnc && fmt)
1274 "CRI: %s:%d %s() eina_log_print() unknown domain %d, original message format '%s'\n",
1283 "CRI: eina_log_print() unknown domain %d, original message format '%s'\n",
1287 if (_abort_on_critical)
1294 d = _log_domains + domain;
1295 #ifdef EINA_SAFETY_CHECKS
1296 if (EINA_UNLIKELY(d->deleted))
1299 "ERR: eina_log_print() domain %d is deleted\n",
1306 if (level > d->level)
1317 fprintf(stderr, "ERR: %s: can not allocate memory\n", __FUNCTION__);
1322 while (strchr(tmp, '%'))
1328 _print_cb(d, level, file, fnc, line, wfmt, _print_cb_data, args);
1332 _print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args);
1335 if (EINA_UNLIKELY(_abort_on_critical) &&
1336 EINA_UNLIKELY(level <= _abort_level_on_critical))
1347 /*============================================================================*
1349 *============================================================================*/
1353 * @brief Initialize the log module.
1355 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1357 * This function sets up the log module of Eina. It is called by
1362 * @warning Not-MT: just call this function from main thread! The
1363 * place where this function was called the first time is
1364 * considered the main thread.
1369 #ifdef EINA_ENABLE_LOG
1370 const char *level, *tmp;
1373 assert((sizeof(_names) / sizeof(_names[0])) == EINA_LOG_LEVELS);
1375 #ifdef EINA_LOG_BACKTRACE
1376 if ((tmp = getenv(EINA_LOG_ENV_BACKTRACE)))
1377 _backtrace_level = atoi(tmp);
1380 if ((tmp = getenv(EINA_LOG_ENV_COLOR_DISABLE)))
1381 color_disable = atoi(tmp);
1385 /* Check if color is explicitly disabled */
1386 if (color_disable == 1)
1387 _disable_color = EINA_TRUE;
1390 /* color was not explicitly disabled or enabled, guess it */
1391 else if (color_disable == -1)
1393 if (!eina_log_term_color_supported(getenv("TERM")))
1394 _disable_color = EINA_TRUE;
1397 /* if not a terminal, but redirected to a file, disable color */
1400 if (_print_cb == eina_log_print_cb_stderr)
1402 else if (_print_cb == eina_log_print_cb_stdout)
1407 if ((fd >= 0) && (!isatty(fd)))
1408 _disable_color = EINA_TRUE;
1413 if ((tmp = getenv(EINA_LOG_ENV_FILE_DISABLE)) && (atoi(tmp) == 1))
1414 _disable_file = EINA_TRUE;
1416 if ((tmp = getenv(EINA_LOG_ENV_FUNCTION_DISABLE)) && (atoi(tmp) == 1))
1417 _disable_function = EINA_TRUE;
1419 if ((tmp = getenv(EINA_LOG_ENV_ABORT)) && (atoi(tmp) == 1))
1420 _abort_on_critical = EINA_TRUE;
1422 if ((tmp = getenv(EINA_LOG_ENV_ABORT_LEVEL)))
1423 _abort_level_on_critical = atoi(tmp);
1425 eina_log_print_prefix_update();
1428 if ((level = getenv(EINA_LOG_ENV_LEVEL)))
1429 _log_level = atoi(level);
1431 // Register UNKNOWN domain, the default logger
1432 EINA_LOG_DOMAIN_GLOBAL = eina_log_domain_register("", NULL);
1434 if (EINA_LOG_DOMAIN_GLOBAL < 0)
1436 fprintf(stderr, "Failed to create global logging domain.\n");
1440 // Parse pending domains passed through EINA_LOG_LEVELS_GLOB
1441 eina_log_domain_parse_pending_globs();
1443 // Parse pending domains passed through EINA_LOG_LEVELS
1444 eina_log_domain_parse_pendings();
1452 * @brief Shut down the log module.
1454 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1456 * This function shuts down the log module set up by
1457 * eina_log_init(). It is called by eina_shutdown().
1459 * @see eina_shutdown()
1461 * @warning Not-MT: just call this function from main thread! The
1462 * place where eina_log_init() (eina_init()) was called the
1463 * first time is considered the main thread.
1466 eina_log_shutdown(void)
1468 #ifdef EINA_ENABLE_LOG
1471 while (_log_domains_count--)
1473 if (_log_domains[_log_domains_count].deleted)
1476 eina_log_domain_free(&_log_domains[_log_domains_count]);
1481 _log_domains = NULL;
1482 _log_domains_count = 0;
1483 _log_domains_allocated = 0;
1488 _glob_list = _glob_list->next;
1492 while (_pending_list)
1494 tmp = _pending_list;
1495 _pending_list = _pending_list->next;
1503 #ifdef EFL_HAVE_THREADS
1507 * @brief Activate the log mutex.
1509 * This function activate the mutex in the eina log module. It is called by
1510 * eina_threads_init().
1512 * @see eina_threads_init()
1515 eina_log_threads_init(void)
1517 #ifdef EINA_ENABLE_LOG
1518 if (_threads_inited) return;
1519 _main_thread = SELF();
1520 if (!INIT()) return;
1521 _threads_inited = EINA_TRUE;
1527 * @brief Shut down the log mutex.
1529 * This function shuts down the mutex in the log module.
1530 * It is called by eina_threads_shutdown().
1532 * @see eina_threads_shutdown()
1535 eina_log_threads_shutdown(void)
1537 #ifdef EINA_ENABLE_LOG
1538 if (!_threads_inited) return;
1541 _threads_enabled = EINA_FALSE;
1542 _threads_inited = EINA_FALSE;
1548 /*============================================================================*
1550 *============================================================================*/
1556 EAPI int EINA_LOG_DOMAIN_GLOBAL = 0;
1563 eina_log_threads_enable(void)
1565 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1566 if (_threads_enabled) return;
1567 if (!_threads_inited) eina_log_threads_init();
1568 _threads_enabled = EINA_TRUE;
1569 eina_log_print_prefix_update();
1574 eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data)
1576 #ifdef EINA_ENABLE_LOG
1579 _print_cb_data = data;
1580 eina_log_print_prefix_update();
1589 eina_log_level_set(int level)
1591 #ifdef EINA_ENABLE_LOG
1593 if (EINA_LIKELY((EINA_LOG_DOMAIN_GLOBAL >= 0) &&
1594 ((unsigned int)EINA_LOG_DOMAIN_GLOBAL < _log_domains_count)))
1595 _log_domains[EINA_LOG_DOMAIN_GLOBAL].level = level;
1602 eina_log_level_get(void)
1604 #ifdef EINA_ENABLE_LOG
1612 eina_log_main_thread_check(void)
1614 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1615 return ((!_threads_enabled) || IS_MAIN(SELF()));
1622 eina_log_color_disable_set(Eina_Bool disabled)
1624 #ifdef EINA_ENABLE_LOG
1625 _disable_color = disabled;
1632 eina_log_color_disable_get(void)
1634 #ifdef EINA_ENABLE_LOG
1635 return _disable_color;
1642 eina_log_file_disable_set(Eina_Bool disabled)
1644 #ifdef EINA_ENABLE_LOG
1645 _disable_file = disabled;
1652 eina_log_file_disable_get(void)
1654 #ifdef EINA_ENABLE_LOG
1655 return _disable_file;
1662 eina_log_function_disable_set(Eina_Bool disabled)
1664 #ifdef EINA_ENABLE_LOG
1665 _disable_function = disabled;
1672 eina_log_function_disable_get(void)
1674 #ifdef EINA_ENABLE_LOG
1675 return _disable_function;
1682 eina_log_abort_on_critical_set(Eina_Bool abort_on_critical)
1684 #ifdef EINA_ENABLE_LOG
1685 _abort_on_critical = abort_on_critical;
1687 (void) abort_on_critical;
1692 eina_log_abort_on_critical_get(void)
1694 #ifdef EINA_ENABLE_LOG
1695 return _abort_on_critical;
1702 eina_log_abort_on_critical_level_set(int critical_level)
1704 #ifdef EINA_ENABLE_LOG
1705 _abort_level_on_critical = critical_level;
1707 (void) critical_level;
1712 eina_log_abort_on_critical_level_get(void)
1714 #ifdef EINA_ENABLE_LOG
1715 return _abort_level_on_critical;
1722 eina_log_domain_register(const char *name, const char *color)
1724 #ifdef EINA_ENABLE_LOG
1727 EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
1730 r = eina_log_domain_register_unlocked(name, color);
1741 eina_log_domain_unregister(int domain)
1743 #ifdef EINA_ENABLE_LOG
1744 EINA_SAFETY_ON_FALSE_RETURN(domain >= 0);
1746 eina_log_domain_unregister_unlocked(domain);
1754 eina_log_domain_level_set(const char *domain_name, int level)
1756 #ifdef EINA_ENABLE_LOG
1757 Eina_Log_Domain_Level_Pending *pending;
1761 EINA_SAFETY_ON_NULL_RETURN(domain_name);
1763 namelen = strlen(domain_name);
1765 for (i = 0; i < _log_domains_count; i++)
1767 if (_log_domains[i].deleted)
1770 if ((namelen != _log_domains[i].namelen) ||
1771 (strcmp(_log_domains[i].name, domain_name) != 0))
1774 _log_domains[i].level = level;
1778 EINA_INLIST_FOREACH(_pending_list, pending)
1780 if ((namelen == pending->namelen) &&
1781 (strcmp(pending->name, domain_name) == 0))
1783 pending->level = level;
1788 pending = malloc(sizeof(Eina_Log_Domain_Level_Pending) + namelen + 1);
1792 pending->level = level;
1793 pending->namelen = namelen;
1794 memcpy(pending->name, domain_name, namelen + 1);
1796 _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(pending));
1804 eina_log_domain_level_get(const char *domain_name)
1806 #ifdef EINA_ENABLE_LOG
1807 Eina_Log_Domain_Level_Pending *pending;
1811 EINA_SAFETY_ON_NULL_RETURN_VAL(domain_name, EINA_LOG_LEVEL_UNKNOWN);
1813 namelen = strlen(domain_name);
1815 for (i = 0; i < _log_domains_count; i++)
1817 if (_log_domains[i].deleted)
1820 if ((namelen != _log_domains[i].namelen) ||
1821 (strcmp(_log_domains[i].name, domain_name) != 0))
1824 return _log_domains[i].level;
1827 EINA_INLIST_FOREACH(_pending_list, pending)
1829 if ((namelen == pending->namelen) &&
1830 (strcmp(pending->name, domain_name) == 0))
1831 return pending->level;
1834 EINA_INLIST_FOREACH(_glob_list, pending)
1836 if (!fnmatch(pending->name, domain_name, 0))
1837 return pending->level;
1848 eina_log_domain_registered_level_get(int domain)
1850 #ifdef EINA_ENABLE_LOG
1851 EINA_SAFETY_ON_FALSE_RETURN_VAL(domain >= 0, EINA_LOG_LEVEL_UNKNOWN);
1852 EINA_SAFETY_ON_FALSE_RETURN_VAL((unsigned int)domain < _log_domains_count,
1853 EINA_LOG_LEVEL_UNKNOWN);
1854 EINA_SAFETY_ON_TRUE_RETURN_VAL(_log_domains[domain].deleted,
1855 EINA_LOG_LEVEL_UNKNOWN);
1856 return _log_domains[domain].level;
1863 #ifdef EINA_LOG_BACKTRACE
1864 # define DISPLAY_BACKTRACE(File, Level) \
1865 if (EINA_UNLIKELY(Level < _backtrace_level)) \
1872 btlen = backtrace((void **)bt, 256); \
1873 strings = backtrace_symbols((void **)bt, btlen); \
1874 fprintf(File, "*** Backtrace ***\n"); \
1875 for (i = 0; i < btlen; ++i) \
1876 fprintf(File, "%s\n", strings[i]); \
1880 # define DISPLAY_BACKTRACE(File, Level)
1884 eina_log_print_cb_stderr(const Eina_Log_Domain *d,
1885 Eina_Log_Level level,
1890 __UNUSED__ void *data,
1893 #ifdef EINA_ENABLE_LOG
1894 _eina_log_print_prefix(stderr, d, level, file, fnc, line);
1895 vfprintf(stderr, fmt, args);
1897 DISPLAY_BACKTRACE(stderr, level);
1911 eina_log_print_cb_stdout(const Eina_Log_Domain *d,
1912 Eina_Log_Level level,
1917 __UNUSED__ void *data,
1920 #ifdef EINA_ENABLE_LOG
1921 _eina_log_print_prefix(stdout, d, level, file, fnc, line);
1924 DISPLAY_BACKTRACE(stdout, level);
1938 eina_log_print_cb_file(const Eina_Log_Domain *d,
1939 __UNUSED__ Eina_Log_Level level,
1947 #ifdef EINA_ENABLE_LOG
1949 #ifdef EFL_HAVE_THREADS
1950 if (_threads_enabled)
1957 fprintf(f, "%s[T:%lu] %s:%d %s() ", d->name, (unsigned long)cur,
1964 fprintf(f, "%s<%u> %s:%d %s() ", d->name, eina_log_pid_get(),
1966 DISPLAY_BACKTRACE(f, level);
1967 #ifdef EFL_HAVE_THREADS
1970 vfprintf(f, fmt, args);
1984 eina_log_print(int domain, Eina_Log_Level level, const char *file,
1985 const char *fnc, int line, const char *fmt, ...)
1987 #ifdef EINA_ENABLE_LOG
1990 #ifdef EINA_SAFETY_CHECKS
1991 if (EINA_UNLIKELY(!file))
1993 fputs("ERR: eina_log_print() file == NULL\n", stderr);
1997 if (EINA_UNLIKELY(!fnc))
1999 fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
2003 if (EINA_UNLIKELY(!fmt))
2005 fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
2010 va_start(args, fmt);
2012 eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
2026 eina_log_vprint(int domain, Eina_Log_Level level, const char *file,
2027 const char *fnc, int line, const char *fmt, va_list args)
2029 #ifdef EINA_ENABLE_LOG
2031 #ifdef EINA_SAFETY_CHECKS
2032 if (EINA_UNLIKELY(!file))
2034 fputs("ERR: eina_log_print() file == NULL\n", stderr);
2038 if (EINA_UNLIKELY(!fnc))
2040 fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
2044 if (EINA_UNLIKELY(!fmt))
2046 fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
2052 eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
2066 eina_log_console_color_set(FILE *fp, const char *color)
2068 #ifdef EINA_ENABLE_LOG
2070 EINA_SAFETY_ON_NULL_RETURN(fp);
2071 EINA_SAFETY_ON_NULL_RETURN(color);
2072 if (_disable_color) return;
2075 int attr = eina_log_win32_color_convert(color, NULL);
2081 handle = GetStdHandle(STD_ERROR_HANDLE);
2082 else if (fp == stdout)
2083 handle = GetStdHandle(STD_OUTPUT_HANDLE);
2086 /* Do we have a way to convert FILE* to HANDLE?
2091 SetConsoleTextAttribute(handle, attr);