You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logger.c 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "logger.h"
  18. #include "rspamd.h"
  19. #include "libserver/maps/map.h"
  20. #include "libserver/maps/map_helpers.h"
  21. #include "ottery.h"
  22. #include "unix-std.h"
  23. #include "logger_private.h"
  24. static rspamd_logger_t *default_logger = NULL;
  25. static rspamd_logger_t *emergency_logger = NULL;
  26. static struct rspamd_log_modules *log_modules = NULL;
  27. guint rspamd_task_log_id = (guint)-1;
  28. RSPAMD_CONSTRUCTOR(rspamd_task_log_init)
  29. {
  30. rspamd_task_log_id = rspamd_logger_add_debug_module("task");
  31. }
  32. rspamd_logger_t *
  33. rspamd_log_default_logger (void)
  34. {
  35. return default_logger;
  36. }
  37. rspamd_logger_t *
  38. rspamd_log_emergency_logger (void)
  39. {
  40. return emergency_logger;
  41. }
  42. void
  43. rspamd_log_set_log_level (rspamd_logger_t *logger, gint level)
  44. {
  45. g_assert (logger != NULL);
  46. logger->log_level = level;
  47. }
  48. void
  49. rspamd_log_set_log_flags (rspamd_logger_t *logger, gint flags)
  50. {
  51. g_assert (logger != NULL);
  52. logger->flags = flags;
  53. }
  54. void
  55. rspamd_log_close (rspamd_logger_t *logger)
  56. {
  57. g_assert (logger != NULL);
  58. if (logger->closed) {
  59. return;
  60. }
  61. logger->closed = TRUE;
  62. if (logger->debug_ip) {
  63. rspamd_map_helper_destroy_radix (logger->debug_ip);
  64. }
  65. if (logger->pk) {
  66. rspamd_pubkey_unref (logger->pk);
  67. }
  68. if (logger->keypair) {
  69. rspamd_keypair_unref (logger->keypair);
  70. }
  71. logger->ops.dtor (logger, logger->ops.specific);
  72. /* TODO: Do we really need that ? */
  73. if (logger == default_logger) {
  74. default_logger = NULL;
  75. }
  76. if (logger == emergency_logger) {
  77. emergency_logger = NULL;
  78. }
  79. if (!logger->pool) {
  80. g_free (logger);
  81. }
  82. }
  83. bool
  84. rspamd_log_reopen (rspamd_logger_t *rspamd_log, struct rspamd_config *cfg,
  85. uid_t uid, gid_t gid)
  86. {
  87. void *nspec;
  88. GError *err = NULL;
  89. g_assert (rspamd_log != NULL);
  90. nspec = rspamd_log->ops.reload (rspamd_log, cfg, rspamd_log->ops.specific,
  91. uid, gid, &err);
  92. if (nspec != NULL) {
  93. rspamd_log->ops.specific = nspec;
  94. }
  95. else {
  96. }
  97. return nspec != NULL;
  98. }
  99. static void
  100. rspamd_emergency_logger_dtor (gpointer d)
  101. {
  102. rspamd_logger_t *logger = (rspamd_logger_t *)d;
  103. rspamd_log_close (logger);
  104. }
  105. rspamd_logger_t *
  106. rspamd_log_open_emergency (rspamd_mempool_t *pool)
  107. {
  108. rspamd_logger_t *logger;
  109. GError *err = NULL;
  110. g_assert (default_logger == NULL);
  111. g_assert (emergency_logger == NULL);
  112. if (pool) {
  113. logger = rspamd_mempool_alloc0 (pool, sizeof (rspamd_logger_t));
  114. logger->mtx = rspamd_mempool_get_mutex (pool);
  115. }
  116. else {
  117. logger = g_malloc0 (sizeof (rspamd_logger_t));
  118. }
  119. logger->pool = pool;
  120. logger->process_type = "main";
  121. const struct rspamd_logger_funcs *funcs = &console_log_funcs;
  122. memcpy (&logger->ops, funcs, sizeof (*funcs));
  123. logger->ops.specific = logger->ops.init (logger, NULL, -1, -1, &err);
  124. if (logger->ops.specific == NULL) {
  125. rspamd_fprintf (stderr, "fatal error: cannot init console logging: %e\n",
  126. err);
  127. g_error_free (err);
  128. exit (EXIT_FAILURE);
  129. }
  130. default_logger = logger;
  131. emergency_logger = logger;
  132. rspamd_mempool_add_destructor (pool, rspamd_emergency_logger_dtor,
  133. emergency_logger);
  134. return logger;
  135. }
  136. rspamd_logger_t *
  137. rspamd_log_open_specific (rspamd_mempool_t *pool,
  138. struct rspamd_config *cfg,
  139. const gchar *ptype,
  140. uid_t uid, gid_t gid)
  141. {
  142. rspamd_logger_t *logger;
  143. GError *err = NULL;
  144. if (pool) {
  145. logger = rspamd_mempool_alloc0 (pool, sizeof (rspamd_logger_t));
  146. logger->mtx = rspamd_mempool_get_mutex (pool);
  147. }
  148. else {
  149. logger = g_malloc0 (sizeof (rspamd_logger_t));
  150. }
  151. logger->pool = pool;
  152. if (cfg) {
  153. if (cfg->log_error_elts > 0 && pool) {
  154. logger->errlog = rspamd_mempool_alloc0_shared (pool,
  155. sizeof (*logger->errlog));
  156. logger->errlog->pool = pool;
  157. logger->errlog->max_elts = cfg->log_error_elts;
  158. logger->errlog->elt_len = cfg->log_error_elt_maxlen;
  159. logger->errlog->elts = rspamd_mempool_alloc0_shared (pool,
  160. sizeof (struct rspamd_logger_error_elt) * cfg->log_error_elts +
  161. cfg->log_error_elt_maxlen * cfg->log_error_elts);
  162. }
  163. logger->log_level = cfg->log_level;
  164. logger->flags = cfg->log_flags;
  165. if (!(logger->flags & RSPAMD_LOG_FLAG_ENFORCED)) {
  166. logger->log_level = cfg->log_level;
  167. }
  168. }
  169. const struct rspamd_logger_funcs *funcs = NULL;
  170. switch (cfg->log_type) {
  171. case RSPAMD_LOG_CONSOLE:
  172. funcs = &console_log_funcs;
  173. break;
  174. case RSPAMD_LOG_SYSLOG:
  175. funcs = &syslog_log_funcs;
  176. break;
  177. case RSPAMD_LOG_FILE:
  178. funcs = &file_log_funcs;
  179. break;
  180. }
  181. g_assert (funcs != NULL);
  182. memcpy (&logger->ops, funcs, sizeof (*funcs));
  183. logger->ops.specific = logger->ops.init (logger, cfg, uid, gid, &err);
  184. if (emergency_logger && logger->ops.specific == NULL) {
  185. rspamd_common_log_function (emergency_logger, G_LOG_LEVEL_CRITICAL,
  186. "logger", NULL, G_STRFUNC,
  187. "cannot open specific logger: %e", err);
  188. g_error_free (err);
  189. return NULL;
  190. }
  191. logger->pid = getpid ();
  192. logger->process_type = ptype;
  193. logger->enabled = TRUE;
  194. /* Set up conditional logging */
  195. if (cfg) {
  196. if (cfg->debug_ip_map != NULL) {
  197. /* Try to add it as map first of all */
  198. if (logger->debug_ip) {
  199. rspamd_map_helper_destroy_radix (logger->debug_ip);
  200. }
  201. logger->debug_ip = NULL;
  202. rspamd_config_radix_from_ucl (cfg,
  203. cfg->debug_ip_map,
  204. "IP addresses for which debug logs are enabled",
  205. &logger->debug_ip,
  206. NULL,
  207. NULL, "debug ip");
  208. }
  209. if (cfg->log_encryption_key) {
  210. logger->pk = rspamd_pubkey_ref (cfg->log_encryption_key);
  211. logger->keypair = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX,
  212. RSPAMD_CRYPTOBOX_MODE_25519);
  213. rspamd_pubkey_calculate_nm (logger->pk, logger->keypair);
  214. }
  215. }
  216. default_logger = logger;
  217. return logger;
  218. }
  219. /**
  220. * Used after fork() for updating structure params
  221. */
  222. void
  223. rspamd_log_on_fork (GQuark ptype, struct rspamd_config *cfg,
  224. rspamd_logger_t *logger)
  225. {
  226. logger->pid = getpid ();
  227. logger->process_type = g_quark_to_string (ptype);
  228. if (logger->ops.on_fork) {
  229. GError *err = NULL;
  230. bool ret = logger->ops.on_fork (logger, cfg, logger->ops.specific, &err);
  231. if (!ret && emergency_logger) {
  232. rspamd_common_log_function (emergency_logger, G_LOG_LEVEL_CRITICAL,
  233. "logger", NULL, G_STRFUNC,
  234. "cannot update logging on fork: %e", err);
  235. g_error_free (err);
  236. }
  237. }
  238. }
  239. static inline gboolean
  240. rspamd_logger_need_log (rspamd_logger_t *rspamd_log, GLogLevelFlags log_level,
  241. guint module_id)
  242. {
  243. g_assert (rspamd_log != NULL);
  244. if ((log_level & RSPAMD_LOG_FORCED) ||
  245. (log_level & (RSPAMD_LOG_LEVEL_MASK & G_LOG_LEVEL_MASK)) <= rspamd_log->log_level) {
  246. return TRUE;
  247. }
  248. if (module_id != (guint)-1 && isset (log_modules->bitset, module_id)) {
  249. return TRUE;
  250. }
  251. return FALSE;
  252. }
  253. static gchar *
  254. rspamd_log_encrypt_message (const gchar *begin, const gchar *end, gsize *enc_len,
  255. rspamd_logger_t *rspamd_log)
  256. {
  257. guchar *out;
  258. gchar *b64;
  259. guchar *p, *nonce, *mac;
  260. const guchar *comp;
  261. guint len, inlen;
  262. g_assert (end > begin);
  263. /* base64 (pubkey | nonce | message) */
  264. inlen = rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  265. rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  266. rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  267. (end - begin);
  268. out = g_malloc (inlen);
  269. p = out;
  270. comp = rspamd_pubkey_get_pk (rspamd_log->pk, &len);
  271. memcpy (p, comp, len);
  272. p += len;
  273. ottery_rand_bytes (p, rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519));
  274. nonce = p;
  275. p += rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  276. mac = p;
  277. p += rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  278. memcpy (p, begin, end - begin);
  279. comp = rspamd_pubkey_get_nm (rspamd_log->pk, rspamd_log->keypair);
  280. g_assert (comp != NULL);
  281. rspamd_cryptobox_encrypt_nm_inplace (p, end - begin, nonce, comp, mac,
  282. RSPAMD_CRYPTOBOX_MODE_25519);
  283. b64 = rspamd_encode_base64 (out, inlen, 0, enc_len);
  284. g_free (out);
  285. return b64;
  286. }
  287. static void
  288. rspamd_log_write_ringbuffer (rspamd_logger_t *rspamd_log,
  289. const gchar *module, const gchar *id,
  290. const gchar *data, glong len)
  291. {
  292. guint32 row_num;
  293. struct rspamd_logger_error_log *elog;
  294. struct rspamd_logger_error_elt *elt;
  295. if (!rspamd_log->errlog) {
  296. return;
  297. }
  298. elog = rspamd_log->errlog;
  299. g_atomic_int_compare_and_exchange (&elog->cur_row, elog->max_elts, 0);
  300. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
  301. row_num = g_atomic_int_add (&elog->cur_row, 1);
  302. #else
  303. row_num = g_atomic_int_exchange_and_add (&elog->cur_row, 1);
  304. #endif
  305. if (row_num < elog->max_elts) {
  306. elt = (struct rspamd_logger_error_elt *)(((guchar *)elog->elts) +
  307. (sizeof (*elt) + elog->elt_len) * row_num);
  308. g_atomic_int_set (&elt->completed, 0);
  309. }
  310. else {
  311. /* Race condition */
  312. elog->cur_row = 0;
  313. return;
  314. }
  315. elt->pid = rspamd_log->pid;
  316. elt->ptype = g_quark_from_string (rspamd_log->process_type);
  317. elt->ts = rspamd_get_calendar_ticks ();
  318. if (id) {
  319. rspamd_strlcpy (elt->id, id, sizeof (elt->id));
  320. }
  321. else {
  322. rspamd_strlcpy (elt->id, "", sizeof (elt->id));
  323. }
  324. if (module) {
  325. rspamd_strlcpy (elt->module, module, sizeof (elt->module));
  326. }
  327. else {
  328. rspamd_strlcpy (elt->module, "", sizeof (elt->module));
  329. }
  330. rspamd_strlcpy (elt->message, data, MIN (len + 1, elog->elt_len));
  331. g_atomic_int_set (&elt->completed, 1);
  332. }
  333. bool
  334. rspamd_common_logv (rspamd_logger_t *rspamd_log, gint level_flags,
  335. const gchar *module, const gchar *id, const gchar *function,
  336. const gchar *fmt, va_list args)
  337. {
  338. gchar logbuf[RSPAMD_LOGBUF_SIZE], *end;
  339. gint level = level_flags & (RSPAMD_LOG_LEVEL_MASK & G_LOG_LEVEL_MASK), mod_id;
  340. bool ret = false;
  341. if (G_UNLIKELY (rspamd_log == NULL)) {
  342. rspamd_log = default_logger;
  343. }
  344. if (G_UNLIKELY (rspamd_log == NULL)) {
  345. /* Just fprintf message to stderr */
  346. if (level >= G_LOG_LEVEL_INFO) {
  347. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
  348. rspamd_fprintf (stderr, "%*s\n", (gint)(end - logbuf), logbuf);
  349. }
  350. }
  351. else {
  352. if (level == G_LOG_LEVEL_DEBUG) {
  353. mod_id = rspamd_logger_add_debug_module (module);
  354. }
  355. else {
  356. mod_id = -1;
  357. }
  358. if (rspamd_logger_need_log (rspamd_log, level_flags, mod_id)) {
  359. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
  360. if ((level_flags & RSPAMD_LOG_ENCRYPTED) && rspamd_log->pk) {
  361. gchar *encrypted;
  362. gsize enc_len;
  363. encrypted = rspamd_log_encrypt_message (logbuf, end, &enc_len,
  364. rspamd_log);
  365. ret = rspamd_log->ops.log (module, id,
  366. function,
  367. level_flags,
  368. encrypted,
  369. enc_len,
  370. rspamd_log,
  371. rspamd_log->ops.specific);
  372. g_free (encrypted);
  373. }
  374. else {
  375. ret = rspamd_log->ops.log (module, id,
  376. function,
  377. level_flags,
  378. logbuf,
  379. end - logbuf,
  380. rspamd_log,
  381. rspamd_log->ops.specific);
  382. }
  383. switch (level) {
  384. case G_LOG_LEVEL_CRITICAL:
  385. rspamd_log->log_cnt[0] ++;
  386. rspamd_log_write_ringbuffer (rspamd_log, module, id, logbuf,
  387. end - logbuf);
  388. break;
  389. case G_LOG_LEVEL_WARNING:
  390. rspamd_log->log_cnt[1]++;
  391. break;
  392. case G_LOG_LEVEL_INFO:
  393. rspamd_log->log_cnt[2]++;
  394. break;
  395. case G_LOG_LEVEL_DEBUG:
  396. rspamd_log->log_cnt[3]++;
  397. break;
  398. default:
  399. break;
  400. }
  401. }
  402. }
  403. return ret;
  404. }
  405. /**
  406. * This log functions select real logger and write message if level is less or equal to configured log level
  407. */
  408. bool
  409. rspamd_common_log_function (rspamd_logger_t *rspamd_log,
  410. gint level_flags,
  411. const gchar *module, const gchar *id,
  412. const gchar *function,
  413. const gchar *fmt,
  414. ...)
  415. {
  416. va_list vp;
  417. va_start (vp, fmt);
  418. bool ret = rspamd_common_logv (rspamd_log, level_flags, module, id, function, fmt, vp);
  419. va_end (vp);
  420. return ret;
  421. }
  422. bool
  423. rspamd_default_logv (gint level_flags, const gchar *module, const gchar *id,
  424. const gchar *function,
  425. const gchar *fmt, va_list args)
  426. {
  427. return rspamd_common_logv (NULL, level_flags, module, id, function, fmt, args);
  428. }
  429. bool
  430. rspamd_default_log_function (gint level_flags,
  431. const gchar *module, const gchar *id,
  432. const gchar *function, const gchar *fmt, ...)
  433. {
  434. va_list vp;
  435. va_start (vp, fmt);
  436. bool ret = rspamd_default_logv (level_flags, module, id, function, fmt, vp);
  437. va_end (vp);
  438. return ret;
  439. }
  440. /**
  441. * Main file interface for logging
  442. */
  443. /**
  444. * Write log line depending on ip
  445. */
  446. bool
  447. rspamd_conditional_debug (rspamd_logger_t *rspamd_log,
  448. rspamd_inet_addr_t *addr, const gchar *module, const gchar *id,
  449. const gchar *function, const gchar *fmt, ...)
  450. {
  451. static gchar logbuf[LOGBUF_LEN];
  452. va_list vp;
  453. gchar *end;
  454. guint mod_id;
  455. if (rspamd_log == NULL) {
  456. rspamd_log = default_logger;
  457. }
  458. mod_id = rspamd_logger_add_debug_module (module);
  459. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  460. rspamd_log->is_debug) {
  461. if (rspamd_log->debug_ip && addr != NULL) {
  462. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip,
  463. addr) == NULL) {
  464. return false;
  465. }
  466. }
  467. va_start (vp, fmt);
  468. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  469. *end = '\0';
  470. va_end (vp);
  471. return rspamd_log->ops.log (module, id,
  472. function,
  473. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  474. logbuf,
  475. end - logbuf,
  476. rspamd_log,
  477. rspamd_log->ops.specific);
  478. }
  479. return false;
  480. }
  481. bool
  482. rspamd_conditional_debug_fast (rspamd_logger_t *rspamd_log,
  483. rspamd_inet_addr_t *addr,
  484. guint mod_id, const gchar *module, const gchar *id,
  485. const gchar *function, const gchar *fmt, ...)
  486. {
  487. static gchar logbuf[LOGBUF_LEN];
  488. va_list vp;
  489. gchar *end;
  490. if (rspamd_log == NULL) {
  491. rspamd_log = default_logger;
  492. }
  493. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  494. rspamd_log->is_debug) {
  495. if (rspamd_log->debug_ip && addr != NULL) {
  496. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip, addr)
  497. == NULL) {
  498. return false;
  499. }
  500. }
  501. va_start (vp, fmt);
  502. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  503. *end = '\0';
  504. va_end (vp);
  505. return rspamd_log->ops.log (module, id,
  506. function,
  507. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  508. logbuf,
  509. end - logbuf,
  510. rspamd_log,
  511. rspamd_log->ops.specific);
  512. }
  513. return false;
  514. }
  515. bool
  516. rspamd_conditional_debug_fast_num_id (rspamd_logger_t *rspamd_log,
  517. rspamd_inet_addr_t *addr,
  518. guint mod_id, const gchar *module, guint64 id,
  519. const gchar *function, const gchar *fmt, ...)
  520. {
  521. static gchar logbuf[LOGBUF_LEN], idbuf[64];
  522. va_list vp;
  523. gchar *end;
  524. if (rspamd_log == NULL) {
  525. rspamd_log = default_logger;
  526. }
  527. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  528. rspamd_log->is_debug) {
  529. if (rspamd_log->debug_ip && addr != NULL) {
  530. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip, addr)
  531. == NULL) {
  532. return false;
  533. }
  534. }
  535. rspamd_snprintf (idbuf, sizeof (idbuf), "%XuL", id);
  536. va_start (vp, fmt);
  537. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  538. *end = '\0';
  539. va_end (vp);
  540. return rspamd_log->ops.log (module, idbuf,
  541. function,
  542. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  543. logbuf,
  544. end - logbuf,
  545. rspamd_log,
  546. rspamd_log->ops.specific);
  547. }
  548. return false;
  549. }
  550. /**
  551. * Wrapper for glib logger
  552. */
  553. void
  554. rspamd_glib_log_function (const gchar *log_domain,
  555. GLogLevelFlags log_level,
  556. const gchar *message,
  557. gpointer arg)
  558. {
  559. rspamd_logger_t *rspamd_log = (rspamd_logger_t *)arg;
  560. if (rspamd_log->enabled &&
  561. rspamd_logger_need_log (rspamd_log, log_level, -1)) {
  562. rspamd_log->ops.log ("glib", NULL,
  563. NULL,
  564. log_level,
  565. message,
  566. strlen (message),
  567. rspamd_log,
  568. rspamd_log->ops.specific);
  569. }
  570. }
  571. void
  572. rspamd_glib_printerr_function (const gchar *message)
  573. {
  574. rspamd_common_log_function (NULL, G_LOG_LEVEL_CRITICAL, "glib",
  575. NULL, G_STRFUNC,
  576. "%s", message);
  577. }
  578. /**
  579. * Temporary turn on debugging
  580. */
  581. void
  582. rspamd_log_debug (rspamd_logger_t *rspamd_log)
  583. {
  584. rspamd_log->is_debug = TRUE;
  585. }
  586. /**
  587. * Turn off temporary debugging
  588. */
  589. void
  590. rspamd_log_nodebug (rspamd_logger_t *rspamd_log)
  591. {
  592. rspamd_log->is_debug = FALSE;
  593. }
  594. const guint64 *
  595. rspamd_log_counters (rspamd_logger_t *logger)
  596. {
  597. if (logger) {
  598. return logger->log_cnt;
  599. }
  600. return NULL;
  601. }
  602. static gint
  603. rspamd_log_errlog_cmp (const ucl_object_t **o1, const ucl_object_t **o2)
  604. {
  605. const ucl_object_t *ts1, *ts2;
  606. ts1 = ucl_object_lookup (*o1, "ts");
  607. ts2 = ucl_object_lookup (*o2, "ts");
  608. if (ts1 && ts2) {
  609. gdouble t1 = ucl_object_todouble (ts1), t2 = ucl_object_todouble (ts2);
  610. if (t1 > t2) {
  611. return -1;
  612. }
  613. else if (t2 > t1) {
  614. return 1;
  615. }
  616. }
  617. return 0;
  618. }
  619. ucl_object_t *
  620. rspamd_log_errorbuf_export (const rspamd_logger_t *logger)
  621. {
  622. struct rspamd_logger_error_elt *cpy, *cur;
  623. ucl_object_t *top = ucl_object_typed_new (UCL_ARRAY);
  624. guint i;
  625. if (logger->errlog == NULL) {
  626. return top;
  627. }
  628. cpy = g_malloc0_n (logger->errlog->max_elts,
  629. sizeof (*cpy) + logger->errlog->elt_len);
  630. memcpy (cpy, logger->errlog->elts, logger->errlog->max_elts *
  631. (sizeof (*cpy) + logger->errlog->elt_len));
  632. for (i = 0; i < logger->errlog->max_elts; i ++) {
  633. cur = (struct rspamd_logger_error_elt *)((guchar *)cpy +
  634. i * ((sizeof (*cpy) + logger->errlog->elt_len)));
  635. if (cur->completed) {
  636. ucl_object_t *obj = ucl_object_typed_new (UCL_OBJECT);
  637. ucl_object_insert_key (obj, ucl_object_fromdouble (cur->ts),
  638. "ts", 0, false);
  639. ucl_object_insert_key (obj, ucl_object_fromint (cur->pid),
  640. "pid", 0, false);
  641. ucl_object_insert_key (obj,
  642. ucl_object_fromstring (g_quark_to_string (cur->ptype)),
  643. "type", 0, false);
  644. ucl_object_insert_key (obj, ucl_object_fromstring (cur->id),
  645. "id", 0, false);
  646. ucl_object_insert_key (obj, ucl_object_fromstring (cur->module),
  647. "module", 0, false);
  648. ucl_object_insert_key (obj, ucl_object_fromstring (cur->message),
  649. "message", 0, false);
  650. ucl_array_append (top, obj);
  651. }
  652. }
  653. ucl_object_array_sort (top, rspamd_log_errlog_cmp);
  654. g_free (cpy);
  655. return top;
  656. }
  657. static guint
  658. rspamd_logger_allocate_mod_bit (void)
  659. {
  660. if (log_modules->bitset_allocated * NBBY > log_modules->bitset_len + 1) {
  661. log_modules->bitset_len ++;
  662. return log_modules->bitset_len - 1;
  663. }
  664. else {
  665. /* Need to expand */
  666. log_modules->bitset_allocated *= 2;
  667. log_modules->bitset = g_realloc (log_modules->bitset,
  668. log_modules->bitset_allocated);
  669. return rspamd_logger_allocate_mod_bit ();
  670. }
  671. }
  672. RSPAMD_DESTRUCTOR (rspamd_debug_modules_dtor)
  673. {
  674. if (log_modules) {
  675. g_hash_table_unref (log_modules->modules);
  676. g_free (log_modules->bitset);
  677. g_free (log_modules);
  678. }
  679. }
  680. guint
  681. rspamd_logger_add_debug_module (const gchar *mname)
  682. {
  683. struct rspamd_log_module *m;
  684. if (mname == NULL) {
  685. return (guint)-1;
  686. }
  687. if (log_modules == NULL) {
  688. /*
  689. * This is usually called from constructors, so we call init check
  690. * each time to avoid dependency issues between ctors calls
  691. */
  692. log_modules = g_malloc0 (sizeof (*log_modules));
  693. log_modules->modules = g_hash_table_new_full (rspamd_strcase_hash,
  694. rspamd_strcase_equal, g_free, g_free);
  695. log_modules->bitset_allocated = 16;
  696. log_modules->bitset_len = 0;
  697. log_modules->bitset = g_malloc0 (log_modules->bitset_allocated);
  698. }
  699. if ((m = g_hash_table_lookup (log_modules->modules, mname)) == NULL) {
  700. m = g_malloc0 (sizeof (*m));
  701. m->mname = g_strdup (mname);
  702. m->id = rspamd_logger_allocate_mod_bit ();
  703. clrbit (log_modules->bitset, m->id);
  704. g_hash_table_insert (log_modules->modules, m->mname, m);
  705. }
  706. return m->id;
  707. }
  708. void
  709. rspamd_logger_configure_modules (GHashTable *mods_enabled)
  710. {
  711. GHashTableIter it;
  712. gpointer k, v;
  713. guint id;
  714. /* Clear all in bitset_allocated -> this are bytes not bits */
  715. memset (log_modules->bitset, 0, log_modules->bitset_allocated);
  716. /* On first iteration, we go through all modules enabled and add missing ones */
  717. g_hash_table_iter_init (&it, mods_enabled);
  718. while (g_hash_table_iter_next (&it, &k, &v)) {
  719. rspamd_logger_add_debug_module ((const gchar *)k);
  720. }
  721. g_hash_table_iter_init (&it, mods_enabled);
  722. while (g_hash_table_iter_next (&it, &k, &v)) {
  723. id = rspamd_logger_add_debug_module ((const gchar *)k);
  724. if (isclr (log_modules->bitset, id)) {
  725. msg_info ("enable debugging for module %s (%d)", (const gchar *) k,
  726. id);
  727. setbit (log_modules->bitset, id);
  728. }
  729. }
  730. }
  731. struct rspamd_logger_funcs*
  732. rspamd_logger_set_log_function (rspamd_logger_t *logger,
  733. struct rspamd_logger_funcs *nfuncs)
  734. {
  735. /* TODO: write this */
  736. return NULL;
  737. }