10 #include "mono-compiler.h"
11 #include "mono-logger-internals.h"
18 GLogLevelFlags mono_internal_current_level = INT_MAX;
19 MonoTraceMask mono_internal_current_mask = MONO_TRACE_ALL;
20 gboolean mono_trace_log_header = FALSE;
22 static GQueue *level_stack = NULL;
23 static const char *mono_log_domain = "Mono";
24 static MonoPrintCallback print_callback, printerr_callback;
26 static MonoLogCallParm logCallback = {
34 MonoLogCallback legacy_callback;
36 } UserSuppliedLoggerUserData;
41 * Initializes the mono tracer.
44 mono_trace_init (void)
46 if(level_stack == NULL) {
47 mono_internal_current_level = G_LOG_LEVEL_ERROR;
48 level_stack = g_queue_new();
50 char *mask = g_getenv ("MONO_LOG_MASK");
51 char *level = g_getenv ("MONO_LOG_LEVEL");
52 char *header = g_getenv ("MONO_LOG_HEADER");
53 char *dest = g_getenv ("MONO_LOG_DEST");
55 mono_trace_set_mask_string(mask);
56 mono_trace_set_level_string(level);
57 mono_trace_set_logheader_string(header);
58 mono_trace_set_logdest_string(dest);
70 * Releases the mono tracer.
73 mono_trace_cleanup (void)
75 if(level_stack != NULL) {
76 while(!g_queue_is_empty (level_stack)) {
77 g_free (g_queue_pop_head (level_stack));
81 g_queue_free (level_stack);
88 * \param level Verbose level of the specified message
89 * \param mask Type of the specified message
90 * Traces a new message, depending on the current logging level
94 mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
97 if (level_stack == NULL) {
99 if(level > mono_internal_current_level || !(mask & mono_internal_current_mask))
103 g_assert (logCallback.opener); // mono_trace_init should have provided us with one!
105 if (g_vasprintf (&log_message, format, args) < 0)
107 logCallback.writer (mono_log_domain, level, logCallback.header, log_message);
108 g_free (log_message);
112 * mono_trace_set_level:
113 * \param level Verbose level to set
114 * Sets the current logging level. Every subsequent call to
115 * \c mono_trace will check the visibility of a message against this
119 mono_trace_set_level (GLogLevelFlags level)
121 if(level_stack == NULL)
124 mono_internal_current_level = level;
128 * mono_trace_set_mask:
129 * \param mask Mask of visible message types.
130 * Sets the current logging level. Every subsequent call to
131 * \c mono_trace will check the visibility of a message against this
135 mono_trace_set_mask (MonoTraceMask mask)
137 if(level_stack == NULL)
140 mono_internal_current_mask = mask;
144 * mono_trace_set_logdest:
145 * \param dest Destination for logging
146 * Sets the current logging destination. This can be a file or, if supported,
150 mono_trace_set_logdest_string (const char *dest)
152 MonoLogCallParm logger;
154 if(level_stack == NULL)
158 logger.opener = mono_log_open_logcat;
159 logger.writer = mono_log_write_logcat;
160 logger.closer = mono_log_close_logcat;
161 logger.dest = (char*) dest;
162 #elif defined (HOST_IOS)
163 logger.opener = mono_log_open_asl;
164 logger.writer = mono_log_write_asl;
165 logger.closer = mono_log_close_asl;
166 logger.dest = (char*) dest;
168 if ((dest == NULL) || (strcmp("syslog", dest) != 0)) {
169 logger.opener = mono_log_open_logfile;
170 logger.writer = mono_log_write_logfile;
171 logger.closer = mono_log_close_logfile;
172 logger.dest = (char *) dest;
174 logger.opener = mono_log_open_syslog;
175 logger.writer = mono_log_write_syslog;
176 logger.closer = mono_log_close_syslog;
177 logger.dest = (char *) dest;
180 mono_trace_set_log_handler_internal(&logger, NULL);
184 * mono_trace_set_logheader:
185 * \param head Whether we want pid/date/time header on log messages
186 * Sets the current logging header option.
189 mono_trace_set_logheader_string(const char *head)
192 mono_trace_log_header = FALSE;
194 mono_trace_log_header = TRUE;
200 * \param level Verbose level to set
201 * \param mask Mask of visible message types.
202 * Saves the current values of level and mask then calls \c mono_trace_set
203 * with the specified new values.
206 mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
208 if(level_stack == NULL)
209 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
211 MonoLogLevelEntry *entry = (MonoLogLevelEntry *) g_malloc(sizeof(MonoLogLevelEntry));
212 entry->level = mono_internal_current_level;
213 entry->mask = mono_internal_current_mask;
215 g_queue_push_head (level_stack, (gpointer)entry);
217 /* Set the new level and mask
219 mono_internal_current_level = level;
220 mono_internal_current_mask = mask;
227 * Restores level and mask values saved from a previous call to mono_trace_push.
230 mono_trace_pop (void)
232 if(level_stack == NULL)
233 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
235 if(!g_queue_is_empty (level_stack)) {
236 MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
238 /* Restore previous level and mask
240 mono_internal_current_level = entry->level;
241 mono_internal_current_mask = entry->mask;
250 mono_trace_set_level_string (const char *value)
253 const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
254 const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
255 G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
260 while(valid_vals[i]) {
261 if(!strcmp(valid_vals[i], value)){
262 mono_trace_set_level(valid_ids[i]);
269 g_print("Unknown trace loglevel: %s\n", value);
273 mono_trace_set_mask_string (const char *value)
279 const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "io-layer", "w32handle", "all", NULL};
280 const MonoTraceMask valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT,
281 MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY,
282 MONO_TRACE_THREADPOOL, MONO_TRACE_IO_THREADPOOL, MONO_TRACE_IO_LAYER,
283 MONO_TRACE_W32HANDLE, MONO_TRACE_ALL };
295 for (i = 0; valid_flags[i]; i++) {
296 size_t len = strlen (valid_flags[i]);
297 if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
298 flags |= valid_masks[i];
303 if (!valid_flags[i]) {
304 g_print("Unknown trace flag: %s\n", tok);
309 mono_trace_set_mask ((MonoTraceMask) flags);
313 * mono_trace_is_traced:
315 * Returns whenever a message with @level and @mask will be printed or not.
318 mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
320 return (level <= mono_internal_current_level && mask & mono_internal_current_mask);
325 * @log_level severity level
327 * Convert log level into a string for legacy log handlers
330 log_level_get_name (GLogLevelFlags log_level)
332 switch (log_level & G_LOG_LEVEL_MASK) {
333 case G_LOG_LEVEL_ERROR: return "error";
334 case G_LOG_LEVEL_CRITICAL: return "critical";
335 case G_LOG_LEVEL_WARNING: return "warning";
336 case G_LOG_LEVEL_MESSAGE: return "message";
337 case G_LOG_LEVEL_INFO: return "info";
338 case G_LOG_LEVEL_DEBUG: return "debug";
339 default: return "unknown";
346 * @log_domain Message prefix
347 * @log_level Severity
348 * @message Message to be written
349 * @fatal Fatal flag - write then abort
350 * @user_data Argument passed to @callback
352 * This adapts the old callback writer exposed by MonoCallback to the newer method of
353 * logging. We ignore the header request as legacy handlers never had headers.
356 callback_adapter (const char *domain, GLogLevelFlags level, mono_bool fatal, const char *message)
358 UserSuppliedLoggerUserData *ll =logCallback.user_data;
360 ll->legacy_callback (domain, log_level_get_name(level), message, fatal, ll->user_data);
364 eglib_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
366 UserSuppliedLoggerUserData *ll = logCallback.user_data;
368 ll->legacy_callback (log_domain, log_level_get_name (log_level), message, log_level & G_LOG_LEVEL_ERROR, ll->user_data);
374 * Dummy routine for older style loggers
377 legacy_opener(const char *path, void *user_data)
385 * Cleanup routine for older style loggers
390 if (logCallback.user_data != NULL) {
391 g_free (logCallback.user_data); /* This is a UserSuppliedLoggerUserData struct */
392 logCallback.opener = NULL;
393 logCallback.writer = NULL;
394 logCallback.closer = NULL;
395 logCallback.user_data = NULL;
396 logCallback.header = FALSE;
401 * mono_trace_set_log_handler:
403 * @callback The callback that will replace the default logging handler
404 * @user_data Argument passed to @callback
406 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
407 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
408 * execution will not resume after a fatal error.
411 mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
415 if (logCallback.closer != NULL)
416 logCallback.closer();
417 UserSuppliedLoggerUserData *ll = g_malloc (sizeof (UserSuppliedLoggerUserData));
418 ll->legacy_callback = callback;
419 ll->user_data = user_data;
420 logCallback.opener = legacy_opener;
421 logCallback.writer = callback_adapter;
422 logCallback.closer = legacy_closer;
423 logCallback.user_data = ll;
424 logCallback.dest = NULL;
426 g_log_set_default_handler (eglib_log_adapter, user_data);
430 structured_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
432 logCallback.writer (log_domain, log_level, logCallback.header, message);
436 * mono_trace_set_log_handler_internal:
437 * \param callback The callback that will replace the default logging handler
438 * \param user_data Argument passed to \p 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.
444 mono_trace_set_log_handler_internal (MonoLogCallParm *callback, void *user_data)
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);
460 print_handler (const char *string)
462 print_callback (string, TRUE);
466 printerr_handler (const char *string)
468 printerr_callback (string, FALSE);
472 * mono_trace_set_print_handler:
473 * \param callback The callback that will replace the default runtime behavior for stdout output.
474 * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
477 mono_trace_set_print_handler (MonoPrintCallback callback)
480 print_callback = callback;
481 g_set_print_handler (print_handler);
485 * mono_trace_set_printerr_handler:
486 * \param callback The callback that will replace the default runtime behavior for stderr output.
487 * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
490 mono_trace_set_printerr_handler (MonoPrintCallback callback)
493 printerr_callback = callback;
494 g_set_printerr_handler (printerr_handler);