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 23KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  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. if (logger == NULL) {
  46. logger = default_logger;
  47. }
  48. logger->log_level = level;
  49. }
  50. gint
  51. rspamd_log_get_log_level (rspamd_logger_t *logger)
  52. {
  53. if (logger == NULL) {
  54. logger = default_logger;
  55. }
  56. return logger->log_level;
  57. }
  58. void
  59. rspamd_log_set_log_flags (rspamd_logger_t *logger, gint flags)
  60. {
  61. g_assert (logger != NULL);
  62. logger->flags = flags;
  63. }
  64. void
  65. rspamd_log_close (rspamd_logger_t *logger)
  66. {
  67. g_assert (logger != NULL);
  68. if (logger->closed) {
  69. return;
  70. }
  71. logger->closed = TRUE;
  72. if (logger->debug_ip) {
  73. rspamd_map_helper_destroy_radix (logger->debug_ip);
  74. }
  75. if (logger->pk) {
  76. rspamd_pubkey_unref (logger->pk);
  77. }
  78. if (logger->keypair) {
  79. rspamd_keypair_unref (logger->keypair);
  80. }
  81. logger->ops.dtor (logger, logger->ops.specific);
  82. /* TODO: Do we really need that ? */
  83. if (logger == default_logger) {
  84. default_logger = NULL;
  85. }
  86. if (logger == emergency_logger) {
  87. emergency_logger = NULL;
  88. }
  89. if (!logger->pool) {
  90. g_free (logger);
  91. }
  92. }
  93. bool
  94. rspamd_log_reopen (rspamd_logger_t *rspamd_log, struct rspamd_config *cfg,
  95. uid_t uid, gid_t gid)
  96. {
  97. void *nspec;
  98. GError *err = NULL;
  99. g_assert (rspamd_log != NULL);
  100. nspec = rspamd_log->ops.reload (rspamd_log, cfg, rspamd_log->ops.specific,
  101. uid, gid, &err);
  102. if (nspec != NULL) {
  103. rspamd_log->ops.specific = nspec;
  104. }
  105. else {
  106. }
  107. return nspec != NULL;
  108. }
  109. static void
  110. rspamd_emergency_logger_dtor (gpointer d)
  111. {
  112. rspamd_logger_t *logger = (rspamd_logger_t *)d;
  113. rspamd_log_close (logger);
  114. }
  115. rspamd_logger_t *
  116. rspamd_log_open_emergency (rspamd_mempool_t *pool, gint flags)
  117. {
  118. rspamd_logger_t *logger;
  119. GError *err = NULL;
  120. g_assert (default_logger == NULL);
  121. g_assert (emergency_logger == NULL);
  122. if (pool) {
  123. logger = rspamd_mempool_alloc0 (pool, sizeof (rspamd_logger_t));
  124. logger->mtx = rspamd_mempool_get_mutex (pool);
  125. }
  126. else {
  127. logger = g_malloc0 (sizeof (rspamd_logger_t));
  128. }
  129. logger->flags = flags;
  130. logger->pool = pool;
  131. logger->process_type = "main";
  132. logger->pid = getpid ();
  133. const struct rspamd_logger_funcs *funcs = &console_log_funcs;
  134. memcpy (&logger->ops, funcs, sizeof (*funcs));
  135. logger->ops.specific = logger->ops.init (logger, NULL, -1, -1, &err);
  136. if (logger->ops.specific == NULL) {
  137. rspamd_fprintf (stderr, "fatal error: cannot init console logging: %e\n",
  138. err);
  139. g_error_free (err);
  140. exit (EXIT_FAILURE);
  141. }
  142. default_logger = logger;
  143. emergency_logger = logger;
  144. rspamd_mempool_add_destructor (pool, rspamd_emergency_logger_dtor,
  145. emergency_logger);
  146. return logger;
  147. }
  148. rspamd_logger_t *
  149. rspamd_log_open_specific (rspamd_mempool_t *pool,
  150. struct rspamd_config *cfg,
  151. const gchar *ptype,
  152. uid_t uid, gid_t gid)
  153. {
  154. rspamd_logger_t *logger;
  155. GError *err = NULL;
  156. if (pool) {
  157. logger = rspamd_mempool_alloc0 (pool, sizeof (rspamd_logger_t));
  158. logger->mtx = rspamd_mempool_get_mutex (pool);
  159. }
  160. else {
  161. logger = g_malloc0 (sizeof (rspamd_logger_t));
  162. }
  163. logger->pool = pool;
  164. if (cfg) {
  165. if (cfg->log_error_elts > 0 && pool) {
  166. logger->errlog = rspamd_mempool_alloc0_shared (pool,
  167. sizeof (*logger->errlog));
  168. logger->errlog->pool = pool;
  169. logger->errlog->max_elts = cfg->log_error_elts;
  170. logger->errlog->elt_len = cfg->log_error_elt_maxlen;
  171. logger->errlog->elts = rspamd_mempool_alloc0_shared (pool,
  172. sizeof (struct rspamd_logger_error_elt) * cfg->log_error_elts +
  173. cfg->log_error_elt_maxlen * cfg->log_error_elts);
  174. }
  175. logger->log_level = cfg->log_level;
  176. logger->flags = cfg->log_flags;
  177. if (!(logger->flags & RSPAMD_LOG_FLAG_ENFORCED)) {
  178. logger->log_level = cfg->log_level;
  179. }
  180. }
  181. const struct rspamd_logger_funcs *funcs = NULL;
  182. if (cfg) {
  183. switch (cfg->log_type) {
  184. case RSPAMD_LOG_CONSOLE:
  185. funcs = &console_log_funcs;
  186. break;
  187. case RSPAMD_LOG_SYSLOG:
  188. funcs = &syslog_log_funcs;
  189. break;
  190. case RSPAMD_LOG_FILE:
  191. funcs = &file_log_funcs;
  192. break;
  193. }
  194. }
  195. else {
  196. funcs = &console_log_funcs;
  197. }
  198. g_assert (funcs != NULL);
  199. memcpy (&logger->ops, funcs, sizeof (*funcs));
  200. logger->ops.specific = logger->ops.init (logger, cfg, uid, gid, &err);
  201. if (emergency_logger && logger->ops.specific == NULL) {
  202. rspamd_common_log_function (emergency_logger, G_LOG_LEVEL_CRITICAL,
  203. "logger", NULL, G_STRFUNC,
  204. "cannot open specific logger: %e", err);
  205. g_error_free (err);
  206. return NULL;
  207. }
  208. logger->pid = getpid ();
  209. logger->process_type = ptype;
  210. logger->enabled = TRUE;
  211. /* Set up conditional logging */
  212. if (cfg) {
  213. if (cfg->debug_ip_map != NULL) {
  214. /* Try to add it as map first of all */
  215. if (logger->debug_ip) {
  216. rspamd_map_helper_destroy_radix (logger->debug_ip);
  217. }
  218. logger->debug_ip = NULL;
  219. rspamd_config_radix_from_ucl (cfg,
  220. cfg->debug_ip_map,
  221. "IP addresses for which debug logs are enabled",
  222. &logger->debug_ip,
  223. NULL,
  224. NULL, "debug ip");
  225. }
  226. if (cfg->log_encryption_key) {
  227. logger->pk = rspamd_pubkey_ref (cfg->log_encryption_key);
  228. logger->keypair = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX,
  229. RSPAMD_CRYPTOBOX_MODE_25519);
  230. rspamd_pubkey_calculate_nm (logger->pk, logger->keypair);
  231. }
  232. }
  233. default_logger = logger;
  234. return logger;
  235. }
  236. /**
  237. * Used after fork() for updating structure params
  238. */
  239. void
  240. rspamd_log_on_fork (GQuark ptype, struct rspamd_config *cfg,
  241. rspamd_logger_t *logger)
  242. {
  243. logger->pid = getpid ();
  244. logger->process_type = g_quark_to_string (ptype);
  245. if (logger->ops.on_fork) {
  246. GError *err = NULL;
  247. bool ret = logger->ops.on_fork (logger, cfg, logger->ops.specific, &err);
  248. if (!ret && emergency_logger) {
  249. rspamd_common_log_function (emergency_logger, G_LOG_LEVEL_CRITICAL,
  250. "logger", NULL, G_STRFUNC,
  251. "cannot update logging on fork: %e", err);
  252. g_error_free (err);
  253. }
  254. }
  255. }
  256. inline gboolean
  257. rspamd_logger_need_log (rspamd_logger_t *rspamd_log, GLogLevelFlags log_level,
  258. gint module_id)
  259. {
  260. g_assert (rspamd_log != NULL);
  261. if ((log_level & RSPAMD_LOG_FORCED) ||
  262. (log_level & (RSPAMD_LOG_LEVEL_MASK & G_LOG_LEVEL_MASK)) <= rspamd_log->log_level) {
  263. return TRUE;
  264. }
  265. if (module_id != -1 && isset (log_modules->bitset, module_id)) {
  266. return TRUE;
  267. }
  268. return FALSE;
  269. }
  270. static gchar *
  271. rspamd_log_encrypt_message (const gchar *begin, const gchar *end, gsize *enc_len,
  272. rspamd_logger_t *rspamd_log)
  273. {
  274. guchar *out;
  275. gchar *b64;
  276. guchar *p, *nonce, *mac;
  277. const guchar *comp;
  278. guint len, inlen;
  279. g_assert (end > begin);
  280. /* base64 (pubkey | nonce | message) */
  281. inlen = rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  282. rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  283. rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  284. (end - begin);
  285. out = g_malloc (inlen);
  286. p = out;
  287. comp = rspamd_pubkey_get_pk (rspamd_log->pk, &len);
  288. memcpy (p, comp, len);
  289. p += len;
  290. ottery_rand_bytes (p, rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519));
  291. nonce = p;
  292. p += rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  293. mac = p;
  294. p += rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  295. memcpy (p, begin, end - begin);
  296. comp = rspamd_pubkey_get_nm (rspamd_log->pk, rspamd_log->keypair);
  297. g_assert (comp != NULL);
  298. rspamd_cryptobox_encrypt_nm_inplace (p, end - begin, nonce, comp, mac,
  299. RSPAMD_CRYPTOBOX_MODE_25519);
  300. b64 = rspamd_encode_base64 (out, inlen, 0, enc_len);
  301. g_free (out);
  302. return b64;
  303. }
  304. static void
  305. rspamd_log_write_ringbuffer (rspamd_logger_t *rspamd_log,
  306. const gchar *module, const gchar *id,
  307. const gchar *data, glong len)
  308. {
  309. guint32 row_num;
  310. struct rspamd_logger_error_log *elog;
  311. struct rspamd_logger_error_elt *elt;
  312. if (!rspamd_log->errlog) {
  313. return;
  314. }
  315. elog = rspamd_log->errlog;
  316. g_atomic_int_compare_and_exchange (&elog->cur_row, elog->max_elts, 0);
  317. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
  318. row_num = g_atomic_int_add (&elog->cur_row, 1);
  319. #else
  320. row_num = g_atomic_int_exchange_and_add (&elog->cur_row, 1);
  321. #endif
  322. if (row_num < elog->max_elts) {
  323. elt = (struct rspamd_logger_error_elt *)(((guchar *)elog->elts) +
  324. (sizeof (*elt) + elog->elt_len) * row_num);
  325. g_atomic_int_set (&elt->completed, 0);
  326. }
  327. else {
  328. /* Race condition */
  329. elog->cur_row = 0;
  330. return;
  331. }
  332. elt->pid = rspamd_log->pid;
  333. elt->ptype = g_quark_from_string (rspamd_log->process_type);
  334. elt->ts = rspamd_get_calendar_ticks ();
  335. if (id) {
  336. rspamd_strlcpy (elt->id, id, sizeof (elt->id));
  337. }
  338. else {
  339. rspamd_strlcpy (elt->id, "", sizeof (elt->id));
  340. }
  341. if (module) {
  342. rspamd_strlcpy (elt->module, module, sizeof (elt->module));
  343. }
  344. else {
  345. rspamd_strlcpy (elt->module, "", sizeof (elt->module));
  346. }
  347. rspamd_strlcpy (elt->message, data, MIN (len + 1, elog->elt_len));
  348. g_atomic_int_set (&elt->completed, 1);
  349. }
  350. bool
  351. rspamd_common_logv (rspamd_logger_t *rspamd_log, gint level_flags,
  352. const gchar *module, const gchar *id, const gchar *function,
  353. const gchar *fmt, va_list args)
  354. {
  355. gchar *end;
  356. gint level = level_flags & (RSPAMD_LOG_LEVEL_MASK & G_LOG_LEVEL_MASK), mod_id;
  357. bool ret = false;
  358. gchar logbuf[RSPAMD_LOGBUF_SIZE], *log_line;
  359. gsize nescaped;
  360. if (G_UNLIKELY (rspamd_log == NULL)) {
  361. rspamd_log = default_logger;
  362. }
  363. log_line = logbuf;
  364. if (G_UNLIKELY (rspamd_log == NULL)) {
  365. /* Just fprintf message to stderr */
  366. if (level >= G_LOG_LEVEL_INFO) {
  367. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
  368. rspamd_fprintf (stderr, "%*s\n", (gint)(end - log_line),
  369. log_line);
  370. }
  371. }
  372. else {
  373. if (level == G_LOG_LEVEL_DEBUG) {
  374. mod_id = rspamd_logger_add_debug_module (module);
  375. }
  376. else {
  377. mod_id = -1;
  378. }
  379. if (rspamd_logger_need_log (rspamd_log, level_flags, mod_id)) {
  380. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
  381. if (!(rspamd_log->flags & RSPAMD_LOG_FLAG_RSPAMADM)) {
  382. if ((nescaped = rspamd_log_line_need_escape (logbuf, end - logbuf)) != 0) {
  383. gsize unescaped_len = end - logbuf;
  384. gchar *logbuf_escaped = g_alloca (unescaped_len + nescaped * 4);
  385. log_line = logbuf_escaped;
  386. end = rspamd_log_line_hex_escape (logbuf, unescaped_len,
  387. logbuf_escaped, unescaped_len + nescaped * 4);
  388. }
  389. }
  390. if ((level_flags & RSPAMD_LOG_ENCRYPTED) && rspamd_log->pk) {
  391. gchar *encrypted;
  392. gsize enc_len;
  393. encrypted = rspamd_log_encrypt_message (log_line, end, &enc_len,
  394. rspamd_log);
  395. ret = rspamd_log->ops.log (module, id,
  396. function,
  397. level_flags,
  398. encrypted,
  399. enc_len,
  400. rspamd_log,
  401. rspamd_log->ops.specific);
  402. g_free (encrypted);
  403. }
  404. else {
  405. ret = rspamd_log->ops.log (module, id,
  406. function,
  407. level_flags,
  408. log_line,
  409. end - log_line,
  410. rspamd_log,
  411. rspamd_log->ops.specific);
  412. }
  413. switch (level) {
  414. case G_LOG_LEVEL_CRITICAL:
  415. rspamd_log->log_cnt[0] ++;
  416. rspamd_log_write_ringbuffer (rspamd_log, module, id, log_line,
  417. end - log_line);
  418. break;
  419. case G_LOG_LEVEL_WARNING:
  420. rspamd_log->log_cnt[1]++;
  421. break;
  422. case G_LOG_LEVEL_INFO:
  423. rspamd_log->log_cnt[2]++;
  424. break;
  425. case G_LOG_LEVEL_DEBUG:
  426. rspamd_log->log_cnt[3]++;
  427. break;
  428. default:
  429. break;
  430. }
  431. }
  432. }
  433. return ret;
  434. }
  435. /**
  436. * This log functions select real logger and write message if level is less or equal to configured log level
  437. */
  438. bool
  439. rspamd_common_log_function (rspamd_logger_t *rspamd_log,
  440. gint level_flags,
  441. const gchar *module, const gchar *id,
  442. const gchar *function,
  443. const gchar *fmt,
  444. ...)
  445. {
  446. va_list vp;
  447. va_start (vp, fmt);
  448. bool ret = rspamd_common_logv (rspamd_log, level_flags, module, id, function, fmt, vp);
  449. va_end (vp);
  450. return ret;
  451. }
  452. bool
  453. rspamd_default_logv (gint level_flags, const gchar *module, const gchar *id,
  454. const gchar *function,
  455. const gchar *fmt, va_list args)
  456. {
  457. return rspamd_common_logv (NULL, level_flags, module, id, function, fmt, args);
  458. }
  459. bool
  460. rspamd_default_log_function (gint level_flags,
  461. const gchar *module, const gchar *id,
  462. const gchar *function, const gchar *fmt, ...)
  463. {
  464. va_list vp;
  465. va_start (vp, fmt);
  466. bool ret = rspamd_default_logv (level_flags, module, id, function, fmt, vp);
  467. va_end (vp);
  468. return ret;
  469. }
  470. /**
  471. * Main file interface for logging
  472. */
  473. /**
  474. * Write log line depending on ip
  475. */
  476. bool
  477. rspamd_conditional_debug (rspamd_logger_t *rspamd_log,
  478. rspamd_inet_addr_t *addr, const gchar *module, const gchar *id,
  479. const gchar *function, const gchar *fmt, ...)
  480. {
  481. static gchar logbuf[LOGBUF_LEN];
  482. va_list vp;
  483. gchar *end;
  484. gint mod_id;
  485. if (rspamd_log == NULL) {
  486. rspamd_log = default_logger;
  487. }
  488. mod_id = rspamd_logger_add_debug_module (module);
  489. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  490. rspamd_log->is_debug) {
  491. if (rspamd_log->debug_ip && addr != NULL) {
  492. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip,
  493. addr) == NULL) {
  494. return false;
  495. }
  496. }
  497. va_start (vp, fmt);
  498. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  499. *end = '\0';
  500. va_end (vp);
  501. return rspamd_log->ops.log (module, id,
  502. function,
  503. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  504. logbuf,
  505. end - logbuf,
  506. rspamd_log,
  507. rspamd_log->ops.specific);
  508. }
  509. return false;
  510. }
  511. bool
  512. rspamd_conditional_debug_fast (rspamd_logger_t *rspamd_log,
  513. rspamd_inet_addr_t *addr,
  514. gint mod_id, const gchar *module, const gchar *id,
  515. const gchar *function, const gchar *fmt, ...)
  516. {
  517. static gchar logbuf[LOGBUF_LEN];
  518. va_list vp;
  519. gchar *end;
  520. if (rspamd_log == NULL) {
  521. rspamd_log = default_logger;
  522. }
  523. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  524. rspamd_log->is_debug) {
  525. if (rspamd_log->debug_ip && addr != NULL) {
  526. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip, addr)
  527. == NULL) {
  528. return false;
  529. }
  530. }
  531. va_start (vp, fmt);
  532. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  533. *end = '\0';
  534. va_end (vp);
  535. return rspamd_log->ops.log (module, id,
  536. function,
  537. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  538. logbuf,
  539. end - logbuf,
  540. rspamd_log,
  541. rspamd_log->ops.specific);
  542. }
  543. return false;
  544. }
  545. bool
  546. rspamd_conditional_debug_fast_num_id (rspamd_logger_t *rspamd_log,
  547. rspamd_inet_addr_t *addr,
  548. gint mod_id, const gchar *module, guint64 id,
  549. const gchar *function, const gchar *fmt, ...)
  550. {
  551. static gchar logbuf[LOGBUF_LEN], idbuf[64];
  552. va_list vp;
  553. gchar *end;
  554. if (rspamd_log == NULL) {
  555. rspamd_log = default_logger;
  556. }
  557. if (rspamd_logger_need_log (rspamd_log, G_LOG_LEVEL_DEBUG, mod_id) ||
  558. rspamd_log->is_debug) {
  559. if (rspamd_log->debug_ip && addr != NULL) {
  560. if (rspamd_match_radix_map_addr (rspamd_log->debug_ip, addr)
  561. == NULL) {
  562. return false;
  563. }
  564. }
  565. rspamd_snprintf (idbuf, sizeof (idbuf), "%XuL", id);
  566. va_start (vp, fmt);
  567. end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp);
  568. *end = '\0';
  569. va_end (vp);
  570. return rspamd_log->ops.log (module, idbuf,
  571. function,
  572. G_LOG_LEVEL_DEBUG | RSPAMD_LOG_FORCED,
  573. logbuf,
  574. end - logbuf,
  575. rspamd_log,
  576. rspamd_log->ops.specific);
  577. }
  578. return false;
  579. }
  580. /**
  581. * Wrapper for glib logger
  582. */
  583. void
  584. rspamd_glib_log_function (const gchar *log_domain,
  585. GLogLevelFlags log_level,
  586. const gchar *message,
  587. gpointer arg)
  588. {
  589. rspamd_logger_t *rspamd_log = (rspamd_logger_t *)arg;
  590. if (rspamd_log->enabled &&
  591. rspamd_logger_need_log (rspamd_log, log_level, -1)) {
  592. rspamd_log->ops.log ("glib", NULL,
  593. NULL,
  594. log_level,
  595. message,
  596. strlen (message),
  597. rspamd_log,
  598. rspamd_log->ops.specific);
  599. }
  600. }
  601. void
  602. rspamd_glib_printerr_function (const gchar *message)
  603. {
  604. rspamd_common_log_function (NULL, G_LOG_LEVEL_CRITICAL, "glib",
  605. NULL, G_STRFUNC,
  606. "%s", message);
  607. }
  608. /**
  609. * Temporary turn on debugging
  610. */
  611. void
  612. rspamd_log_debug (rspamd_logger_t *rspamd_log)
  613. {
  614. rspamd_log->is_debug = TRUE;
  615. }
  616. /**
  617. * Turn off temporary debugging
  618. */
  619. void
  620. rspamd_log_nodebug (rspamd_logger_t *rspamd_log)
  621. {
  622. rspamd_log->is_debug = FALSE;
  623. }
  624. const guint64 *
  625. rspamd_log_counters (rspamd_logger_t *logger)
  626. {
  627. if (logger) {
  628. return logger->log_cnt;
  629. }
  630. return NULL;
  631. }
  632. static gint
  633. rspamd_log_errlog_cmp (const ucl_object_t **o1, const ucl_object_t **o2)
  634. {
  635. const ucl_object_t *ts1, *ts2;
  636. ts1 = ucl_object_lookup (*o1, "ts");
  637. ts2 = ucl_object_lookup (*o2, "ts");
  638. if (ts1 && ts2) {
  639. gdouble t1 = ucl_object_todouble (ts1), t2 = ucl_object_todouble (ts2);
  640. if (t1 > t2) {
  641. return -1;
  642. }
  643. else if (t2 > t1) {
  644. return 1;
  645. }
  646. }
  647. return 0;
  648. }
  649. ucl_object_t *
  650. rspamd_log_errorbuf_export (const rspamd_logger_t *logger)
  651. {
  652. struct rspamd_logger_error_elt *cpy, *cur;
  653. ucl_object_t *top = ucl_object_typed_new (UCL_ARRAY);
  654. guint i;
  655. if (logger->errlog == NULL) {
  656. return top;
  657. }
  658. cpy = g_malloc0_n (logger->errlog->max_elts,
  659. sizeof (*cpy) + logger->errlog->elt_len);
  660. memcpy (cpy, logger->errlog->elts, logger->errlog->max_elts *
  661. (sizeof (*cpy) + logger->errlog->elt_len));
  662. for (i = 0; i < logger->errlog->max_elts; i ++) {
  663. cur = (struct rspamd_logger_error_elt *)((guchar *)cpy +
  664. i * ((sizeof (*cpy) + logger->errlog->elt_len)));
  665. if (cur->completed) {
  666. ucl_object_t *obj = ucl_object_typed_new (UCL_OBJECT);
  667. ucl_object_insert_key (obj, ucl_object_fromdouble (cur->ts),
  668. "ts", 0, false);
  669. ucl_object_insert_key (obj, ucl_object_fromint (cur->pid),
  670. "pid", 0, false);
  671. ucl_object_insert_key (obj,
  672. ucl_object_fromstring (g_quark_to_string (cur->ptype)),
  673. "type", 0, false);
  674. ucl_object_insert_key (obj, ucl_object_fromstring (cur->id),
  675. "id", 0, false);
  676. ucl_object_insert_key (obj, ucl_object_fromstring (cur->module),
  677. "module", 0, false);
  678. ucl_object_insert_key (obj, ucl_object_fromstring (cur->message),
  679. "message", 0, false);
  680. ucl_array_append (top, obj);
  681. }
  682. }
  683. ucl_object_array_sort (top, rspamd_log_errlog_cmp);
  684. g_free (cpy);
  685. return top;
  686. }
  687. static guint
  688. rspamd_logger_allocate_mod_bit (void)
  689. {
  690. if (log_modules->bitset_allocated * NBBY > log_modules->bitset_len + 1) {
  691. log_modules->bitset_len ++;
  692. return log_modules->bitset_len - 1;
  693. }
  694. else {
  695. /* Need to expand */
  696. log_modules->bitset_allocated *= 2;
  697. log_modules->bitset = g_realloc (log_modules->bitset,
  698. log_modules->bitset_allocated);
  699. return rspamd_logger_allocate_mod_bit ();
  700. }
  701. }
  702. RSPAMD_DESTRUCTOR (rspamd_debug_modules_dtor)
  703. {
  704. if (log_modules) {
  705. g_hash_table_unref (log_modules->modules);
  706. g_free (log_modules->bitset);
  707. g_free (log_modules);
  708. }
  709. }
  710. gint
  711. rspamd_logger_add_debug_module (const gchar *mname)
  712. {
  713. struct rspamd_log_module *m;
  714. if (mname == NULL) {
  715. return -1;
  716. }
  717. if (log_modules == NULL) {
  718. /*
  719. * This is usually called from constructors, so we call init check
  720. * each time to avoid dependency issues between ctors calls
  721. */
  722. log_modules = g_malloc0 (sizeof (*log_modules));
  723. log_modules->modules = g_hash_table_new_full (rspamd_strcase_hash,
  724. rspamd_strcase_equal, g_free, g_free);
  725. log_modules->bitset_allocated = 16;
  726. log_modules->bitset_len = 0;
  727. log_modules->bitset = g_malloc0 (log_modules->bitset_allocated);
  728. }
  729. if ((m = g_hash_table_lookup (log_modules->modules, mname)) == NULL) {
  730. m = g_malloc0 (sizeof (*m));
  731. m->mname = g_strdup (mname);
  732. m->id = rspamd_logger_allocate_mod_bit ();
  733. clrbit (log_modules->bitset, m->id);
  734. g_hash_table_insert (log_modules->modules, m->mname, m);
  735. }
  736. return m->id;
  737. }
  738. void
  739. rspamd_logger_configure_modules (GHashTable *mods_enabled)
  740. {
  741. GHashTableIter it;
  742. gpointer k, v;
  743. guint id;
  744. /* Clear all in bitset_allocated -> this are bytes not bits */
  745. memset (log_modules->bitset, 0, log_modules->bitset_allocated);
  746. /* On first iteration, we go through all modules enabled and add missing ones */
  747. g_hash_table_iter_init (&it, mods_enabled);
  748. while (g_hash_table_iter_next (&it, &k, &v)) {
  749. rspamd_logger_add_debug_module ((const gchar *)k);
  750. }
  751. g_hash_table_iter_init (&it, mods_enabled);
  752. while (g_hash_table_iter_next (&it, &k, &v)) {
  753. id = rspamd_logger_add_debug_module ((const gchar *)k);
  754. if (isclr (log_modules->bitset, id)) {
  755. msg_info ("enable debugging for module %s (%d)", (const gchar *) k,
  756. id);
  757. setbit (log_modules->bitset, id);
  758. }
  759. }
  760. }
  761. struct rspamd_logger_funcs*
  762. rspamd_logger_set_log_function (rspamd_logger_t *logger,
  763. struct rspamd_logger_funcs *nfuncs)
  764. {
  765. /* TODO: write this */
  766. return NULL;
  767. }
  768. gchar *
  769. rspamd_log_line_hex_escape (const guchar *src, gsize srclen,
  770. gchar *dst, gsize dstlen)
  771. {
  772. static const gchar hexdigests[16] = "0123456789ABCDEF";
  773. gchar *d = dst;
  774. static guint32 escape[] = {
  775. 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
  776. /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
  777. 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
  778. /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
  779. 0x00000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
  780. /* ~}| {zyx wvut srqp onml kjih gfed cba` */
  781. 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
  782. /* Allow all 8bit characters (assuming they are valid utf8) */
  783. 0x00000000,
  784. 0x00000000,
  785. 0x00000000,
  786. 0x00000000,
  787. };
  788. while (srclen && dstlen) {
  789. if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  790. if (dstlen >= 4) {
  791. *d++ = '\\';
  792. *d++ = 'x';
  793. *d++ = hexdigests[*src >> 4];
  794. *d++ = hexdigests[*src & 0xf];
  795. src++;
  796. dstlen -= 4;
  797. }
  798. else {
  799. /* Overflow */
  800. break;
  801. }
  802. } else {
  803. *d++ = *src++;
  804. dstlen --;
  805. }
  806. srclen--;
  807. }
  808. return d;
  809. }
  810. gsize
  811. rspamd_log_line_need_escape (const guchar *src, gsize srclen)
  812. {
  813. static guint32 escape[] = {
  814. 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
  815. /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
  816. 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0100 */
  817. /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
  818. 0x00000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */
  819. /* ~}| {zyx wvut srqp onml kjih gfed cba` */
  820. 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
  821. /* Allow all 8bit characters (assuming they are valid utf8) */
  822. 0x00000000,
  823. 0x00000000,
  824. 0x00000000,
  825. 0x00000000,
  826. };
  827. gsize n = 0;
  828. while (srclen) {
  829. if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
  830. n++;
  831. }
  832. src ++;
  833. srclen --;
  834. }
  835. return n;
  836. }
  837. const gchar *
  838. rspamd_get_log_severity_string (gint level_flags)
  839. {
  840. unsigned int bitnum;
  841. static const char *level_strs[G_LOG_LEVEL_USER_SHIFT] = {
  842. "", /* G_LOG_FLAG_RECURSION */
  843. "", /* G_LOG_FLAG_FATAL */
  844. "crit",
  845. "error",
  846. "warn",
  847. "notice",
  848. "info",
  849. "debug"
  850. };
  851. level_flags &= ((1u << G_LOG_LEVEL_USER_SHIFT) - 1u) & ~(G_LOG_FLAG_RECURSION|G_LOG_FLAG_FATAL);
  852. #ifdef __GNUC__
  853. /* We assume gcc >= 3 and clang >= 5 anyway */
  854. bitnum = __builtin_ffs (level_flags) - 1;
  855. #else
  856. bitnum = ffs (level_flags) - 1;
  857. #endif
  858. return level_strs[bitnum];
  859. }