6 #include "mono-compiler.h"
7 #include "mono-logger-internals.h"
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 = {
30 MonoLogCallback legacy_callback;
32 } legacyLoggerUserData;
37 * Initializes the mono tracer.
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"));
56 * Releases the mono tracer.
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));
67 g_queue_free (level_stack);
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
82 mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
84 if (level_stack == NULL) {
86 if(level > mono_internal_current_level || !(mask & mono_internal_current_mask))
90 if (logCallback.opener == NULL) {
91 logCallback.opener = mono_log_open_logfile;
92 logCallback.writer = mono_log_write_logfile;
93 logCallback.closer = mono_log_close_logfile;
94 logCallback.opener(NULL, NULL);
96 logCallback.writer(mono_log_domain, level, logCallback.header, format, args);
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
109 mono_trace_set_level (GLogLevelFlags level)
111 if(level_stack == NULL)
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
127 mono_trace_set_mask (MonoTraceMask mask)
129 if(level_stack == NULL)
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,
144 mono_trace_set_logdest_string (const char *dest)
146 MonoLogCallParm logger;
148 if(level_stack == NULL)
151 if ((dest == NULL) || (strcmp("syslog", dest) != 0)) {
152 logger.opener = mono_log_open_logfile;
153 logger.writer = mono_log_write_logfile;
154 logger.closer = mono_log_close_logfile;
155 logger.dest = (char *) dest;
156 mono_trace_set_log_handler_internal(&logger, NULL);
158 logger.opener = mono_log_open_syslog;
159 logger.writer = mono_log_write_syslog;
160 logger.closer = mono_log_close_syslog;
161 logger.dest = (char *) dest;
162 mono_trace_set_log_handler_internal(&logger, NULL);
167 * mono_trace_set_logheader:
169 * @head: Whether we want pid/date/time header on log messages
171 * Sets the current logging header option.
174 mono_trace_set_logheader_string(const char *head)
177 mono_trace_log_header = FALSE;
179 mono_trace_log_header = TRUE;
186 * @level: Verbose level to set
187 * @mask: Mask of visible message types.
189 * Saves the current values of level and mask then calls mono_trace_set
190 * with the specified new values.
193 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
195 if(level_stack == NULL)
196 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
198 MonoLogLevelEntry *entry = (MonoLogLevelEntry *) g_malloc(sizeof(MonoLogLevelEntry));
199 entry->level = mono_internal_current_level;
200 entry->mask = mono_internal_current_mask;
202 g_queue_push_head (level_stack, (gpointer)entry);
204 /* Set the new level and mask
206 mono_internal_current_level = level;
207 mono_internal_current_mask = mask;
214 * Restores level and mask values saved from a previous call to mono_trace_push.
217 mono_trace_pop (void)
219 if(level_stack == NULL)
220 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
222 if(!g_queue_is_empty (level_stack)) {
223 MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
225 /* Restore previous level and mask
227 mono_internal_current_level = entry->level;
228 mono_internal_current_mask = entry->mask;
237 mono_trace_set_level_string (const char *value)
240 const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
241 const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
242 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
247 while(valid_vals[i]) {
248 if(!strcmp(valid_vals[i], value)){
249 mono_trace_set_level(valid_ids[i]);
256 g_print("Unknown trace loglevel: %s\n", value);
260 mono_trace_set_mask_string (const char *value)
266 const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "io-layer", "w32handle", "all", NULL};
267 const MonoTraceMask valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
268 MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY,
269 MONO_TRACE_THREADPOOL, MONO_TRACE_IO_THREADPOOL, MONO_TRACE_IO_LAYER,
270 MONO_TRACE_W32HANDLE, MONO_TRACE_ALL };
282 for (i = 0; valid_flags[i]; i++) {
283 int len = strlen (valid_flags[i]);
284 if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
285 flags |= valid_masks[i];
290 if (!valid_flags[i]) {
291 g_print("Unknown trace flag: %s\n", tok);
296 mono_trace_set_mask ((MonoTraceMask) flags);
300 * mono_trace_is_traced:
302 * Returns whenever a message with @level and @mask will be printed or not.
305 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
307 return (level <= mono_internal_current_level && mask & mono_internal_current_mask);
312 * @log_level severity level
314 * Convert log level into a string for legacy log handlers
317 log_level_get_name (GLogLevelFlags log_level)
319 switch (log_level & G_LOG_LEVEL_MASK) {
320 case G_LOG_LEVEL_ERROR: return "error";
321 case G_LOG_LEVEL_CRITICAL: return "critical";
322 case G_LOG_LEVEL_WARNING: return "warning";
323 case G_LOG_LEVEL_MESSAGE: return "message";
324 case G_LOG_LEVEL_INFO: return "info";
325 case G_LOG_LEVEL_DEBUG: return "debug";
326 default: return "unknown";
333 * @log_domain Message prefix
334 * @log_level Severity
335 * @message Message to be written
336 * @fatal Fatal flag - write then abort
337 * @user_data Argument passed to @callback
339 * This adapts the old callback writer exposed by MonoCallback to the newer method of
340 * logging. We ignore the header request as legacy handlers never had headers.
343 callback_adapter(const char *domain, GLogLevelFlags level, mono_bool fatal, const char *fmt, va_list args)
345 legacyLoggerUserData *ll = (legacyLoggerUserData *) logCallback.user_data;
346 const char *msg = g_strdup_vprintf (fmt, args);
348 ll->legacy_callback (domain, log_level_get_name(level), msg, fatal, ll->user_data);
349 g_free ((void *) msg);
355 * Dummy routine for older style loggers
358 legacy_opener(const char *path, void *user_data)
366 * Cleanup routine for older style loggers
371 if (logCallback.user_data != NULL) {
372 g_free (logCallback.user_data); /* This is a LegacyLoggerUserData struct */
373 logCallback.opener = NULL;
374 logCallback.writer = NULL;
375 logCallback.closer = NULL;
376 logCallback.user_data = NULL;
377 logCallback.header = FALSE;
382 * mono_trace_set_log_handler:
384 * @callback The callback that will replace the default logging handler
385 * @user_data Argument passed to @callback
387 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
388 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
389 * execution will not resume after a fatal error. This is for "old-style" or legacy log handers.
392 mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
395 if (logCallback.closer != NULL)
396 logCallback.closer();
397 legacyLoggerUserData *ll = g_malloc (sizeof (legacyLoggerUserData));
398 ll->legacy_callback = callback;
399 ll->user_data = user_data;
400 logCallback.opener = legacy_opener;
401 logCallback.writer = callback_adapter;
402 logCallback.closer = legacy_closer;
403 logCallback.user_data = ll;
404 logCallback.dest = NULL;
408 * mono_trace_set_log_handler_internal:
410 * @callback The callback that will replace the default logging handler
411 * @user_data Argument passed to @callback
413 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
414 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
415 * execution will not resume after a fatal error.
418 mono_trace_set_log_handler_internal (MonoLogCallParm *callback, void *user_data)
421 if (logCallback.closer != NULL)
422 logCallback.closer();
423 logCallback.opener = callback->opener;
424 logCallback.writer = callback->writer;
425 logCallback.closer = callback->closer;
426 logCallback.header = mono_trace_log_header;
427 logCallback.dest = callback->dest;
428 logCallback.opener(logCallback.dest, user_data);
432 print_handler (const char *string)
434 print_callback (string, TRUE);
438 printerr_handler (const char *string)
440 printerr_callback (string, FALSE);
444 * mono_trace_set_print_handler:
446 * @callback The callback that will replace the default runtime behavior for stdout output.
448 * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
452 mono_trace_set_print_handler (MonoPrintCallback callback)
455 print_callback = callback;
456 g_set_print_handler (print_handler);
460 * mono_trace_set_printerr_handler:
462 * @callback The callback that will replace the default runtime behavior for stderr output.
464 * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
468 mono_trace_set_printerr_handler (MonoPrintCallback callback)
471 printerr_callback = callback;
472 g_set_printerr_handler (printerr_handler);