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 mono_trace_set_mask_string(g_getenv("MONO_LOG_MASK"));
51 mono_trace_set_level_string(g_getenv("MONO_LOG_LEVEL"));
52 mono_trace_set_logheader_string(g_getenv("MONO_LOG_HEADER"));
53 mono_trace_set_logdest_string(g_getenv("MONO_LOG_DEST"));
60 * Releases the mono tracer.
63 mono_trace_cleanup (void)
65 if(level_stack
!= NULL
) {
66 while(!g_queue_is_empty (level_stack
)) {
67 g_free (g_queue_pop_head (level_stack
));
71 g_queue_free (level_stack
);
78 * \param level Verbose level of the specified message
79 * \param mask Type of the specified message
80 * Traces a new message, depending on the current logging level
84 mono_tracev_inner (GLogLevelFlags level
, MonoTraceMask mask
, const char *format
, va_list args
)
87 if (level_stack
== NULL
) {
89 if(level
> mono_internal_current_level
|| !(mask
& mono_internal_current_mask
))
93 g_assert (logCallback
.opener
); // mono_trace_init should have provided us with one!
95 if (g_vasprintf (&log_message
, format
, args
) < 0)
97 logCallback
.writer (mono_log_domain
, level
, logCallback
.header
, log_message
);
102 * mono_trace_set_level:
103 * \param level Verbose level to set
104 * Sets the current logging level. Every subsequent call to
105 * \c 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:
119 * \param mask Mask of visible message types.
120 * Sets the current logging level. Every subsequent call to
121 * \c mono_trace will check the visibility of a message against this
125 mono_trace_set_mask (MonoTraceMask mask
)
127 if(level_stack
== NULL
)
130 mono_internal_current_mask
= mask
;
134 * mono_trace_set_logdest:
135 * \param dest Destination for logging
136 * Sets the current logging destination. This can be a file or, if supported,
140 mono_trace_set_logdest_string (const char *dest
)
142 MonoLogCallParm logger
;
144 if(level_stack
== NULL
)
148 logger
.opener
= mono_log_open_logcat
;
149 logger
.writer
= mono_log_write_logcat
;
150 logger
.closer
= mono_log_close_logcat
;
151 logger
.dest
= (char*) dest
;
152 #elif defined (HOST_IOS)
153 logger
.opener
= mono_log_open_asl
;
154 logger
.writer
= mono_log_write_asl
;
155 logger
.closer
= mono_log_close_asl
;
156 logger
.dest
= (char*) dest
;
158 if ((dest
== NULL
) || (strcmp("syslog", dest
) != 0)) {
159 logger
.opener
= mono_log_open_logfile
;
160 logger
.writer
= mono_log_write_logfile
;
161 logger
.closer
= mono_log_close_logfile
;
162 logger
.dest
= (char *) dest
;
164 logger
.opener
= mono_log_open_syslog
;
165 logger
.writer
= mono_log_write_syslog
;
166 logger
.closer
= mono_log_close_syslog
;
167 logger
.dest
= (char *) dest
;
170 mono_trace_set_log_handler_internal(&logger
, NULL
);
174 * mono_trace_set_logheader:
175 * \param head Whether we want pid/date/time header on log messages
176 * Sets the current logging header option.
179 mono_trace_set_logheader_string(const char *head
)
182 mono_trace_log_header
= FALSE
;
184 mono_trace_log_header
= TRUE
;
190 * \param level Verbose level to set
191 * \param mask Mask of visible message types.
192 * Saves the current values of level and mask then calls \c mono_trace_set
193 * with the specified new values.
196 mono_trace_push (GLogLevelFlags level
, MonoTraceMask mask
)
198 if(level_stack
== NULL
)
199 g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__
);
201 MonoLogLevelEntry
*entry
= (MonoLogLevelEntry
*) g_malloc(sizeof(MonoLogLevelEntry
));
202 entry
->level
= mono_internal_current_level
;
203 entry
->mask
= mono_internal_current_mask
;
205 g_queue_push_head (level_stack
, (gpointer
)entry
);
207 /* Set the new level and mask
209 mono_internal_current_level
= level
;
210 mono_internal_current_mask
= mask
;
217 * Restores level and mask values saved from a previous call to mono_trace_push.
220 mono_trace_pop (void)
222 if(level_stack
== NULL
)
223 g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__
);
225 if(!g_queue_is_empty (level_stack
)) {
226 MonoLogLevelEntry
*entry
= (MonoLogLevelEntry
*)g_queue_pop_head (level_stack
);
228 /* Restore previous level and mask
230 mono_internal_current_level
= entry
->level
;
231 mono_internal_current_mask
= entry
->mask
;
240 mono_trace_set_level_string (const char *value
)
243 const char *valid_vals
[] = {"error", "critical", "warning", "message", "info", "debug", NULL
};
244 const GLogLevelFlags valid_ids
[] = {G_LOG_LEVEL_ERROR
, G_LOG_LEVEL_CRITICAL
, G_LOG_LEVEL_WARNING
,
245 G_LOG_LEVEL_MESSAGE
, G_LOG_LEVEL_INFO
, G_LOG_LEVEL_DEBUG
};
250 while(valid_vals
[i
]) {
251 if(!strcmp(valid_vals
[i
], value
)){
252 mono_trace_set_level(valid_ids
[i
]);
259 g_print("Unknown trace loglevel: %s\n", value
);
263 mono_trace_set_mask_string (const char *value
)
269 const char *valid_flags
[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "io-layer", "w32handle", "all", NULL
};
270 const MonoTraceMask valid_masks
[] = {MONO_TRACE_ASSEMBLY
, MONO_TRACE_TYPE
, MONO_TRACE_DLLIMPORT
,
271 MONO_TRACE_GC
, MONO_TRACE_CONFIG
, MONO_TRACE_AOT
, MONO_TRACE_SECURITY
,
272 MONO_TRACE_THREADPOOL
, MONO_TRACE_IO_THREADPOOL
, MONO_TRACE_IO_LAYER
,
273 MONO_TRACE_W32HANDLE
, MONO_TRACE_ALL
};
285 for (i
= 0; valid_flags
[i
]; i
++) {
286 size_t len
= strlen (valid_flags
[i
]);
287 if (strncmp (tok
, valid_flags
[i
], len
) == 0 && (tok
[len
] == 0 || tok
[len
] == ',')) {
288 flags
|= valid_masks
[i
];
293 if (!valid_flags
[i
]) {
294 g_print("Unknown trace flag: %s\n", tok
);
299 mono_trace_set_mask ((MonoTraceMask
) flags
);
303 * mono_trace_is_traced:
305 * Returns whenever a message with @level and @mask will be printed or not.
308 mono_trace_is_traced (GLogLevelFlags level
, MonoTraceMask mask
)
310 return (level
<= mono_internal_current_level
&& mask
& mono_internal_current_mask
);
315 * @log_level severity level
317 * Convert log level into a string for legacy log handlers
320 log_level_get_name (GLogLevelFlags log_level
)
322 switch (log_level
& G_LOG_LEVEL_MASK
) {
323 case G_LOG_LEVEL_ERROR
: return "error";
324 case G_LOG_LEVEL_CRITICAL
: return "critical";
325 case G_LOG_LEVEL_WARNING
: return "warning";
326 case G_LOG_LEVEL_MESSAGE
: return "message";
327 case G_LOG_LEVEL_INFO
: return "info";
328 case G_LOG_LEVEL_DEBUG
: return "debug";
329 default: return "unknown";
336 * @log_domain Message prefix
337 * @log_level Severity
338 * @message Message to be written
339 * @fatal Fatal flag - write then abort
340 * @user_data Argument passed to @callback
342 * This adapts the old callback writer exposed by MonoCallback to the newer method of
343 * logging. We ignore the header request as legacy handlers never had headers.
346 callback_adapter (const char *domain
, GLogLevelFlags level
, mono_bool fatal
, const char *message
)
348 UserSuppliedLoggerUserData
*ll
=logCallback
.user_data
;
350 ll
->legacy_callback (domain
, log_level_get_name(level
), message
, fatal
, ll
->user_data
);
354 eglib_log_adapter (const gchar
*log_domain
, GLogLevelFlags log_level
, const gchar
*message
, gpointer user_data
)
356 UserSuppliedLoggerUserData
*ll
= logCallback
.user_data
;
358 ll
->legacy_callback (log_domain
, log_level_get_name (log_level
), message
, log_level
& G_LOG_LEVEL_ERROR
, ll
->user_data
);
364 * Dummy routine for older style loggers
367 legacy_opener(const char *path
, void *user_data
)
375 * Cleanup routine for older style loggers
380 if (logCallback
.user_data
!= NULL
) {
381 g_free (logCallback
.user_data
); /* This is a UserSuppliedLoggerUserData struct */
382 logCallback
.opener
= NULL
;
383 logCallback
.writer
= NULL
;
384 logCallback
.closer
= NULL
;
385 logCallback
.user_data
= NULL
;
386 logCallback
.header
= FALSE
;
391 * mono_trace_set_log_handler:
393 * @callback The callback that will replace the default logging handler
394 * @user_data Argument passed to @callback
396 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
397 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
398 * execution will not resume after a fatal error.
401 mono_trace_set_log_handler (MonoLogCallback callback
, void *user_data
)
405 if (logCallback
.closer
!= NULL
)
406 logCallback
.closer();
407 UserSuppliedLoggerUserData
*ll
= g_malloc (sizeof (UserSuppliedLoggerUserData
));
408 ll
->legacy_callback
= callback
;
409 ll
->user_data
= user_data
;
410 logCallback
.opener
= legacy_opener
;
411 logCallback
.writer
= callback_adapter
;
412 logCallback
.closer
= legacy_closer
;
413 logCallback
.user_data
= ll
;
414 logCallback
.dest
= NULL
;
416 g_log_set_default_handler (eglib_log_adapter
, user_data
);
420 structured_log_adapter (const gchar
*log_domain
, GLogLevelFlags log_level
, const gchar
*message
, gpointer user_data
)
422 logCallback
.writer (log_domain
, log_level
, logCallback
.header
, message
);
426 * mono_trace_set_log_handler_internal:
427 * \param callback The callback that will replace the default logging handler
428 * \param user_data Argument passed to \p callback
429 * The log handler replaces the default runtime logger. All logging requests with be routed to it.
430 * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
431 * execution will not resume after a fatal error.
434 mono_trace_set_log_handler_internal (MonoLogCallParm
*callback
, void *user_data
)
437 if (logCallback
.closer
!= NULL
)
438 logCallback
.closer();
439 logCallback
.opener
= callback
->opener
;
440 logCallback
.writer
= callback
->writer
;
441 logCallback
.closer
= callback
->closer
;
442 logCallback
.header
= mono_trace_log_header
;
443 logCallback
.dest
= callback
->dest
;
444 logCallback
.opener (logCallback
.dest
, user_data
);
446 g_log_set_default_handler (structured_log_adapter
, user_data
);
450 print_handler (const char *string
)
452 print_callback (string
, TRUE
);
456 printerr_handler (const char *string
)
458 printerr_callback (string
, FALSE
);
462 * mono_trace_set_print_handler:
463 * \param callback The callback that will replace the default runtime behavior for stdout output.
464 * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
467 mono_trace_set_print_handler (MonoPrintCallback callback
)
470 print_callback
= callback
;
471 g_set_print_handler (print_handler
);
475 * mono_trace_set_printerr_handler:
476 * \param callback The callback that will replace the default runtime behavior for stderr output.
477 * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
480 mono_trace_set_printerr_handler (MonoPrintCallback callback
)
483 printerr_callback
= callback
;
484 g_set_printerr_handler (printerr_handler
);