PageRenderTime 100ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/mono/utils/mono-logger.c

https://github.com/kumpera/mono
C | 521 lines | 339 code | 59 blank | 123 comment | 53 complexity | 43683faec1314878df3927df31b73f9d MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, Unlicense
  1. /**
  2. * \file
  3. */
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <glib.h>
  8. #include "mono-compiler.h"
  9. #include "mono-logger-internals.h"
  10. typedef struct {
  11. GLogLevelFlags level;
  12. MonoTraceMask mask;
  13. } MonoLogLevelEntry;
  14. GLogLevelFlags mono_internal_current_level = INT_MAX;
  15. MonoTraceMask mono_internal_current_mask = ~((MonoTraceMask)0);
  16. gboolean mono_trace_log_header = FALSE;
  17. static GQueue *level_stack = NULL;
  18. static const char *mono_log_domain = "Mono";
  19. static MonoPrintCallback print_callback, printerr_callback;
  20. static MonoLogCallParm logCallback = {
  21. .opener = NULL,
  22. .writer = NULL,
  23. .closer = NULL,
  24. .header = FALSE
  25. };
  26. typedef struct {
  27. MonoLogCallback legacy_callback;
  28. gpointer user_data;
  29. } UserSuppliedLoggerUserData;
  30. /**
  31. * mono_trace_init:
  32. *
  33. * Initializes the mono tracer.
  34. */
  35. void
  36. mono_trace_init (void)
  37. {
  38. if(level_stack == NULL) {
  39. mono_internal_current_level = G_LOG_LEVEL_ERROR;
  40. level_stack = g_queue_new();
  41. char *mask = g_getenv ("MONO_LOG_MASK");
  42. char *level = g_getenv ("MONO_LOG_LEVEL");
  43. char *header = g_getenv ("MONO_LOG_HEADER");
  44. char *dest = g_getenv ("MONO_LOG_DEST");
  45. mono_trace_set_mask_string(mask);
  46. mono_trace_set_level_string(level);
  47. mono_trace_set_logheader_string(header);
  48. mono_trace_set_logdest_string(dest);
  49. g_free (mask);
  50. g_free (level);
  51. g_free (header);
  52. g_free (dest);
  53. }
  54. }
  55. /**
  56. * mono_trace_cleanup:
  57. *
  58. * Releases the mono tracer.
  59. */
  60. void
  61. mono_trace_cleanup (void)
  62. {
  63. if(level_stack != NULL) {
  64. while(!g_queue_is_empty (level_stack)) {
  65. g_free (g_queue_pop_head (level_stack));
  66. }
  67. logCallback.closer();
  68. g_queue_free (level_stack);
  69. level_stack = NULL;
  70. }
  71. }
  72. /**
  73. * mono_tracev_inner:
  74. * \param level Verbose level of the specified message
  75. * \param mask Type of the specified message
  76. * Traces a new message, depending on the current logging level
  77. * and trace mask.
  78. */
  79. void
  80. mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args)
  81. {
  82. char *log_message;
  83. if (level_stack == NULL) {
  84. mono_trace_init ();
  85. if(level > mono_internal_current_level || !(mask & mono_internal_current_mask))
  86. return;
  87. }
  88. g_assert (logCallback.opener); // mono_trace_init should have provided us with one!
  89. if (g_vasprintf (&log_message, format, args) < 0)
  90. return;
  91. logCallback.writer (mono_log_domain, level, logCallback.header, log_message);
  92. g_free (log_message);
  93. }
  94. /**
  95. * mono_trace_set_level:
  96. * \param level Verbose level to set
  97. * Sets the current logging level. Every subsequent call to
  98. * \c mono_trace will check the visibility of a message against this
  99. * value.
  100. */
  101. void
  102. mono_trace_set_level (GLogLevelFlags level)
  103. {
  104. if(level_stack == NULL)
  105. mono_trace_init();
  106. mono_internal_current_level = level;
  107. }
  108. /**
  109. * mono_trace_set_mask:
  110. * \param mask Mask of visible message types.
  111. * Sets the current logging level. Every subsequent call to
  112. * \c mono_trace will check the visibility of a message against this
  113. * value.
  114. */
  115. void
  116. mono_trace_set_mask (MonoTraceMask mask)
  117. {
  118. if(level_stack == NULL)
  119. mono_trace_init();
  120. mono_internal_current_mask = mask;
  121. }
  122. /**
  123. * mono_trace_set_logdest:
  124. * \param dest Destination for logging
  125. * Sets the current logging destination. This can be a file or, if supported,
  126. * syslog.
  127. */
  128. void
  129. mono_trace_set_logdest_string (const char *dest)
  130. {
  131. MonoLogCallParm logger;
  132. if(level_stack == NULL)
  133. mono_trace_init();
  134. #if HOST_ANDROID
  135. logger.opener = mono_log_open_logcat;
  136. logger.writer = mono_log_write_logcat;
  137. logger.closer = mono_log_close_logcat;
  138. logger.dest = (char*) dest;
  139. #elif defined (HOST_IOS)
  140. logger.opener = mono_log_open_asl;
  141. logger.writer = mono_log_write_asl;
  142. logger.closer = mono_log_close_asl;
  143. logger.dest = (char*) dest;
  144. #else
  145. if ((dest == NULL) || (strcmp("syslog", dest) != 0)) {
  146. logger.opener = mono_log_open_logfile;
  147. logger.writer = mono_log_write_logfile;
  148. logger.closer = mono_log_close_logfile;
  149. logger.dest = (char *) dest;
  150. } else {
  151. logger.opener = mono_log_open_syslog;
  152. logger.writer = mono_log_write_syslog;
  153. logger.closer = mono_log_close_syslog;
  154. logger.dest = (char *) dest;
  155. }
  156. #endif
  157. mono_trace_set_log_handler_internal(&logger, NULL);
  158. }
  159. /**
  160. * mono_trace_set_logheader:
  161. * \param head Whether we want pid/date/time header on log messages
  162. * Sets the current logging header option.
  163. */
  164. void
  165. mono_trace_set_logheader_string(const char *head)
  166. {
  167. if (head == NULL) {
  168. mono_trace_log_header = FALSE;
  169. } else {
  170. mono_trace_log_header = TRUE;
  171. }
  172. }
  173. /**
  174. * mono_trace_push:
  175. * \param level Verbose level to set
  176. * \param mask Mask of visible message types.
  177. * Saves the current values of level and mask then calls \c mono_trace_set
  178. * with the specified new values.
  179. */
  180. void
  181. mono_trace_push (GLogLevelFlags level, MonoTraceMask mask)
  182. {
  183. if(level_stack == NULL)
  184. g_error("%s: cannot use mono_trace_push without calling mono_trace_init first.", __func__);
  185. else {
  186. MonoLogLevelEntry *entry = (MonoLogLevelEntry *) g_malloc(sizeof(MonoLogLevelEntry));
  187. entry->level = mono_internal_current_level;
  188. entry->mask = mono_internal_current_mask;
  189. g_queue_push_head (level_stack, (gpointer)entry);
  190. /* Set the new level and mask
  191. */
  192. mono_internal_current_level = level;
  193. mono_internal_current_mask = mask;
  194. }
  195. }
  196. /**
  197. * mono_trace_pop:
  198. *
  199. * Restores level and mask values saved from a previous call to mono_trace_push.
  200. */
  201. void
  202. mono_trace_pop (void)
  203. {
  204. if(level_stack == NULL)
  205. g_error("%s: cannot use mono_trace_pop without calling mono_trace_init first.", __func__);
  206. else {
  207. if(!g_queue_is_empty (level_stack)) {
  208. MonoLogLevelEntry *entry = (MonoLogLevelEntry*)g_queue_pop_head (level_stack);
  209. /* Restore previous level and mask
  210. */
  211. mono_internal_current_level = entry->level;
  212. mono_internal_current_mask = entry->mask;
  213. g_free (entry);
  214. }
  215. }
  216. }
  217. void
  218. mono_trace_set_level_string (const char *value)
  219. {
  220. int i = 0;
  221. const char *valid_vals[] = {"error", "critical", "warning", "message", "info", "debug", NULL};
  222. const GLogLevelFlags valid_ids[] = {G_LOG_LEVEL_ERROR, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING,
  223. G_LOG_LEVEL_MESSAGE, G_LOG_LEVEL_INFO, G_LOG_LEVEL_DEBUG };
  224. if(!value)
  225. return;
  226. while(valid_vals[i]) {
  227. if(!strcmp(valid_vals[i], value)){
  228. mono_trace_set_level(valid_ids[i]);
  229. return;
  230. }
  231. i++;
  232. }
  233. if(*value)
  234. g_print("Unknown trace loglevel: %s\n", value);
  235. }
  236. void
  237. mono_trace_set_mask_string (const char *value)
  238. {
  239. int i;
  240. const char *tok;
  241. guint32 flags = 0;
  242. static const struct { const char * const flag; const MonoTraceMask mask; } flag_mask_map[] = {
  243. { "asm", MONO_TRACE_ASSEMBLY },
  244. { "type", MONO_TRACE_TYPE },
  245. { "dll", MONO_TRACE_DLLIMPORT },
  246. { "gc", MONO_TRACE_GC },
  247. { "cfg", MONO_TRACE_CONFIG },
  248. { "aot", MONO_TRACE_AOT },
  249. { "security", MONO_TRACE_SECURITY },
  250. { "threadpool", MONO_TRACE_THREADPOOL },
  251. { "io-threadpool", MONO_TRACE_IO_SELECTOR },
  252. { "io-selector", MONO_TRACE_IO_SELECTOR },
  253. { "io-layer-process", MONO_TRACE_IO_LAYER_PROCESS },
  254. { "io-layer-socket", MONO_TRACE_IO_LAYER_SOCKET },
  255. { "io-layer-file", MONO_TRACE_IO_LAYER_FILE },
  256. { "io-layer-console", MONO_TRACE_IO_LAYER_FILE },
  257. { "io-layer-pipe", MONO_TRACE_IO_LAYER_FILE },
  258. { "io-layer-event", MONO_TRACE_IO_LAYER_EVENT },
  259. { "io-layer-semaphore", MONO_TRACE_IO_LAYER_SEMAPHORE },
  260. { "io-layer-mutex", MONO_TRACE_IO_LAYER_MUTEX },
  261. { "io-layer-handle", MONO_TRACE_IO_LAYER_HANDLE },
  262. { "io-layer", MONO_TRACE_IO_LAYER_PROCESS
  263. | MONO_TRACE_IO_LAYER_SOCKET
  264. | MONO_TRACE_IO_LAYER_FILE
  265. | MONO_TRACE_IO_LAYER_EVENT
  266. | MONO_TRACE_IO_LAYER_SEMAPHORE
  267. | MONO_TRACE_IO_LAYER_MUTEX
  268. | MONO_TRACE_IO_LAYER_HANDLE },
  269. { "w32handle", MONO_TRACE_IO_LAYER_HANDLE },
  270. { "all", ~((MonoTraceMask)0) },
  271. { NULL, 0 },
  272. };
  273. if(!value)
  274. return;
  275. tok = value;
  276. while (*tok) {
  277. if (*tok == ',') {
  278. tok++;
  279. continue;
  280. }
  281. for (i = 0; flag_mask_map[i].flag; i++) {
  282. size_t len = strlen (flag_mask_map[i].flag);
  283. if (strncmp (tok, flag_mask_map[i].flag, len) == 0 && (tok[len] == 0 || tok[len] == ',')) {
  284. flags |= flag_mask_map[i].mask;
  285. tok += len;
  286. break;
  287. }
  288. }
  289. if (!flag_mask_map[i].flag) {
  290. g_print("Unknown trace flag: %s\n", tok);
  291. break;
  292. }
  293. }
  294. mono_trace_set_mask ((MonoTraceMask) flags);
  295. }
  296. /*
  297. * mono_trace_is_traced:
  298. *
  299. * Returns whenever a message with @level and @mask will be printed or not.
  300. */
  301. gboolean
  302. mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
  303. {
  304. return (level <= mono_internal_current_level && (mask & mono_internal_current_mask));
  305. }
  306. /**
  307. * log_level_get_name
  308. * @log_level severity level
  309. *
  310. * Convert log level into a string for legacy log handlers
  311. */
  312. static const char *
  313. log_level_get_name (GLogLevelFlags log_level)
  314. {
  315. switch (log_level & G_LOG_LEVEL_MASK) {
  316. case G_LOG_LEVEL_ERROR: return "error";
  317. case G_LOG_LEVEL_CRITICAL: return "critical";
  318. case G_LOG_LEVEL_WARNING: return "warning";
  319. case G_LOG_LEVEL_MESSAGE: return "message";
  320. case G_LOG_LEVEL_INFO: return "info";
  321. case G_LOG_LEVEL_DEBUG: return "debug";
  322. default: return "unknown";
  323. }
  324. }
  325. /**
  326. * callback_adapter
  327. *
  328. * @log_domain Message prefix
  329. * @log_level Severity
  330. * @message Message to be written
  331. * @fatal Fatal flag - write then abort
  332. * @user_data Argument passed to @callback
  333. *
  334. * This adapts the old callback writer exposed by MonoCallback to the newer method of
  335. * logging. We ignore the header request as legacy handlers never had headers.
  336. */
  337. static void
  338. callback_adapter (const char *domain, GLogLevelFlags level, mono_bool fatal, const char *message)
  339. {
  340. UserSuppliedLoggerUserData *ll =logCallback.user_data;
  341. ll->legacy_callback (domain, log_level_get_name(level), message, fatal, ll->user_data);
  342. }
  343. static void
  344. eglib_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
  345. {
  346. UserSuppliedLoggerUserData *ll = logCallback.user_data;
  347. ll->legacy_callback (log_domain, log_level_get_name (log_level), message, log_level & G_LOG_LEVEL_ERROR, ll->user_data);
  348. }
  349. /**
  350. * legacy_opener
  351. *
  352. * Dummy routine for older style loggers
  353. */
  354. static void
  355. legacy_opener(const char *path, void *user_data)
  356. {
  357. /* nothing to do */
  358. }
  359. /**
  360. * legacy_closer
  361. *
  362. * Cleanup routine for older style loggers
  363. */
  364. static void
  365. legacy_closer(void)
  366. {
  367. if (logCallback.user_data != NULL) {
  368. g_free (logCallback.user_data); /* This is a UserSuppliedLoggerUserData struct */
  369. logCallback.opener = NULL;
  370. logCallback.writer = NULL;
  371. logCallback.closer = NULL;
  372. logCallback.user_data = NULL;
  373. logCallback.header = FALSE;
  374. }
  375. }
  376. /**
  377. * mono_trace_set_log_handler:
  378. *
  379. * @callback The callback that will replace the default logging handler
  380. * @user_data Argument passed to @callback
  381. *
  382. * The log handler replaces the default runtime logger. All logging requests with be routed to it.
  383. * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
  384. * execution will not resume after a fatal error.
  385. */
  386. void
  387. mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
  388. {
  389. g_assert (callback);
  390. if (logCallback.closer != NULL)
  391. logCallback.closer();
  392. UserSuppliedLoggerUserData *ll = g_malloc (sizeof (UserSuppliedLoggerUserData));
  393. ll->legacy_callback = callback;
  394. ll->user_data = user_data;
  395. logCallback.opener = legacy_opener;
  396. logCallback.writer = callback_adapter;
  397. logCallback.closer = legacy_closer;
  398. logCallback.user_data = ll;
  399. logCallback.dest = NULL;
  400. g_log_set_default_handler (eglib_log_adapter, user_data);
  401. }
  402. static void
  403. structured_log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
  404. {
  405. logCallback.writer (log_domain, log_level, logCallback.header, message);
  406. }
  407. /**
  408. * mono_trace_set_log_handler_internal:
  409. * \param callback The callback that will replace the default logging handler
  410. * \param user_data Argument passed to \p callback
  411. * The log handler replaces the default runtime logger. All logging requests with be routed to it.
  412. * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that
  413. * execution will not resume after a fatal error.
  414. */
  415. void
  416. mono_trace_set_log_handler_internal (MonoLogCallParm *callback, void *user_data)
  417. {
  418. g_assert (callback);
  419. if (logCallback.closer != NULL)
  420. logCallback.closer();
  421. logCallback.opener = callback->opener;
  422. logCallback.writer = callback->writer;
  423. logCallback.closer = callback->closer;
  424. logCallback.header = mono_trace_log_header;
  425. logCallback.dest = callback->dest;
  426. logCallback.opener (logCallback.dest, user_data);
  427. g_log_set_default_handler (structured_log_adapter, user_data);
  428. }
  429. static void
  430. print_handler (const char *string)
  431. {
  432. print_callback (string, TRUE);
  433. }
  434. static void
  435. printerr_handler (const char *string)
  436. {
  437. printerr_callback (string, FALSE);
  438. }
  439. /**
  440. * mono_trace_set_print_handler:
  441. * \param callback The callback that will replace the default runtime behavior for stdout output.
  442. * The print handler replaces the default runtime stdout output handler. This is used by free form output done by the runtime.
  443. */
  444. void
  445. mono_trace_set_print_handler (MonoPrintCallback callback)
  446. {
  447. g_assert (callback);
  448. print_callback = callback;
  449. g_set_print_handler (print_handler);
  450. }
  451. /**
  452. * mono_trace_set_printerr_handler:
  453. * \param callback The callback that will replace the default runtime behavior for stderr output.
  454. * The print handler replaces the default runtime stderr output handler. This is used by free form output done by the runtime.
  455. */
  456. void
  457. mono_trace_set_printerr_handler (MonoPrintCallback callback)
  458. {
  459. g_assert (callback);
  460. printerr_callback = callback;
  461. g_set_printerr_handler (printerr_handler);
  462. }