83d4547eed6b1cfec07df27fd07c1449e541f9ab
[claws.git] / src / etpan / etpan-log.c
1 #ifdef HAVE_CONFIG_H
2 #  include "config.h"
3 #endif
4
5 #ifdef HAVE_LIBETPAN
6
7 #include "etpan-log.h"
8
9 #include <pthread.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <sys/time.h>
13 #include <libetpan/libetpan.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #define MAX_LOG_LINE 1024
18 static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
19 static char log_line[MAX_LOG_LINE];
20 static chash * log_filter = NULL;
21
22 static void etpan_str_log(void)
23 {
24   fprintf(stderr, "%s\n", log_line);
25 }
26
27 void etpan_log_init(void)
28 {
29   pthread_mutex_lock(&log_lock);
30   if (log_filter == NULL) {
31     char * env_value;
32     
33     env_value = getenv("ETPAN_LOG");
34     if (env_value != NULL) {
35       strncpy(log_line, env_value, sizeof(log_line));
36       log_line[sizeof(log_line) - 1] = '\0';
37     }
38     else {
39       * log_line = '\0';
40     }
41     env_value = log_line;
42     
43     log_filter = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
44     if (log_filter != NULL) {
45       chashdatum key;
46       chashdatum value;
47       
48       key.data = "LOG";
49       key.len = strlen("LOG");
50       value.data = NULL;
51       value.len = 0;
52       chash_set(log_filter, &key, &value, NULL);
53       
54       while (env_value != NULL) {
55         char * p;
56         
57         p = strchr(env_value, ' ');
58         if (p != NULL) {
59           * p = '\0';
60           key.data = env_value;
61           key.len = strlen(env_value);
62           value.data = NULL;
63           value.len = 0;
64           chash_set(log_filter, &key, &value, NULL);
65           
66           env_value = p + 1;
67         }
68         else {
69           key.data = env_value;
70           key.len = strlen(env_value);
71           value.data = NULL;
72           value.len = 0;
73           chash_set(log_filter, &key, &value, NULL);
74           
75           env_value = p;
76         }
77       }
78     }
79   }
80   pthread_mutex_unlock(&log_lock);
81 }
82
83 void etpan_log_done(void)
84 {
85   pthread_mutex_lock(&log_lock);
86   if (log_filter != NULL) {
87     chash_free(log_filter);
88     log_filter = NULL;
89   }
90   pthread_mutex_unlock(&log_lock);
91 }
92
93 void etpan_log(char * log_id, char * format, ...)
94 {
95   va_list argp;
96   struct timeval time_info;
97   int r;
98   chashdatum key;
99   chashdatum value;
100   
101   etpan_log_init();
102   
103   key.data = log_id;
104   key.len = strlen(log_id);
105   r = chash_get(log_filter, &key, &value);
106   if (r < 0)
107     return;
108   
109   r = gettimeofday(&time_info, NULL);
110   if (r == 0) {
111     fprintf(stderr, "%4lu.%03u [%s] ", time_info.tv_sec % 3600,
112         (unsigned int) (time_info.tv_usec / 1000), log_id);
113   }
114   
115   va_start(argp, format);
116   pthread_mutex_lock(&log_lock);
117   vsnprintf(log_line, sizeof(log_line), format, argp);
118   etpan_str_log();
119   pthread_mutex_unlock(&log_lock);
120   va_end(argp);
121 }
122
123 #if defined(__APPLE__) && defined(__MACH__)
124 #include <mach/vm_types.h>
125
126 extern void thread_stack_pcs(vm_address_t *buffer,
127     unsigned max, unsigned *num);
128
129 void etpan_log_stack(void)
130 {
131   unsigned buffer[256];
132   int num_frames;
133   int i;
134   char output[1024];
135   char * current_output;
136   size_t remaining;
137   
138   thread_stack_pcs(buffer, sizeof(buffer) / sizeof(buffer[0]), &num_frames);
139   remaining = sizeof(output);
140   current_output = output;
141   for(i = 0 ; i < num_frames ; i ++) {
142     size_t len;
143     
144     snprintf(current_output, remaining, "0x%x ", buffer[i]);
145     len = strlen(current_output);
146     remaining -= len;
147     current_output += len;
148     if (remaining == 0)
149       break;
150   }
151   ETPAN_STACK_LOG(output);
152 }
153 #else
154 #if defined(__linux__)
155 #include <execinfo.h>
156
157 extern char **backtrace_symbols (void *__const *__array, int __size) __THROW;
158
159 void etpan_log_stack(void)
160 {
161   void * buffer[256];
162   char ** table;
163   int num_frames;
164   int i;
165   char output[1024];
166   char * current_output;
167   size_t remaining;
168   
169   num_frames = backtrace(buffer, sizeof(buffer) / sizeof(buffer[0]));
170   remaining = sizeof(output);
171   current_output = output;
172   for(i = 0 ; i < num_frames ; i ++) {
173     size_t len;
174     
175     snprintf(current_output, remaining, "%p ", buffer[i]);
176     len = strlen(current_output);
177     remaining -= len;
178     current_output += len;
179     if (remaining == 0)
180       break;
181   }
182   ETPAN_STACK_LOG(output);
183 }
184
185 #else
186
187 void etpan_log_stack(void)
188 {
189   ETPAN_STACK_LOG("this feature not available");
190 }
191
192 #endif
193 #endif
194 #endif