[System] Fixes UdpClient.Receive with IPv6 endpoint
[mono.git] / mono / utils / mono-logger.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <glib.h>
5
6 #include "mono-compiler.h"
7 #include "mono-logger-internal.h"
8
9 typedef struct {
10         GLogLevelFlags  level;
11         MonoTraceMask   mask;
12 } MonoLogLevelEntry;
13
14 static GLogLevelFlags current_level             = G_LOG_LEVEL_ERROR;
15 static MonoTraceMask current_mask               = MONO_TRACE_ALL;
16
17 static const char       *mono_log_domain        = "Mono";
18 static GQueue           *level_stack            = NULL;
19 static MonoPrintCallback print_callback, printerr_callback;
20
21 /**
22  * mono_trace_init:
23  *
24  * Initializes the mono tracer.
25  */
26 static void 
27 mono_trace_init (void)
28 {
29         if(level_stack == NULL) {
30                 level_stack = g_queue_new();
31
32                 mono_trace_set_mask_string(g_getenv("MONO_LOG_MASK"));
33                 mono_trace_set_level_string(g_getenv("MONO_LOG_LEVEL"));
34         }
35 }
36
37 /**
38  * mono_trace_cleanup:
39  *
40  * Releases the mono tracer.
41  */
42 void 
43 mono_trace_cleanup (void)
44 {
45         if(level_stack != NULL) {
46                 while(!g_queue_is_empty (level_stack)) {
47                         g_free (g_queue_pop_head (level_stack));
48                 }
49
50                 g_queue_free (level_stack);
51                 level_stack = NULL;
52         }
53 }
54
55 /**
56  * mono_trace:
57  *
58  *      @level: Verbose level of the specified message
59  *      @mask: Type of the specified message
60  *
61  * Traces a new message, depending on the current logging level
62  * and trace mask.
63  */
64 void
65 mono_trace(GLogLevelFlags level, MonoTraceMask mask, const char *format, ...) 
66 {
67         if(level_stack == NULL)
68                 mono_trace_init();
69
70         if(level <= current_level && mask & current_mask) {
71                 va_list args;
72                 va_start (args, format);
73                 g_logv (mono_log_domain, level, format, args);
74                 va_end (args);
75         }
76 }
77
78 /**
79  * mono_tracev:
80  *
81  *      @level: Verbose level of the specified message
82  *      @mask: Type of the specified message
83  *
84  * Traces a new message, depending on the current logging level
85  * and trace mask.
86  */
87 void 
88 mono_tracev (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
89 {
90         if (level_stack == NULL)
91                 mono_trace_init ();
92
93         if(level <= current_level && mask & current_mask)
94                 g_logv (mono_log_domain, level, format, args);
95 }
96
97 /**
98  * mono_trace_set_level:
99  *
100  *      @level: Verbose level to set
101  *
102  * Sets the current logging level. Every subsequent call to
103  * mono_trace will check the visibility of a message against this
104  * value.
105  */
106 void 
107 mono_trace_set_level (GLogLevelFlags level)
108 {
109         if(level_stack == NULL)
110                 mono_trace_init();
111
112         current_level = level;
113 }
114
115 /**
116  * mono_trace_set_mask:
117  *
118  *      @mask: Mask of visible message types.
119  *
120  * Sets the current logging level. Every subsequent call to
121  * mono_trace will check the visibility of a message against this
122  * value.
123  */
124 void 
125 mono_trace_set_mask (MonoTraceMask mask)
126 {
127         if(level_stack == NULL)
128                 mono_trace_init();
129
130         current_mask    = mask;
131 }
132
133 /**
134  * mono_trace_push:
135  *
136  *      @level: Verbose level to set
137  *      @mask: Mask of visible message types.
138  *
139  * Saves the current values of level and mask then calls mono_trace_set
140  * with the specified new values.
141  */
142 void 
143 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
144 {
145         if(level_stack == NULL)
146                 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
147         else {
148                 MonoLogLevelEntry *entry = (MonoLogLevelEntry *) g_malloc(sizeof(MonoLogLevelEntry));
149                 entry->level    = current_level;
150                 entry->mask             = current_mask;
151
152                 g_queue_push_head (level_stack, (gpointer)entry);
153
154                 /* Set the new level and mask
155                  */
156                 current_level = level;
157                 current_mask  = mask;
158         }
159 }
160
161 /**
162  * mono_trace_pop:
163  *
164  * Restores level and mask values saved from a previous call to mono_trace_push.
165  */
166 void 
167 mono_trace_pop (void)
168 {
169         if(level_stack == NULL)
170                 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
171         else {
172                 if(!g_queue_is_empty (level_stack)) {
173                         MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
174
175                         /*      Restore previous level and mask
176                          */
177                         current_level = entry->level;
178                         current_mask  = entry->mask;
179
180                         g_free (entry);
181                 }
182         }
183 }
184
185
186 void 
187 mono_trace_set_level_string (const char *value)
188 {
189         int i = 0;
190         const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
191         const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
192                                                                                 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
193
194         if(!value)
195                 return;
196
197         while(valid_vals[i]) {
198                 if(!strcmp(valid_vals[i], value)){
199                         mono_trace_set_level(valid_ids[i]);
200                         return;
201                 }
202                 i++;
203         }
204
205         if(*value)
206                 g_print("Unknown trace loglevel: %s\n", value);
207 }
208
209 void 
210 mono_trace_set_mask_string (const char *value)
211 {
212         int i;
213         const char *tok;
214         guint32 flags = 0;
215
216         const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "all", NULL};
217         const MonoTraceMask     valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
218                                                  MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY,
219                                                  MONO_TRACE_THREADPOOL, MONO_TRACE_IO_THREADPOOL, MONO_TRACE_ALL };
220
221         if(!value)
222                 return;
223
224         tok = value;
225
226         while (*tok) {
227                 if (*tok == ',') {
228                         tok++;
229                         continue;
230                 }
231                 for (i = 0; valid_flags[i]; i++) {
232                         int len = strlen (valid_flags[i]);
233                         if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
234                                 flags |= valid_masks[i];
235                                 tok += len;
236                                 break;
237                         }
238                 }
239                 if (!valid_flags[i]) {
240                         g_print("Unknown trace flag: %s\n", tok);
241                         break;
242                 }
243         }
244
245         mono_trace_set_mask ((MonoTraceMask) flags);
246 }
247
248 /*
249  * mono_trace_is_traced:
250  *
251  *   Returns whenever a message with @level and @mask will be printed or not.
252  */
253 gboolean
254 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
255 {
256         return (level <= current_level && mask & current_mask);
257 }
258
259 static MonoLogCallback log_callback;
260
261 static const char*
262 log_level_get_name (GLogLevelFlags log_level)
263 {
264         switch (log_level & G_LOG_LEVEL_MASK) {
265         case G_LOG_LEVEL_ERROR: return "error";
266         case G_LOG_LEVEL_CRITICAL: return "critical";
267         case G_LOG_LEVEL_WARNING: return "warning";
268         case G_LOG_LEVEL_MESSAGE: return "message";
269         case G_LOG_LEVEL_INFO: return "info";
270         case G_LOG_LEVEL_DEBUG: return "debug";
271         default: return "unknown";
272         }
273 }
274
275 static void
276 log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
277 {
278         log_callback (log_domain, log_level_get_name (log_level), message, log_level & G_LOG_LEVEL_ERROR, user_data);
279 }
280
281 /**
282  * mono_trace_set_log_handler:
283  *
284  *  @callback The callback that will replace the default logging handler
285  *  @user_data Argument passed to @callback
286  *
287  * The log handler replaces the default runtime logger. All logging requests with be routed to it.
288  * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
289  * execution will not resume after a fatal error.
290  */
291 void
292 mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
293 {
294         g_assert (callback);
295         log_callback = callback;
296         g_log_set_default_handler (log_adapter, user_data);
297 }
298
299 static void
300 print_handler (const char *string)
301 {
302         print_callback (string, TRUE);
303 }
304
305 static void
306 printerr_handler (const char *string)
307 {
308         printerr_callback (string, FALSE);
309 }
310
311 /**
312  * mono_trace_set_print_handler:
313  *
314  * @callback The callback that will replace the default runtime behavior for stdout output.
315  *
316  * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
317  *
318  */
319 void
320 mono_trace_set_print_handler (MonoPrintCallback callback)
321 {
322         g_assert (callback);
323         print_callback = callback;
324         g_set_print_handler (print_handler);
325 }
326
327 /**
328  * mono_trace_set_printerr_handler:
329  *
330  * @callback The callback that will replace the default runtime behavior for stderr output.
331  *
332  * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
333  *
334  */
335 void
336 mono_trace_set_printerr_handler (MonoPrintCallback callback)
337 {
338         g_assert (callback);
339         printerr_callback = callback;
340         g_set_printerr_handler (printerr_handler);
341 }