Uniform use of the return error from mono_dl
[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.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(getenv("MONO_LOG_MASK"));
32                 mono_trace_set_level_string(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 (char *value)
210 {
211         int i;
212         char *tok;
213         guint32 flags = 0;
214
215         const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "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_ALL };
218
219         if(!value)
220                 return;
221
222         tok     = strtok (value, ",");
223
224         if(!tok)
225                 tok = value;
226
227         while (tok) {
228                 for (i = 0; valid_flags[i]; i++) {
229                         if (strcmp (tok, valid_flags[i]) == 0) {
230                                 flags |= valid_masks[i];
231                                 break;
232                         }
233                 }
234                 if (!valid_flags[i])
235                         g_print("Unknown trace flag: %s\n", tok);
236
237                 tok = strtok (NULL, ",");
238         }
239
240         if(flags)
241                 mono_trace_set_mask (flags);
242 }
243
244 /*
245  * mono_trace_is_traced:
246  *
247  *   Returns whenever a message with @level and @mask will be printed or not.
248  */
249 gboolean
250 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
251 {
252         return (level <= current_level && mask & current_mask);
253 }