[tools] Add nuget-hash-extractor tool to help produce the runtime ignored assemblies...
[mono-project.git] / mono / utils / mono-logger.c
blob5cc59c77fbe6dd87bf56d097df56dc7380e9baf9
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <glib.h>
6 #include "mono-compiler.h"
7 #include "mono-logger-internals.h"
9 typedef struct {
10 GLogLevelFlags level;
11 MonoTraceMask mask;
12 } MonoLogLevelEntry;
14 GLogLevelFlags mono_internal_current_level = INT_MAX;
15 MonoTraceMask mono_internal_current_mask = MONO_TRACE_ALL;
16 gboolean mono_trace_log_header = FALSE;
18 static GQueue *level_stack = NULL;
19 static const char *mono_log_domain = "Mono";
20 static MonoPrintCallback print_callback, printerr_callback;
22 static MonoLogCallParm logCallback = {
23 .opener = NULL,
24 .writer = NULL,
25 .closer = NULL,
26 .header = FALSE
29 typedef struct {
30 MonoLogCallback legacy_callback;
31 gpointer user_data;
32 } UserSuppliedLoggerUserData;
34 /**
35 * mono_trace_init:
37 * Initializes the mono tracer.
39 void
40 mono_trace_init (void)
42 if(level_stack == NULL) {
43 mono_internal_current_level = G_LOG_LEVEL_ERROR;
44 level_stack = g_queue_new();
46 mono_trace_set_mask_string(g_getenv("MONO_LOG_MASK"));
47 mono_trace_set_level_string(g_getenv("MONO_LOG_LEVEL"));
48 mono_trace_set_logheader_string(g_getenv("MONO_LOG_HEADER"));
49 mono_trace_set_logdest_string(g_getenv("MONO_LOG_DEST"));
53 /**
54 * mono_trace_cleanup:
56 * Releases the mono tracer.
58 void
59 mono_trace_cleanup (void)
61 if(level_stack != NULL) {
62 while(!g_queue_is_empty (level_stack)) {
63 g_free (g_queue_pop_head (level_stack));
66 logCallback.closer();
67 g_queue_free (level_stack);
68 level_stack = NULL;
72 /**
73 * mono_tracev:
75 * @level: Verbose level of the specified message
76 * @mask: Type of the specified message
78 * Traces a new message, depending on the current logging level
79 * and trace mask.
81 void
82 mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
84 char *log_message;
85 if (level_stack == NULL) {
86 mono_trace_init ();
87 if(level > mono_internal_current_level || !(mask & mono_internal_current_mask))
88 return;
91 g_assert (logCallback.opener); // mono_trace_init should have provided us with one!
93 if (g_vasprintf (&log_message, format, args) < 0)
94 return;
95 logCallback.writer (mono_log_domain, level, logCallback.header, log_message);
96 g_free (log_message);
99 /**
100 * mono_trace_set_level:
102 * @level: Verbose level to set
104 * Sets the current logging level. Every subsequent call to
105 * mono_trace will check the visibility of a message against this
106 * value.
108 void
109 mono_trace_set_level (GLogLevelFlags level)
111 if(level_stack == NULL)
112 mono_trace_init();
114 mono_internal_current_level = level;
118 * mono_trace_set_mask:
120 * @mask: Mask of visible message types.
122 * Sets the current logging level. Every subsequent call to
123 * mono_trace will check the visibility of a message against this
124 * value.
126 void
127 mono_trace_set_mask (MonoTraceMask mask)
129 if(level_stack == NULL)
130 mono_trace_init();
132 mono_internal_current_mask = mask;
136 * mono_trace_set_logdest:
138 * @dest: Destination for logging
140 * Sets the current logging destination. This can be a file or, if supported,
141 * syslog.
143 void
144 mono_trace_set_logdest_string (const char *dest)
146 MonoLogCallParm logger;
148 if(level_stack == NULL)
149 mono_trace_init();
151 #if PLATFORM_ANDROID
152 logger.opener = mono_log_open_logcat;
153 logger.writer = mono_log_write_logcat;
154 logger.closer = mono_log_close_logcat;
155 logger.dest = (char*) dest;
156 #elif defined (HOST_IOS)
157 logger.opener = mono_log_open_asl;
158 logger.writer = mono_log_write_asl;
159 logger.closer = mono_log_close_asl;
160 logger.dest = (char*) dest;
161 #else
162 if ((dest == NULL) || (strcmp("syslog", dest) != 0)) {
163 logger.opener = mono_log_open_logfile;
164 logger.writer = mono_log_write_logfile;
165 logger.closer = mono_log_close_logfile;
166 logger.dest = (char *) dest;
167 } else {
168 logger.opener = mono_log_open_syslog;
169 logger.writer = mono_log_write_syslog;
170 logger.closer = mono_log_close_syslog;
171 logger.dest = (char *) dest;
173 #endif
174 mono_trace_set_log_handler_internal(&logger, NULL);
178 * mono_trace_set_logheader:
180 * @head: Whether we want pid/date/time header on log messages
182 * Sets the current logging header option.
184 void
185 mono_trace_set_logheader_string(const char *head)
187 if (head == NULL) {
188 mono_trace_log_header = FALSE;
189 } else {
190 mono_trace_log_header = TRUE;
195 * mono_trace_push:
197 * @level: Verbose level to set
198 * @mask: Mask of visible message types.
200 * Saves the current values of level and mask then calls mono_trace_set
201 * with the specified new values.
203 void
204 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
206 if(level_stack == NULL)
207 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
208 else {
209 MonoLogLevelEntry *entry = (MonoLogLevelEntry *) g_malloc(sizeof(MonoLogLevelEntry));
210 entry->level = mono_internal_current_level;
211 entry->mask = mono_internal_current_mask;
213 g_queue_push_head (level_stack, (gpointer)entry);
215 /* Set the new level and mask
217 mono_internal_current_level = level;
218 mono_internal_current_mask = mask;
223 * mono_trace_pop:
225 * Restores level and mask values saved from a previous call to mono_trace_push.
227 void
228 mono_trace_pop (void)
230 if(level_stack == NULL)
231 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
232 else {
233 if(!g_queue_is_empty (level_stack)) {
234 MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
236 /* Restore previous level and mask
238 mono_internal_current_level = entry->level;
239 mono_internal_current_mask = entry->mask;
241 g_free (entry);
247 void
248 mono_trace_set_level_string (const char *value)
250 int i = 0;
251 const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
252 const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
253 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
255 if(!value)
256 return;
258 while(valid_vals[i]) {
259 if(!strcmp(valid_vals[i], value)){
260 mono_trace_set_level(valid_ids[i]);
261 return;
263 i++;
266 if(*value)
267 g_print("Unknown trace loglevel: %s\n", value);
270 void
271 mono_trace_set_mask_string (const char *value)
273 int i;
274 const char *tok;
275 guint32 flags = 0;
277 const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "io-layer", "w32handle", "all", NULL};
278 const MonoTraceMask valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
279 MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY,
280 MONO_TRACE_THREADPOOL, MONO_TRACE_IO_THREADPOOL, MONO_TRACE_IO_LAYER,
281 MONO_TRACE_W32HANDLE, MONO_TRACE_ALL };
283 if(!value)
284 return;
286 tok = value;
288 while (*tok) {
289 if (*tok == ',') {
290 tok++;
291 continue;
293 for (i = 0; valid_flags[i]; i++) {
294 size_t len = strlen (valid_flags[i]);
295 if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
296 flags |= valid_masks[i];
297 tok += len;
298 break;
301 if (!valid_flags[i]) {
302 g_print("Unknown trace flag: %s\n", tok);
303 break;
307 mono_trace_set_mask ((MonoTraceMask) flags);
311 * mono_trace_is_traced:
313 * Returns whenever a message with @level and @mask will be printed or not.
315 gboolean
316 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
318 return (level <= mono_internal_current_level && mask & mono_internal_current_mask);
322 * log_level_get_name
323 * @log_level severity level
325 * Convert log level into a string for legacy log handlers
327 static const char *
328 log_level_get_name (GLogLevelFlags log_level)
330 switch (log_level & G_LOG_LEVEL_MASK) {
331 case G_LOG_LEVEL_ERROR: return "error";
332 case G_LOG_LEVEL_CRITICAL: return "critical";
333 case G_LOG_LEVEL_WARNING: return "warning";
334 case G_LOG_LEVEL_MESSAGE: return "message";
335 case G_LOG_LEVEL_INFO: return "info";
336 case G_LOG_LEVEL_DEBUG: return "debug";
337 default: return "unknown";
342 * callback_adapter
344 * @log_domain Message prefix
345 * @log_level Severity
346 * @message Message to be written
347 * @fatal Fatal flag - write then abort
348 * @user_data Argument passed to @callback
350 * This adapts the old callback writer exposed by MonoCallback to the newer method of
351 * logging. We ignore the header request as legacy handlers never had headers.
353 static void
354 callback_adapter (const char *domain, GLogLevelFlags level, mono_bool fatal, const char *message)
356 UserSuppliedLoggerUserData *ll =logCallback.user_data;
358 ll->legacy_callback (domain, log_level_get_name(level), message, fatal, ll->user_data);
361 static void
362 eglib_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
364 UserSuppliedLoggerUserData *ll = logCallback.user_data;
366 ll->legacy_callback (log_domain, log_level_get_name (log_level), message, log_level & G_LOG_LEVEL_ERROR, ll->user_data);
370 * legacy_opener
372 * Dummy routine for older style loggers
374 static void
375 legacy_opener(const char *path, void *user_data)
377 /* nothing to do */
381 * legacy_closer
383 * Cleanup routine for older style loggers
385 static void
386 legacy_closer(void)
388 if (logCallback.user_data != NULL) {
389 g_free (logCallback.user_data); /* This is a UserSuppliedLoggerUserData struct */
390 logCallback.opener = NULL;
391 logCallback.writer = NULL;
392 logCallback.closer = NULL;
393 logCallback.user_data = NULL;
394 logCallback.header = FALSE;
399 * mono_trace_set_log_handler:
401 * @callback The callback that will replace the default logging handler
402 * @user_data Argument passed to @callback
404 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
405 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
406 * execution will not resume after a fatal error.
408 void
409 mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
411 g_assert (callback);
413 if (logCallback.closer != NULL)
414 logCallback.closer();
415 UserSuppliedLoggerUserData *ll = g_malloc (sizeof (UserSuppliedLoggerUserData));
416 ll->legacy_callback = callback;
417 ll->user_data = user_data;
418 logCallback.opener = legacy_opener;
419 logCallback.writer = callback_adapter;
420 logCallback.closer = legacy_closer;
421 logCallback.user_data = ll;
422 logCallback.dest = NULL;
424 g_log_set_default_handler (eglib_log_adapter, user_data);
427 static void
428 structured_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
430 logCallback.writer (log_domain, log_level, logCallback.header, message);
434 * mono_trace_set_log_handler_internal:
436 * @callback The callback that will replace the default logging handler
437 * @user_data Argument passed to @callback
439 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
440 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
441 * execution will not resume after a fatal error.
443 void
444 mono_trace_set_log_handler_internal (MonoLogCallParm *callback, void *user_data)
446 g_assert (callback);
447 if (logCallback.closer != NULL)
448 logCallback.closer();
449 logCallback.opener = callback->opener;
450 logCallback.writer = callback->writer;
451 logCallback.closer = callback->closer;
452 logCallback.header = mono_trace_log_header;
453 logCallback.dest = callback->dest;
454 logCallback.opener (logCallback.dest, user_data);
456 g_log_set_default_handler (structured_log_adapter, user_data);
459 static void
460 print_handler (const char *string)
462 print_callback (string, TRUE);
465 static void
466 printerr_handler (const char *string)
468 printerr_callback (string, FALSE);
472 * mono_trace_set_print_handler:
474 * @callback The callback that will replace the default runtime behavior for stdout output.
476 * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
479 void
480 mono_trace_set_print_handler (MonoPrintCallback callback)
482 g_assert (callback);
483 print_callback = callback;
484 g_set_print_handler (print_handler);
488 * mono_trace_set_printerr_handler:
490 * @callback The callback that will replace the default runtime behavior for stderr output.
492 * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
495 void
496 mono_trace_set_printerr_handler (MonoPrintCallback callback)
498 g_assert (callback);
499 printerr_callback = callback;
500 g_set_printerr_handler (printerr_handler);