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