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