2003-10-13 Zoltan Varga <vargaz@freemail.hu>
[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_INFO;
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 <= current_level && mask & current_mask)
89                 g_logv (mono_log_domain, level, format, args);
90 }
91
92 /**
93  * mono_trace_set_level:
94  *
95  *      @level: Verbose level to set
96  *
97  * Sets the current logging level. Every subsequent call to
98  * mono_trace will check the visibility of a message against this
99  * value.
100  */
101 void 
102 mono_trace_set_level (GLogLevelFlags level)
103 {
104         if(level_stack == NULL)
105                 mono_trace_init();
106
107         current_level = level;
108 }
109
110 /**
111  * mono_trace_set_mask:
112  *
113  *      @mask: Mask of visible message types.
114  *
115  * Sets the current logging level. Every subsequent call to
116  * mono_trace will check the visibility of a message against this
117  * value.
118  */
119 void 
120 mono_trace_set_mask (MonoTraceMask mask)
121 {
122         if(level_stack == NULL)
123                 mono_trace_init();
124
125         current_mask    = mask;
126 }
127
128 /**
129  * mono_trace_push:
130  *
131  *      @level: Verbose level to set
132  *      @mask: Mask of visible message types.
133  *
134  * Saves the current values of level and mask then calls mono_trace_set
135  * with the specified new values.
136  */
137 void 
138 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
139 {
140         if(level_stack == NULL)
141                 g_error(G_GNUC_PRETTY_FUNCTION ": cannot use mono_trace_push without calling mono_trace_init first.");
142         else {
143                 MonoLogLevelEntry *entry = g_malloc(sizeof(MonoLogLevelEntry));
144                 entry->level    = current_level;
145                 entry->mask             = current_mask;
146
147         g_queue_push_head (level_stack, (gpointer)entry);
148
149                 /* Set the new level and mask
150                  */
151                 current_level = level;
152                 current_mask  = mask;
153         }
154 }
155
156 /**
157  * mono_trace_pop:
158  *
159  * Restores level and mask values saved from a previous call to mono_trace_push.
160  */
161 void 
162 mono_trace_pop (void)
163 {
164         if(level_stack == NULL)
165                 g_error(G_GNUC_PRETTY_FUNCTION ": cannot use mono_trace_pop without calling mono_trace_init first.");
166         else {
167                 if(!g_queue_is_empty (level_stack)) {
168                         MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
169
170                         /*      Restore previous level and mask
171                          */
172                         current_level = entry->level;
173                         current_mask  = entry->mask;
174
175                         g_free (entry);
176                 }
177         }
178 }
179
180
181 void 
182 mono_trace_set_level_string (const char *value)
183 {
184         int i = 0;
185         const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
186         const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
187                                                                                 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
188
189         if(!value)
190                 return;
191
192         while(valid_vals[i]) {
193                 if(!strcmp(valid_vals[i], value)){
194                         mono_trace_set_level(valid_ids[i]);
195                         return;
196                 }
197                 i++;
198         }
199
200         if(*value)
201                 g_print("Unknown trace loglevel: %s\n", value);
202 }
203
204 void 
205 mono_trace_set_mask_string (char *value)
206 {
207         int i;
208         char *tok;
209         guint32 flags = 0;
210
211         const char *valid_flags[] = {"asm", "type", "dll", "gc", "all", NULL};
212         const MonoTraceMask     valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
213                                                                                         MONO_TRACE_GC, MONO_TRACE_ALL };
214
215         if(!value)
216                 return;
217
218         tok     = strtok (value, ",");
219
220         if(!tok)
221                 tok = value;
222
223         while (tok) {
224                 for (i = 0; valid_flags[i]; i++) {
225                         if (strcmp (tok, valid_flags[i]) == 0) {
226                                 flags |= valid_masks[i];
227                                 break;
228                         }
229                 }
230                 if (!valid_flags[i])
231                         g_print("Unknown trace flag: %s\n", tok);
232
233                 tok = strtok (NULL, ",");
234         }
235
236         if(flags)
237                 mono_trace_set_mask (flags);
238 }