Merge pull request #743 from gvillanueva/master
[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
20 /**
21  * mono_trace_init:
22  *
23  * Initializes the mono tracer.
24  */
25 static void 
26 mono_trace_init (void)
27 {
28         if(level_stack == NULL) {
29                 level_stack = g_queue_new();
30
31                 mono_trace_set_mask_string(g_getenv("MONO_LOG_MASK"));
32                 mono_trace_set_level_string(g_getenv("MONO_LOG_LEVEL"));
33         }
34 }
35
36 /**
37  * mono_trace_cleanup:
38  *
39  * Releases the mono tracer.
40  */
41 void 
42 mono_trace_cleanup (void)
43 {
44         if(level_stack != NULL) {
45                 while(!g_queue_is_empty (level_stack)) {
46                         g_free (g_queue_pop_head (level_stack));
47                 }
48
49                 g_queue_free (level_stack);
50                 level_stack = NULL;
51         }
52 }
53
54 /**
55  * mono_trace:
56  *
57  *      @level: Verbose level of the specified message
58  *      @mask: Type of the specified message
59  *
60  * Traces a new message, depending on the current logging level
61  * and trace mask.
62  */
63 void
64 mono_trace(GLogLevelFlags level, MonoTraceMask mask, const char *format, ...) 
65 {
66         if(level_stack == NULL)
67                 mono_trace_init();
68
69         if(level <= current_level && mask & current_mask) {
70                 va_list args;
71                 va_start (args, format);
72                 g_logv (mono_log_domain, level, format, args);
73                 va_end (args);
74         }
75 }
76
77 /**
78  * mono_tracev:
79  *
80  *      @level: Verbose level of the specified message
81  *      @mask: Type of the specified message
82  *
83  * Traces a new message, depending on the current logging level
84  * and trace mask.
85  */
86 void 
87 mono_tracev (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
88 {
89         if (level_stack == NULL)
90                 mono_trace_init ();
91
92         if(level <= current_level && mask & current_mask)
93                 g_logv (mono_log_domain, level, format, args);
94 }
95
96 /**
97  * mono_trace_set_level:
98  *
99  *      @level: Verbose level to set
100  *
101  * Sets the current logging level. Every subsequent call to
102  * mono_trace will check the visibility of a message against this
103  * value.
104  */
105 void 
106 mono_trace_set_level (GLogLevelFlags level)
107 {
108         if(level_stack == NULL)
109                 mono_trace_init();
110
111         current_level = level;
112 }
113
114 /**
115  * mono_trace_set_mask:
116  *
117  *      @mask: Mask of visible message types.
118  *
119  * Sets the current logging level. Every subsequent call to
120  * mono_trace will check the visibility of a message against this
121  * value.
122  */
123 void 
124 mono_trace_set_mask (MonoTraceMask mask)
125 {
126         if(level_stack == NULL)
127                 mono_trace_init();
128
129         current_mask    = mask;
130 }
131
132 /**
133  * mono_trace_push:
134  *
135  *      @level: Verbose level to set
136  *      @mask: Mask of visible message types.
137  *
138  * Saves the current values of level and mask then calls mono_trace_set
139  * with the specified new values.
140  */
141 void 
142 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
143 {
144         if(level_stack == NULL)
145                 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
146         else {
147                 MonoLogLevelEntry *entry = g_malloc(sizeof(MonoLogLevelEntry));
148                 entry->level    = current_level;
149                 entry->mask             = current_mask;
150
151                 g_queue_push_head (level_stack, (gpointer)entry);
152
153                 /* Set the new level and mask
154                  */
155                 current_level = level;
156                 current_mask  = mask;
157         }
158 }
159
160 /**
161  * mono_trace_pop:
162  *
163  * Restores level and mask values saved from a previous call to mono_trace_push.
164  */
165 void 
166 mono_trace_pop (void)
167 {
168         if(level_stack == NULL)
169                 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
170         else {
171                 if(!g_queue_is_empty (level_stack)) {
172                         MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
173
174                         /*      Restore previous level and mask
175                          */
176                         current_level = entry->level;
177                         current_mask  = entry->mask;
178
179                         g_free (entry);
180                 }
181         }
182 }
183
184
185 void 
186 mono_trace_set_level_string (const char *value)
187 {
188         int i = 0;
189         const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
190         const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
191                                                                                 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
192
193         if(!value)
194                 return;
195
196         while(valid_vals[i]) {
197                 if(!strcmp(valid_vals[i], value)){
198                         mono_trace_set_level(valid_ids[i]);
199                         return;
200                 }
201                 i++;
202         }
203
204         if(*value)
205                 g_print("Unknown trace loglevel: %s\n", value);
206 }
207
208 void 
209 mono_trace_set_mask_string (const char *value)
210 {
211         int i;
212         const char *tok;
213         guint32 flags = 0;
214
215         const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "all", NULL};
216         const MonoTraceMask     valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
217                                                  MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY, 
218                                                  MONO_TRACE_ALL };
219
220         if(!value)
221                 return;
222
223         tok = value;
224
225         while (*tok) {
226                 if (*tok == ',') {
227                         tok++;
228                         continue;
229                 }
230                 for (i = 0; valid_flags[i]; i++) {
231                         int len = strlen (valid_flags[i]);
232                         if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
233                                 flags |= valid_masks[i];
234                                 tok += len;
235                                 break;
236                         }
237                 }
238                 if (!valid_flags[i]) {
239                         g_print("Unknown trace flag: %s\n", tok);
240                         break;
241                 }
242         }
243
244         mono_trace_set_mask (flags);
245 }
246
247 /*
248  * mono_trace_is_traced:
249  *
250  *   Returns whenever a message with @level and @mask will be printed or not.
251  */
252 gboolean
253 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
254 {
255         return (level <= current_level && mask & current_mask);
256 }