the repository of RSA merge with private repository.
[platform/core/uifw/e17.git] / src / bin / e_log.c
1 #include "e.h"
2
3 #ifndef E_LOG_LEVEL
4 # define E_LOG_LEVEL EINA_LOG_LEVEL_INFO
5 #endif
6
7 EINTERN int e_log_dom = -1;
8
9 static const char *_names[] = {
10    "CRI",
11    "ERR",
12    "WRN",
13    "INF",
14    "DBG",
15 };
16
17 static void
18 _e_log_cb(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc __UNUSED__, int line, const char *fmt, void *data __UNUSED__, va_list args)
19 {
20    const char *color;
21
22    color = eina_log_level_color_get(level);
23    fprintf(stdout,
24            "%s%s<" EINA_COLOR_RESET "%s%s>" EINA_COLOR_RESET "%s:%d" EINA_COLOR_RESET " ",
25            color, _names[level > EINA_LOG_LEVEL_DBG ? EINA_LOG_LEVEL_DBG : level],
26            d->domain_str, color, file, line);
27    vfprintf(stdout, fmt, args);
28    putc('\n', stdout);
29 }
30
31 EINTERN int
32 e_log_init(void)
33 {
34    e_log_dom = eina_log_domain_register("e", EINA_COLOR_WHITE);
35    eina_log_domain_level_set("e", E_LOG_LEVEL);
36    eina_log_print_cb_set(_e_log_cb, NULL);
37    return (e_log_dom != -1);
38 }
39
40 EINTERN int
41 e_log_shutdown(void)
42 {
43    eina_log_domain_unregister(e_log_dom);
44    e_log_dom = -1;
45    return 0;
46 }
47
48 #ifdef _F_E_LOGBUF_
49 EAPI unsigned int e_logbuf_type = ELBT_NONE;
50
51 #define MAX_LOGS 9216
52 #define MAX_LOG_FUNC_STR_SIZE 20
53 #define MAX_LOG_STR_SIZE 80
54
55 typedef struct _E_Log
56 {
57    unsigned int      num;
58    unsigned int      type;
59    unsigned int      blank;
60    char              func[MAX_LOG_FUNC_STR_SIZE];
61    int               line;
62    unsigned int      id; // Ecore_X_Window or Zone ID
63    char              str[MAX_LOG_STR_SIZE];
64 } E_Log;
65
66 typedef struct _E_Logbuf
67 {
68    E_DBus_Interface    *iface;
69    int                  cur;
70    int                  num;
71    Eina_Bool            pts;
72    FILE                *fp;
73    Eina_List           *list; // list of E_Log
74    Ecore_Event_Handler *h;
75    Ecore_X_Atom         a;
76 } E_Logbuf;
77
78 static E_Logbuf *buf = NULL;
79
80 static void _log_disp(FILE *fp, E_Log *m);
81
82 EAPI void
83 e_logbuf_add(unsigned int type,
84              const char  *func,
85              int          line,
86              const char  *str,
87              unsigned int id)
88 {
89    E_Log *msg = NULL;
90    if (!buf) return;
91
92    if (eina_list_count(buf->list) < MAX_LOGS)
93      {
94         msg = E_NEW(E_Log, 1);
95         if (msg)
96           buf->list = eina_list_append(buf->list, msg);
97      }
98    else
99      {
100         buf->cur = (buf->cur) % MAX_LOGS;
101         msg = eina_list_nth(buf->list, buf->cur);
102      }
103
104    if (msg)
105      {
106         unsigned int n = 0;
107         msg->num = buf->num++;
108         msg->type = type;
109         msg->blank = 0;
110
111         n = sizeof(msg->func);
112         if (n >= MAX_LOG_FUNC_STR_SIZE)
113           {
114              strncpy(msg->func, func, MAX_LOG_FUNC_STR_SIZE-1);
115              msg->func[MAX_LOG_FUNC_STR_SIZE-1] = '\0';
116           }
117         else
118           {
119              strncpy(msg->func, func, n);
120           }
121
122         msg->line = line;
123         msg->id = id;
124
125         n = sizeof(msg->str);
126         if (n >= MAX_LOG_STR_SIZE)
127           {
128              strncpy(msg->str, str, MAX_LOG_STR_SIZE-1);
129              msg->str[MAX_LOG_STR_SIZE-1] = '\0';
130           }
131         else
132           {
133              strncpy(msg->str, str, n);
134           }
135
136         buf->cur = (buf->num) % MAX_LOGS;
137
138         if ((buf->pts) && (buf->fp))
139           _log_disp(buf->fp, msg);
140      }
141 }
142
143 EAPI void
144 e_logbuf_fmt_add(unsigned int type,
145                  unsigned int blank,
146                  const char  *func,
147                  int          line,
148                  unsigned int id,
149                  const char  *fmt,
150                  ...)
151 {
152    E_Log *msg = NULL;
153    va_list args;
154    if (!buf) return;
155
156    if (eina_list_count(buf->list) < MAX_LOGS)
157      {
158         msg = E_NEW(E_Log, 1);
159         if (msg)
160           buf->list = eina_list_append(buf->list, msg);
161      }
162    else
163      {
164         buf->cur = (buf->cur) % MAX_LOGS;
165         msg = eina_list_nth(buf->list, buf->cur);
166      }
167
168    if (msg)
169      {
170         unsigned int n = 0;
171         msg->num = buf->num++;
172         msg->type = type;
173         msg->blank = blank;
174
175         n = sizeof(msg->func);
176         if (n >= MAX_LOG_FUNC_STR_SIZE)
177           {
178              strncpy(msg->func, func, MAX_LOG_FUNC_STR_SIZE-1);
179              msg->func[MAX_LOG_FUNC_STR_SIZE-1] = '\0';
180           }
181         else
182           {
183              strncpy(msg->func, func, n);
184           }
185
186         msg->line = line;
187         msg->id = id;
188
189         va_start(args, fmt);
190         vsnprintf(msg->str, sizeof(msg->str), fmt, args);
191         va_end(args);
192
193         buf->cur = (buf->num) % MAX_LOGS;
194
195         if ((buf->pts) && (buf->fp))
196           _log_disp(buf->fp, msg);
197      }
198 }
199
200 static void
201 _e_logbuf_shutdown(void)
202 {
203    e_logbuf_type = ELBT_NONE;
204
205    if (buf)
206      {
207         E_Log *msg = NULL;
208         EINA_LIST_FREE(buf->list, msg) E_FREE(msg);
209         buf->list = NULL;
210         if (buf->iface)
211           {
212              e_msgbus_interface_detach(buf->iface);
213              e_dbus_interface_unref(buf->iface);
214              buf->iface = NULL;
215           }
216         if (buf->h)
217           ecore_event_handler_del(buf->h);
218         memset(buf, 0, sizeof(E_Logbuf));
219         E_FREE(buf);
220         buf = NULL;
221      }
222 }
223
224 static const char *
225 _type_name_get(unsigned int t)
226 {
227    switch (t)
228      {
229       case ELBT_NONE:   return "NONE";   break;
230       case ELBT_DFT:    return "DFT";    break;
231       case ELBT_MNG:    return "MNG";    break;
232       case ELBT_BD:     return "BD";     break;
233       case ELBT_ROT:    return "ROT";    break;
234       case ELBT_ILLUME: return "ILLUME"; break;
235       case ELBT_COMP:   return "COMP";   break;
236       case ELBT_MOVE:   return "MOVE";   break;
237       case ELBT_TRACE:  return "TRACE";  break;
238       case ELBT_ALL:    return "ALL";    break;
239       default: break;
240      }
241    return NULL;
242 }
243
244 static void
245 _log_disp(FILE  *fp,
246           E_Log *m)
247 {
248    if (m->blank)
249      {
250         if (m->id)
251           fprintf(fp, "%38.38s|0x%08x|%s\n",
252                   "", m->id, m->str);
253         else
254           fprintf(fp, "%49.49s|%s\n",
255                   "", m->str);
256      }
257    else
258      {
259         if (m->id)
260           fprintf(fp, "%5d|%20.20s|%5d|%5.5s|0x%08x|%s\n",
261                   m->num, m->func, m->line,
262                   _type_name_get(m->type), m->id, m->str);
263         else
264           fprintf(fp, "%5d|%20.20s|%5d|%5.5s|%10.10s|%s\n",
265                   m->num, m->func, m->line,
266                   _type_name_get(m->type), "", m->str);
267      }
268 }
269
270 static void
271 _e_log_dump(FILE *fp)
272 {
273    Eina_List *l = NULL, *ll = NULL;
274    E_Log *msg = NULL;
275    unsigned int idx = 0;
276    if ((!buf) || (!fp)) return;
277
278    ll = eina_list_nth_list(buf->list, buf->cur);
279    EINA_LIST_FOREACH(ll, l, msg)
280      {
281         _log_disp(fp, msg);
282         idx = msg->num;
283      }
284    EINA_LIST_FOREACH(buf->list, l, msg)
285      {
286         if (msg->num < idx) break;
287         _log_disp(fp, msg);
288         idx = msg->num;
289      }
290    fprintf(fp, "Total:%d Num:%d\n", eina_list_count(buf->list), buf->num);
291    fflush(fp);
292 }
293
294 static DBusMessage *
295 _e_log_cb_enable(E_DBus_Object *obj __UNUSED__,
296                  DBusMessage       *msg)
297 {
298    e_logbuf_type = ELBT_ALL;
299    return dbus_message_new_method_return(msg);
300 }
301
302 static DBusMessage *
303 _e_log_cb_disable(E_DBus_Object *obj __UNUSED__,
304                   DBusMessage       *msg)
305 {
306    e_logbuf_type = ELBT_NONE;
307    return dbus_message_new_method_return(msg);
308 }
309
310 static DBusMessage *
311 _e_log_cb_dump(E_DBus_Object *obj __UNUSED__,
312                DBusMessage       *msg)
313 {
314    DBusError err;
315    const char *path = NULL;
316    FILE *fp = NULL;
317
318    dbus_error_init(&err);
319    if (!dbus_message_get_args(msg, &err,
320                               DBUS_TYPE_STRING, &path,
321                               DBUS_TYPE_INVALID))
322      {
323         fprintf(stderr,
324                 "could not get Log.Dump arguments: %s: %s",
325                 err.name, err.message);
326         dbus_error_free(&err);
327      }
328    else if (path)
329      {
330         if (buf)
331           {
332              Eina_Bool pts = EINA_FALSE;
333              if (strstr(path, "/dev/pts/"))
334                pts = EINA_TRUE;
335
336              fp = fopen(path, "w");
337              if (fp)
338                {
339                   _e_log_dump(fp);
340
341                   if (buf->fp)
342                     {
343                        fclose(buf->fp);
344                        buf->fp = NULL;
345                     }
346
347                   if (pts)
348                     {
349                        buf->pts = EINA_TRUE;
350                        buf->fp = fp;
351                     }
352                   else
353                     fclose(fp);
354
355                   fprintf(stdout,
356                           "dump log messages to file:%s\n",
357                           path);
358                }
359           }
360      }
361
362    return dbus_message_new_method_return(msg);
363 }
364
365 static Eina_Bool
366 _e_log_cb_prop(void *data __UNUSED__,
367                int type   __UNUSED__,
368                void      *event)
369 {
370    Ecore_X_Event_Window_Property *ev = event;
371    char *path = NULL;
372    FILE *fp = NULL;
373
374    if (!ev) return ECORE_CALLBACK_PASS_ON;
375    if (!ev->atom) return ECORE_CALLBACK_PASS_ON;
376    if (!buf) return ECORE_CALLBACK_PASS_ON;
377    if (ev->atom != buf->a) return ECORE_CALLBACK_PASS_ON;
378
379    path = ecore_x_window_prop_string_get(ev->win, ev->atom);
380    if (!path) return ECORE_CALLBACK_PASS_ON;
381
382    fp = fopen(path, "w");
383    if (!fp) return ECORE_CALLBACK_PASS_ON;
384
385    _e_log_dump(fp);
386    if (buf->fp)
387      {
388         fclose(buf->fp);
389         buf->pts = EINA_FALSE;
390         buf->fp = NULL;
391      }
392    fprintf(stdout,
393            "dump log messages to file:%s\n",
394            path);
395
396    fclose(fp);
397    return ECORE_CALLBACK_PASS_ON;
398 }
399
400 EINTERN int
401 e_logbuf_init(void)
402 {
403    _e_logbuf_shutdown();
404
405    buf = E_NEW(E_Logbuf, 1);
406    if (!buf) return 0;
407
408    buf->iface = e_dbus_interface_new("org.enlightenment.wm.Log");
409    if (!buf->iface)
410      {
411         fprintf(stderr, "Cannot add org.enlightenment.wm.Log interface\n");
412         memset(buf, 0, sizeof(E_Logbuf));
413         E_FREE(buf);
414         return 0;
415      }
416
417    e_dbus_interface_method_add(buf->iface, "Enable", "", "",   _e_log_cb_enable);
418    e_dbus_interface_method_add(buf->iface, "Disable", "", "",  _e_log_cb_disable);
419    e_dbus_interface_method_add(buf->iface, "Dump", "s", "",    _e_log_cb_dump);
420
421    e_msgbus_interface_attach(buf->iface);
422
423    buf->h = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _e_log_cb_prop, NULL);
424    buf->a = ecore_x_atom_get("_E_LOG");
425
426    e_logbuf_type = ELBT_ALL;
427
428    return 1;
429 }
430
431 EINTERN int
432 e_logbuf_shutdown(void)
433 {
434    _e_logbuf_shutdown();
435    return 1;
436 }
437 #endif