suricata
util-debug.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22 *
23 * Debug utility functions
24 */
25
26#include "suricata-common.h"
27#include "util-debug.h"
28
29#include "output.h"
30
31#include "suricata.h"
32
33#include "util-conf.h"
34#include "util-enum.h"
35#include "util-path.h"
36#include "util-syslog.h"
37#include "util-time.h"
38
39// clang-format off
40/* holds the string-enum mapping for the enums held in the table SCLogLevel */
42 { "Not set", SC_LOG_NOTSET },
43 { "None", SC_LOG_NONE },
44 { "Error", SC_LOG_ERROR },
45 { "Warning", SC_LOG_WARNING },
46 { "Notice", SC_LOG_NOTICE },
47 { "Info", SC_LOG_INFO },
48 { "Perf", SC_LOG_PERF },
49 { "Config", SC_LOG_CONFIG },
50 { "Debug", SC_LOG_DEBUG },
51 { NULL, -1 }
52};
53
55 { "Not set", SC_LOG_NOTSET },
56 { "None", SC_LOG_NONE },
57 { "E", SC_LOG_ERROR },
58 { "W", SC_LOG_WARNING },
59 { "i", SC_LOG_NOTICE },
60 { "i", SC_LOG_INFO },
61 { "i", SC_LOG_PERF },
62 { "i", SC_LOG_CONFIG },
63 { "d", SC_LOG_DEBUG },
64 { NULL, -1 }
65};
66
67/* holds the string-enum mapping for the enums held in the table SCLogOPIface */
69 { "Console", SC_LOG_OP_IFACE_CONSOLE },
70 { "File", SC_LOG_OP_IFACE_FILE },
71 { "Syslog", SC_LOG_OP_IFACE_SYSLOG },
72 { NULL, -1 }
73};
74// clang-format on
75
76#if defined (OS_WIN32)
77/**
78 * \brief Used for synchronous output on WIN32
79 */
80static SCMutex sc_log_stream_lock;
81#endif /* OS_WIN32 */
82
83/**
84 * \brief Transform the module name into display module name for logging
85 */
86static const char *SCTransformModule(const char *module_name, int *dn_len);
87
88/**
89 * \brief Holds the config state for the logging module
90 */
91static SCLogConfig *sc_log_config = NULL;
92
93/**
94 * \brief Returns the full path given a file and configured log dir
95 */
96static char *SCLogGetLogFilename(const char *);
97
98/**
99 * \brief Holds the global log level. Is the same as sc_log_config->log_level
100 */
102
103/**
104 * \brief Used to indicate whether the logging module has been init or not
105 */
107
108/**
109 * \brief Used to indicate whether the logging module has been cleaned or not
110 */
112
113/**
114 * \brief Maps the SC logging level to the syslog logging level
115 *
116 * \param The SC logging level that has to be mapped to the syslog_log_level
117 *
118 * \retval syslog_log_level The mapped syslog_api_log_level, for the logging
119 * module api's internal log_level
120 */
121static inline int SCLogMapLogLevelToSyslogLevel(int log_level)
122{
123 int syslog_log_level = 0;
124
125 switch (log_level) {
126 case SC_LOG_ERROR:
127 syslog_log_level = LOG_ERR;
128 break;
129 case SC_LOG_WARNING:
130 syslog_log_level = LOG_WARNING;
131 break;
132 case SC_LOG_NOTICE:
133 syslog_log_level = LOG_NOTICE;
134 break;
135 case SC_LOG_INFO:
136 syslog_log_level = LOG_INFO;
137 break;
138 case SC_LOG_CONFIG:
139 case SC_LOG_DEBUG:
140 case SC_LOG_PERF:
141 syslog_log_level = LOG_DEBUG;
142 break;
143 default:
144 syslog_log_level = LOG_EMERG;
145 break;
146 }
147
148 return syslog_log_level;
149}
150
151/**
152 * \brief Output function that logs a character string out to a file descriptor
153 *
154 * \param fd Pointer to the file descriptor
155 * \param msg Pointer to the character string that should be logged
156 */
157static inline void SCLogPrintToStream(FILE *fd, char *msg)
158{
159 /* Would only happen if the log file failed to re-open during rotation. */
160 if (fd == NULL) {
161 return;
162 }
163
164#if defined (OS_WIN32)
165 SCMutexLock(&sc_log_stream_lock);
166#endif /* OS_WIN32 */
167
168 if (fprintf(fd, "%s\n", msg) < 0)
169 printf("Error writing to stream using fprintf\n");
170
171 fflush(fd);
172
173#if defined (OS_WIN32)
174 SCMutexUnlock(&sc_log_stream_lock);
175#endif /* OS_WIN32 */
176}
177
178/**
179 * \brief Output function that logs a character string through the syslog iface
180 *
181 * \param syslog_log_level Holds the syslog_log_level that the message should be
182 * logged as
183 * \param msg Pointer to the char string, that should be logged
184 *
185 * \todo syslog is thread-safe according to POSIX manual and glibc code, but we
186 * we will have to look into non POSIX compliant boxes like freeBSD
187 */
188static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg)
189{
190 //static struct syslog_data data = SYSLOG_DATA_INIT;
191 //syslog_r(syslog_log_level, NULL, "%s", msg);
192
193 syslog(syslog_log_level, "%s", msg);
194}
195
196/**
197 */
198static int SCLogMessageJSON(SCTime_t tval, char *buffer, size_t buffer_size, SCLogLevel log_level,
199 const char *file, unsigned line, const char *function, const char *module,
200 const char *message)
201{
202 SCJsonBuilder *js = SCJbNewObject();
203 if (unlikely(js == NULL))
204 goto error;
205
206 char timebuf[64];
207 CreateIsoTimeString(tval, timebuf, sizeof(timebuf));
208 SCJbSetString(js, "timestamp", timebuf);
209
210 const char *s = SCMapEnumValueToName(log_level, sc_log_level_map);
211 if (s != NULL) {
212 SCJbSetString(js, "log_level", s);
213 } else {
214 JB_SET_STRING(js, "log_level", "INVALID");
215 }
216
217 JB_SET_STRING(js, "event_type", "engine");
218 SCJbOpenObject(js, "engine");
219
220 if (message)
221 SCJbSetString(js, "message", message);
222
223 if (t_thread_name[0] != '\0') {
224 SCJbSetString(js, "thread_name", t_thread_name);
225 }
226
227 if (module) {
228 /* Determine how much of module name to display */
229 int dn_len = 0;
230 const char *dn_name;
231 dn_name = SCTransformModule(module, &dn_len);
232 SCJbSetString(js, "module", dn_name);
233 }
234
235 if (log_level >= SC_LOG_DEBUG) {
236 if (function)
237 SCJbSetString(js, "function", function);
238
239 if (file)
240 SCJbSetString(js, "file", file);
241
242 if (line > 0)
243 SCJbSetUint(js, "line", line);
244 }
245 SCJbClose(js); // engine
246
247 SCJbClose(js);
248 memcpy(buffer, SCJbPtr(js), MIN(buffer_size, SCJbLen(js)));
249
250 SCJbFree(js);
251
252 return 0;
253
254error:
255 return -1;
256}
257
258static const int transform_max_segs = 2; /* The maximum segment count to display */
259/*
260 * \brief Return a display name for the given module name for logging.
261 *
262 * The transformation is dependent upon the source code module names
263 * that use the dash character to separate incremental refinements of
264 * the subsystem.
265 *
266 * The transformation uses the local constant "transform_max_segs" to determine
267 * how many segments to display; the transformed name will never consist
268 * of more than this many segments.
269 *
270 * E.g., "detect-http-content-len" ==> "detect-http" when the max is 2
271 *
272 * \param module_name The source code module name to be transformed.
273 * \param dn_len The number of characters in the display name to print.
274 *
275 * \retval Pointer to the display name
276 */
277static const char *SCTransformModule(const char *module_name, int *dn_len)
278{
279 /*
280 * special case for source code module names beginning with:
281 * Prefixes skipped
282 * tm-*
283 * util-*
284 * source-*
285 * No transformation
286 * app-layer-*
287 */
288 if (strncmp("tm-", module_name, 3) == 0) {
289 *dn_len = (int)strlen(module_name) - 3;
290 return module_name + 3;
291 } else if (strncmp("util-", module_name, 5) == 0) {
292 *dn_len = (int)strlen(module_name) - 5;
293 return module_name + 5;
294 } else if (strncmp("source-pcap-file", module_name, 16) == 0) {
295 *dn_len = (int)strlen("pcap");
296 return "pcap";
297 } else if (strncmp("source-", module_name, 7) == 0) {
298 *dn_len = (int)strlen(module_name) - 7;
299 return module_name + 7;
300 } else if (strncmp("runmode-", module_name, 8) == 0) {
301 *dn_len = (int)strlen(module_name) - 8;
302 return module_name + 8;
303 } else if (strncmp("app-layer-", module_name, 10) == 0) {
304 *dn_len = (int)strlen(module_name);
305 return module_name;
306 } else if (strncmp("detect-engine", module_name, 13) == 0) {
307 *dn_len = (int)strlen("detect");
308 return "detect";
309 }
310
311 int seg_cnt = 0;
312
313 char *last;
314 char *w = (char *)module_name;
315 while (w && (w = strchr(w, '-')) != NULL && seg_cnt < transform_max_segs) {
316 seg_cnt++;
317 last = w;
318 w++; /* skip past '-' */
319 }
320
321 if (seg_cnt < transform_max_segs)
322 *dn_len = (int)strlen(module_name);
323 else
324 *dn_len = (int)(last - module_name);
325
326 return module_name;
327}
328
329/**
330 * \brief Adds the global log_format to the outgoing buffer
331 *
332 * \param log_level log_level of the message that has to be logged
333 * \param msg Buffer containing the outgoing message
334 * \param file File_name from where the message originated
335 * \param function Function_name from where the message originated
336 * \param line Line_no from where the messaged originated
337 *
338 * \retval 0 on success; else a negative value on error
339 */
340static SCError SCLogMessageGetBuffer(SCTime_t tval, bool color, SCLogOPType type, char *buffer,
341 size_t buffer_size, const char *log_format, const SCLogLevel log_level, const char *file,
342 const unsigned int line, const char *function, const char *module, const char *message)
343{
345 return SCLogMessageJSON(
346 tval, buffer, buffer_size, log_level, file, line, function, module, message);
347
348 char *temp = buffer;
349 const char *s = NULL;
350 struct tm *tms = NULL;
351
352 const char *redb = "";
353 const char *red = "";
354 const char *yellowb = "";
355 const char *yellow = "";
356 const char *green = "";
357 const char *blue = "";
358 const char *reset = "";
359 if (color) {
360 redb = "\x1b[1;31m";
361 red = "\x1b[31m";
362 yellowb = "\x1b[1;33m";
363 yellow = "\x1b[33m";
364 green = "\x1b[32m";
365 blue = "\x1b[34m";
366 reset = "\x1b[0m";
367 }
368 /* no of characters_written(cw) by snprintf */
369 int cw = 0;
370
372
373 /* make a copy of the format string as it will be modified below */
374 const int add_M = strstr(log_format, "%M") == NULL;
375 char local_format[strlen(log_format) + add_M * 2 + 1];
376 strlcpy(local_format, log_format, sizeof(local_format));
377 if (add_M)
378 strlcat(local_format, "%M", sizeof(local_format));
379 char *temp_fmt = local_format;
380 char *substr = temp_fmt;
381 struct tm local_tm;
382
383 while ((temp_fmt = strchr(temp_fmt, SC_LOG_FMT_PREFIX))) {
384 if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
385 return 0;
386 }
387 switch(temp_fmt[1]) {
388 case SC_LOG_FMT_TIME:
389 temp_fmt[0] = '\0';
390
391 tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
392
393 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
394 "%s%s%04d-%02d-%02d %02d:%02d:%02d%s", substr, green, tms->tm_year + 1900,
395 tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec,
396 reset);
397 if (cw < 0)
398 return -1;
399 temp += cw;
400 temp_fmt++;
401 substr = temp_fmt;
402 substr++;
403 break;
404
406 temp_fmt[0] = '\0';
407
408 tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
409
410 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
411 "%s%s%d/%d/%04d -- %02d:%02d:%02d%s",
412 substr, green, tms->tm_mday, tms->tm_mon + 1,
413 tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
414 tms->tm_sec, reset);
415 if (cw < 0)
416 return -1;
417 temp += cw;
418 temp_fmt++;
419 substr = temp_fmt;
420 substr++;
421 break;
422
423 case SC_LOG_FMT_PID:
424 temp_fmt[0] = '\0';
425 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
426 "%s%s%u%s", substr, yellow, getpid(), reset);
427 if (cw < 0)
428 return -1;
429 temp += cw;
430 temp_fmt++;
431 substr = temp_fmt;
432 substr++;
433 break;
434
435 case SC_LOG_FMT_TID:
436 temp_fmt[0] = '\0';
437 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
438 "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset);
439 if (cw < 0)
440 return -1;
441 temp += cw;
442 temp_fmt++;
443 substr = temp_fmt;
444 substr++;
445 break;
446
448 case SC_LOG_FMT_TM:
449 temp_fmt[0] = '\0';
450 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
451 yellow, t_thread_name, reset);
452 if (cw < 0)
453 return -1;
454 temp += cw;
455 temp_fmt++;
456 substr = temp_fmt;
457 substr++;
458 break;
459
461 temp_fmt[0] = '\0';
463 if (s != NULL) {
464 if (log_level <= SC_LOG_ERROR)
465 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
466 "%s%s%s%s", substr, redb, s, reset);
467 else if (log_level == SC_LOG_WARNING)
468 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
469 "%s%s%s%s", substr, red, s, reset);
470 else if (log_level == SC_LOG_NOTICE)
471 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
472 "%s%s%s%s", substr, yellowb, s, reset);
473 else
474 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
475 substr, yellow, s, reset);
476 } else {
477 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr,
478 "INVALID");
479 }
480 if (cw < 0)
481 return -1;
482 temp += cw;
483 temp_fmt++;
484 substr = temp_fmt;
485 substr++;
486 break;
487
489 temp_fmt[0] = '\0';
491 if (s != NULL) {
492 if (log_level <= SC_LOG_ERROR)
493 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
494 substr, redb, s, reset);
495 else if (log_level == SC_LOG_WARNING)
496 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
497 substr, red, s, reset);
498 else if (log_level == SC_LOG_NOTICE)
499 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
500 substr, yellowb, s, reset);
501 else
502 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
503 "%s%s%s%s", substr, yellow, s, reset);
504 } else {
505 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
506 "%s%s", substr, "INVALID");
507 }
508 if (cw < 0)
509 return -1;
510 temp += cw;
511 temp_fmt++;
512 substr = temp_fmt;
513 substr++;
514 break;
515
517 temp_fmt[0] = '\0';
518 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
519 "%s%s%s%s", substr, blue, file, reset);
520 if (cw < 0)
521 return -1;
522 temp += cw;
523 temp_fmt++;
524 substr = temp_fmt;
525 substr++;
526 break;
527
528 case SC_LOG_FMT_LINE:
529 temp_fmt[0] = '\0';
530 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
531 "%s%s%u%s", substr, green, line, reset);
532 if (cw < 0)
533 return -1;
534 temp += cw;
535 temp_fmt++;
536 substr = temp_fmt;
537 substr++;
538 break;
539
541 temp_fmt[0] = '\0';
542
543 /* Determine how much of module name to display */
544 int dn_len = 0;
545 const char *dn_name = "unknown";
546 if (module) {
547 dn_name = SCTransformModule(module, &dn_len);
548 }
549
550 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
551 green, dn_name, reset);
552 if (cw < 0)
553 return -1;
554 temp += cw;
555 temp_fmt++;
556 substr = temp_fmt;
557 substr++;
558 break;
559
561 temp_fmt[0] = '\0';
562 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
563 "%s%s%s%s", substr, green, function, reset);
564 if (cw < 0)
565 return -1;
566 temp += cw;
567 temp_fmt++;
568 substr = temp_fmt;
569 substr++;
570 break;
571
572 case SC_LOG_FMT_MESSAGE: {
573 temp_fmt[0] = '\0';
574 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
575 if (cw < 0) {
576 return -1;
577 }
578 temp += cw;
579 if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
580 return 0;
581 }
582 const char *hi = "";
583 if (log_level <= SC_LOG_ERROR)
584 hi = red;
585 else if (log_level <= SC_LOG_NOTICE)
586 hi = yellow;
587 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message,
588 reset);
589 if (cw < 0) {
590 return -1;
591 }
592 temp += cw;
593 if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
594 return 0;
595 }
596 temp_fmt++;
597 substr = temp_fmt;
598 substr++;
599 break;
600 }
601 }
602 temp_fmt++;
603 }
604 if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
605 return 0;
606 }
607 cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
608 if (cw < 0) {
609 return -1;
610 }
611 if (sc_log_config->op_filter_regex != NULL) {
612 if (pcre2_match(sc_log_config->op_filter_regex, (PCRE2_SPTR8)buffer, strlen(buffer), 0, 0,
613 sc_log_config->op_filter_regex_match, NULL) < 0) {
614 return -1; // bit hacky, but just return !0
615 }
616 }
617
618 return 0;
619}
620
621/** \internal
622 * \brief try to reopen file
623 * \note no error reporting here, as we're called by SCLogMessage
624 * \retval status 0 ok, -1 error */
625static int SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx)
626{
627 if (op_iface_ctx->file == NULL) {
628 return 0;
629 }
630
631 if (op_iface_ctx->file_d != NULL) {
632 fclose(op_iface_ctx->file_d);
633 }
634 op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a");
635 if (op_iface_ctx->file_d == NULL) {
636 return -1;
637 }
638 return 0;
639}
640
641/**
642 * \brief Adds the global log_format to the outgoing buffer
643 *
644 * \param log_level log_level of the message that has to be logged
645 * \param msg Buffer containing the outgoing message
646 * \param file File_name from where the message originated
647 * \param function Function_name from where the message originated
648 * \param line Line_no from where the messaged originated
649 *
650 * \retval SC_OK on success; else an error code
651 */
652SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line,
653 const char *function, const char *module, const char *message)
654{
655 char buffer[SC_LOG_MAX_LOG_MSG_LEN] = "";
656 SCLogOPIfaceCtx *op_iface_ctx = NULL;
657
658 if (sc_log_module_initialized != 1) {
659 printf("Logging module not initialized. Call SCLogInitLogModule() "
660 "first before using the debug API\n");
661 return SC_OK;
662 }
663
664 /* get ts here so we log the same ts to each output */
665 struct timeval tval;
666 gettimeofday(&tval, NULL);
668
669 op_iface_ctx = sc_log_config->op_ifaces;
670 while (op_iface_ctx != NULL) {
671 if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) {
672 op_iface_ctx = op_iface_ctx->next;
673 continue;
674 }
675
676 switch (op_iface_ctx->iface) {
678 if (SCLogMessageGetBuffer(ts, op_iface_ctx->use_color, op_iface_ctx->type, buffer,
679 sizeof(buffer),
680 op_iface_ctx->log_format ? op_iface_ctx->log_format
681 : sc_log_config->log_format,
682 log_level, file, line, function, module, message) == 0) {
683 SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer);
684 }
685 break;
687 if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
688 op_iface_ctx->log_format ? op_iface_ctx->log_format
689 : sc_log_config->log_format,
690 log_level, file, line, function, module, message) == 0) {
691 int r = 0;
692 SCMutexLock(&op_iface_ctx->fp_mutex);
693 if (op_iface_ctx->rotation_flag) {
694 r = SCLogReopen(op_iface_ctx);
695 op_iface_ctx->rotation_flag = 0;
696 }
697 SCLogPrintToStream(op_iface_ctx->file_d, buffer);
698 SCMutexUnlock(&op_iface_ctx->fp_mutex);
699
700 /* report error outside of lock to avoid recursion */
701 if (r == -1) {
702 SCLogError("re-opening file \"%s\" failed: %s", op_iface_ctx->file,
703 strerror(errno));
704 }
705 }
706 break;
708 if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
709 op_iface_ctx->log_format ? op_iface_ctx->log_format
710 : sc_log_config->log_format,
711 log_level, file, line, function, module, message) == 0) {
712 SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer);
713 }
714 break;
715 default:
716 break;
717 }
718 op_iface_ctx = op_iface_ctx->next;
719 }
720 return SC_OK;
721}
722
723void SCLog(int x, const char *file, const char *func, const int line, const char *module,
724 const char *fmt, ...)
725{
726 if (sc_log_global_log_level >= x &&
728 SCLogMatchFGFilterWL(file, func, line) == 1 ||
729 SCLogMatchFGFilterBL(file, func, line) == 1) &&
731 SCLogMatchFDFilter(func) == 1))
732 {
733 char msg[SC_LOG_MAX_LOG_MSG_LEN];
734 va_list ap;
735 va_start(ap, fmt);
736 vsnprintf(msg, sizeof(msg), fmt, ap);
737 va_end(ap);
738 SCLogMessage(x, file, line, func, module, msg);
739 }
740}
741
742void SCLogErr(int x, const char *file, const char *func, const int line, const char *module,
743 const char *fmt, ...)
744{
745 if (sc_log_global_log_level >= x &&
747 SCLogMatchFGFilterWL(file, func, line) == 1 ||
748 SCLogMatchFGFilterBL(file, func, line) == 1) &&
750 SCLogMatchFDFilter(func) == 1))
751 {
752 char msg[SC_LOG_MAX_LOG_MSG_LEN];
753 va_list ap;
754 va_start(ap, fmt);
755 vsnprintf(msg, sizeof(msg), fmt, ap);
756 va_end(ap);
757 SCLogMessage(x, file, line, func, module, msg);
758 }
759}
760
761/**
762 * \brief Returns whether debug messages are enabled to be logged or not
763 *
764 * \retval 1 if debug messages are enabled to be logged
765 * \retval 0 if debug messages are not enabled to be logged
766 */
768{
769#ifdef DEBUG
771 return 1;
772 else
773 return 0;
774#else
775 return 0;
776#endif
777}
778
779/**
780 * \brief Allocates an output buffer for an output interface. Used when we
781 * want the op_interface log_format to override the global_log_format.
782 * Currently not used.
783 *
784 * \retval buffer Pointer to the newly created output_buffer
785 */
787{
788 SCLogOPBuffer *buffer = NULL;
789
790 if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt *
791 sizeof(SCLogOPBuffer))) == NULL) {
792 FatalError("Fatal error encountered in SCLogAllocLogOPBuffer. Exiting...");
793 }
794
795 SCLogOPIfaceCtx *op_iface_ctx = sc_log_config->op_ifaces;
796 for (int i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) {
797 buffer[i].log_format = op_iface_ctx->log_format;
798 buffer[i].temp = buffer[i].msg;
799 }
800
801 return buffer;
802}
803
804/*----------------------The logging module initialization code--------------- */
805
806/**
807 * \brief Returns a new output_interface_context
808 *
809 * \retval iface_ctx Pointer to a newly allocated output_interface_context
810 * \initonly
811 */
812static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx(void)
813{
814 SCLogOPIfaceCtx *iface_ctx = NULL;
815
816 if ((iface_ctx = SCCalloc(1, sizeof(SCLogOPIfaceCtx))) == NULL) {
817 FatalError("Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting...");
818 }
819
820 return iface_ctx;
821}
822
823/**
824 * \brief Initializes the file output interface
825 *
826 * \param file Path to the file used for logging purposes
827 * \param log_format Pointer to the log_format for this op interface, that
828 * overrides the global_log_format
829 * \param log_level Override of the global_log_level by this interface
830 *
831 * \retval iface_ctx Pointer to the file output interface context created
832 * \initonly
833 */
834static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, uint32_t userid,
835 uint32_t groupid, const char *log_format, int log_level, SCLogOPType type)
836{
837 SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
838 if (iface_ctx == NULL) {
839 FatalError("Fatal error encountered in SCLogInitFileOPIface. Exiting...");
840 }
841
842 if (file == NULL) {
843 goto error;
844 }
845
846 iface_ctx->iface = SC_LOG_OP_IFACE_FILE;
847 iface_ctx->type = type;
848
849 if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) {
850 SCLogWarning("error opening file %s: %s", file, strerror(errno));
851 goto error;
852 }
853
854#ifndef OS_WIN32
855 if (userid != 0 || groupid != 0) {
856 if (fchown(fileno(iface_ctx->file_d), userid, groupid) == -1) {
857 SCLogWarning("Failed to change ownership of file %s: %s", file, strerror(errno));
858 }
859 }
860#endif
861
862 if ((iface_ctx->file = SCStrdup(file)) == NULL) {
863 goto error;
864 }
865
866 if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
867 goto error;
868 }
869
870 SCMutexInit(&iface_ctx->fp_mutex, NULL);
872
873 iface_ctx->log_level = log_level;
874
875 return iface_ctx;
876
877error:
878 if (iface_ctx->file != NULL) {
879 SCFree((char *)iface_ctx->file);
880 iface_ctx->file = NULL;
881 }
882 if (iface_ctx->log_format != NULL) {
883 SCFree((char *)iface_ctx->log_format);
884 iface_ctx->log_format = NULL;
885 }
886 if (iface_ctx->file_d != NULL) {
887 fclose(iface_ctx->file_d);
888 iface_ctx->file_d = NULL;
889 }
890 SCFree(iface_ctx);
891 return NULL;
892}
893
894/**
895 * \brief Initializes the console output interface and deals with possible
896 * env var overrides.
897 *
898 * \param log_format Pointer to the log_format for this op interface, that
899 * overrides the global_log_format
900 * \param log_level Override of the global_log_level by this interface
901 *
902 * \retval iface_ctx Pointer to the console output interface context created
903 * \initonly
904 */
905static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
906 SCLogLevel log_level, SCLogOPType type)
907{
908 SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
909
910 if (iface_ctx == NULL) {
911 FatalError("Fatal error encountered in SCLogInitConsoleOPIface. Exiting...");
912 }
913
914 iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE;
915 iface_ctx->type = type;
916
917 /* console log format is overridden by envvars */
918 const char *tmp_log_format = log_format;
919 const char *s = getenv(SC_LOG_ENV_LOG_FORMAT);
920 if (s != NULL) {
921#if 0
922 printf("Overriding setting for \"console.format\" because of env "
923 "var SC_LOG_FORMAT=\"%s\".\n", s);
924#endif
925 tmp_log_format = s;
926 }
927
928 if (tmp_log_format != NULL &&
929 (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) {
930 printf("Error allocating memory\n");
931 exit(EXIT_FAILURE);
932 }
933
934 /* console log level is overridden by envvars */
935 SCLogLevel tmp_log_level = log_level;
936 s = getenv(SC_LOG_ENV_LOG_LEVEL);
937 if (s != NULL) {
939 if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) {
940#if 0
941 printf("Overriding setting for \"console.level\" because of env "
942 "var SC_LOG_LEVEL=\"%s\".\n", s);
943#endif
944 tmp_log_level = l;
945 }
946 }
947 iface_ctx->log_level = tmp_log_level;
948
949#ifndef OS_WIN32
950 if (isatty(fileno(stdout)) && isatty(fileno(stderr))) {
951 iface_ctx->use_color = true;
952 }
953#endif
954
955 return iface_ctx;
956}
957
958/**
959 * \brief Initializes the syslog output interface
960 *
961 * \param facility The facility code for syslog
962 * \param log_format Pointer to the log_format for this op interface, that
963 * overrides the global_log_format
964 * \param log_level Override of the global_log_level by this interface
965 *
966 * \retval iface_ctx Pointer to the syslog output interface context created
967 */
968static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility,
969 const char *log_format,
970 SCLogLevel log_level,
972{
973 SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
974
975 if ( iface_ctx == NULL) {
976 FatalError("Fatal error encountered in SCLogInitSyslogOPIface. Exiting...");
977 }
978
979 iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG;
980 iface_ctx->type = type;
981
982 if (facility == -1)
984 iface_ctx->facility = facility;
985
986 if (log_format != NULL &&
987 (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
988 printf("Error allocating memory\n");
989 exit(EXIT_FAILURE);
990 }
991
992 iface_ctx->log_level = log_level;
993
994 openlog(NULL, LOG_NDELAY, iface_ctx->facility);
995
996 return iface_ctx;
997}
998
999/**
1000 * \brief Frees the output_interface context supplied as an argument
1001 *
1002 * \param iface_ctx Pointer to the op_interface_context to be freed
1003 */
1004static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx)
1005{
1006 SCLogOPIfaceCtx *temp = NULL;
1007
1008 while (iface_ctx != NULL) {
1009 temp = iface_ctx;
1010
1011 if (iface_ctx->file_d != NULL) {
1012 fclose(iface_ctx->file_d);
1013 SCMutexDestroy(&iface_ctx->fp_mutex);
1014 }
1015
1016 if (iface_ctx->file != NULL)
1017 SCFree((void *)iface_ctx->file);
1018
1019 if (iface_ctx->log_format != NULL)
1020 SCFree((void *)iface_ctx->log_format);
1021
1022 if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) {
1023 closelog();
1024 }
1025
1026 iface_ctx = iface_ctx->next;
1027
1028 SCFree(temp);
1029 }
1030}
1031
1032/**
1033 * \brief Internal function used to set the logging module global_log_level
1034 * during the initialization phase
1035 *
1036 * \param sc_lid The initialization data supplied.
1037 * \param sc_lc The logging module context which has to be updated.
1038 */
1039static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1040{
1041 SCLogLevel log_level = SC_LOG_NOTSET;
1042 const char *s = NULL;
1043
1044 /* envvar overrides config */
1045 s = getenv(SC_LOG_ENV_LOG_LEVEL);
1046 if (s != NULL) {
1047 log_level = SCMapEnumNameToValue(s, sc_log_level_map);
1048 } else if (sc_lid != NULL) {
1049 log_level = sc_lid->global_log_level;
1050 }
1051
1052 /* deal with the global_log_level to be used */
1053 if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX)
1054 sc_lc->log_level = log_level;
1055 else {
1057#ifndef UNITTESTS
1058 if (sc_lid != NULL) {
1059 printf("Warning: Invalid/No global_log_level assigned by user. Falling "
1060 "back on the default_log_level \"%s\"\n",
1062 }
1063#endif
1064 }
1065
1066 /* we also set it to a global var, as it is easier to access it */
1068}
1069
1074
1075static inline const char *SCLogGetDefaultLogFormat(const SCLogLevel lvl)
1076{
1077 const char *prog_ver = GetProgramVersion();
1078 if (strstr(prog_ver, "RELEASE") != NULL) {
1079 if (lvl <= SC_LOG_NOTICE)
1081 else if (lvl <= SC_LOG_INFO)
1083 else if (lvl <= SC_LOG_CONFIG)
1085 }
1087}
1088
1089/**
1090 * \brief Internal function used to set the logging module global_log_format
1091 * during the initialization phase
1092 *
1093 * \param sc_lid The initialization data supplied.
1094 * \param sc_lc The logging module context which has to be updated.
1095 */
1096static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1097{
1098 const char *format = NULL;
1099
1100 /* envvar overrides config */
1101 format = getenv(SC_LOG_ENV_LOG_FORMAT);
1102 if (format == NULL) {
1103 if (sc_lid != NULL) {
1104 format = sc_lid->global_log_format;
1105 }
1106 }
1107
1108 /* deal with the global log format to be used */
1109 if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) {
1110 format = SCLogGetDefaultLogFormat(sc_lc->log_level);
1111#ifndef UNITTESTS
1112 if (sc_lid != NULL) {
1113 printf("Warning: Invalid/No global_log_format supplied by user or format "
1114 "length exceeded limit of \"%d\" characters. Falling back on "
1115 "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN,
1116 format);
1117 }
1118#endif
1119 }
1120
1121 if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) {
1122 printf("Error allocating memory\n");
1123 exit(EXIT_FAILURE);
1124 }
1125}
1126
1127/**
1128 * \brief Internal function used to set the logging module global_op_ifaces
1129 * during the initialization phase
1130 *
1131 * \param sc_lid The initialization data supplied.
1132 * \param sc_lc The logging module context which has to be updated.
1133 */
1134static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1135{
1136 SCLogOPIfaceCtx *op_ifaces_ctx = NULL;
1137 int op_iface = 0;
1138 const char *s = NULL;
1139
1140 if (sc_lid != NULL && sc_lid->op_ifaces != NULL) {
1141 sc_lc->op_ifaces = sc_lid->op_ifaces;
1142 sc_lid->op_ifaces = NULL;
1143 sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt;
1144 } else {
1145 s = getenv(SC_LOG_ENV_LOG_OP_IFACE);
1146 if (s != NULL) {
1148
1149 if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) {
1150 op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1151#ifndef UNITTESTS
1152 printf("Warning: Invalid output interface supplied by user. "
1153 "Falling back on default_output_interface \"%s\"\n",
1155#endif
1156 }
1157 }
1158 else {
1159 op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1160#ifndef UNITTESTS
1161 if (sc_lid != NULL) {
1162 printf("Warning: Output_interface not supplied by user. Falling "
1163 "back on default_output_interface \"%s\"\n",
1165 }
1166#endif
1167 }
1168
1169 switch (op_iface) {
1171 op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0);
1172 break;
1174 s = getenv(SC_LOG_ENV_LOG_FILE);
1175 if (s == NULL) {
1176 char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
1177 if (str != NULL) {
1178 op_ifaces_ctx = SCLogInitFileOPIface(str, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
1179 SCFree(str);
1180 }
1181 } else {
1182 op_ifaces_ctx = SCLogInitFileOPIface(s, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
1183 }
1184 break;
1186 s = getenv(SC_LOG_ENV_LOG_FACILITY);
1187 if (s == NULL)
1189
1190 op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0);
1191 break;
1192 }
1193 sc_lc->op_ifaces = op_ifaces_ctx;
1194 sc_lc->op_ifaces_cnt++;
1195 }
1196}
1197
1198/**
1199 * \brief Internal function used to set the logging module op_filter
1200 * during the initialization phase
1201 *
1202 * \param sc_lid The initialization data supplied.
1203 * \param sc_lc The logging module context which has to be updated.
1204 */
1205static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1206{
1207 const char *filter = NULL;
1208
1209 int opts = 0;
1210 int en;
1211 PCRE2_SIZE eo = 0;
1212
1213 /* envvar overrides */
1214 filter = getenv(SC_LOG_ENV_LOG_OP_FILTER);
1215 if (filter == NULL) {
1216 if (sc_lid != NULL) {
1217 filter = sc_lid->op_filter;
1218 }
1219 }
1220
1221 if (filter != NULL && strcmp(filter, "") != 0) {
1222 sc_lc->op_filter = SCStrdup(filter);
1223 if (sc_lc->op_filter == NULL) {
1224 printf("pcre filter alloc failed\n");
1225 return;
1226 }
1227 sc_lc->op_filter_regex =
1228 pcre2_compile((PCRE2_SPTR8)filter, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
1229 if (sc_lc->op_filter_regex == NULL) {
1230 SCFree(sc_lc->op_filter);
1231 PCRE2_UCHAR errbuffer[256];
1232 pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
1233 printf("pcre2 compile of \"%s\" failed at offset %d : %s\n", filter, (int)eo,
1234 errbuffer);
1235 return;
1236 }
1237 sc_lc->op_filter_regex_match =
1238 pcre2_match_data_create_from_pattern(sc_lc->op_filter_regex, NULL);
1239 }
1240}
1241
1242/**
1243 * \brief Returns a pointer to a new SCLogInitData. This is a public interface
1244 * intended to be used after the logging parameters are read from the
1245 * conf file
1246 *
1247 * \retval sc_lid Pointer to the newly created SCLogInitData
1248 * \initonly
1249 */
1251{
1252 SCLogInitData *sc_lid = NULL;
1253
1254 if ((sc_lid = SCCalloc(1, sizeof(SCLogInitData))) == NULL)
1255 return NULL;
1256
1257 return sc_lid;
1258}
1259
1260#ifdef UNITTESTS
1261#ifndef OS_WIN32
1262/**
1263 * \brief Frees a SCLogInitData
1264 *
1265 * \param sc_lid Pointer to the SCLogInitData to be freed
1266 */
1267static void SCLogFreeLogInitData(SCLogInitData *sc_lid)
1268{
1269 if (sc_lid != NULL) {
1270 SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces);
1271 SCFree(sc_lid);
1272 }
1273}
1274#endif
1275#endif
1276
1277/**
1278 * \brief Frees the logging module context
1279 */
1280static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc)
1281{
1282 if (sc_lc != NULL) {
1283 if (sc_lc->startup_message != NULL)
1284 SCFree(sc_lc->startup_message);
1285 if (sc_lc->log_format != NULL)
1286 SCFree(sc_lc->log_format);
1287 if (sc_lc->op_filter != NULL)
1288 SCFree(sc_lc->op_filter);
1289
1290 if (sc_lc->op_filter_regex != NULL)
1291 pcre2_code_free(sc_lc->op_filter_regex);
1292 if (sc_lc->op_filter_regex_match)
1293 pcre2_match_data_free(sc_lc->op_filter_regex_match);
1294
1295 SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces);
1296 SCFree(sc_lc);
1297 }
1298}
1299
1300/**
1301 * \brief Appends an output_interface to the output_interface list sent in head
1302 *
1303 * \param iface_ctx Pointer to the output_interface that has to be added to head
1304 * \param head Pointer to the output_interface list
1305 */
1307{
1308 SCLogOPIfaceCtx *temp = NULL, *prev = NULL;
1309 SCLogOPIfaceCtx **head = &sc_lid->op_ifaces;
1310
1311 if (iface_ctx == NULL) {
1312#ifdef DEBUG
1313 printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n");
1314#endif
1315 return;
1316 }
1317
1318 temp = *head;
1319 while (temp != NULL) {
1320 prev = temp;
1321 temp = temp->next;
1322 }
1323
1324 if (prev == NULL)
1325 *head = iface_ctx;
1326 else
1327 prev->next = iface_ctx;
1328
1329 sc_lid->op_ifaces_cnt++;
1330}
1331
1332#ifdef UNITTESTS
1333#ifndef OS_WIN32
1334/**
1335 * \internal
1336 * \brief Creates a new output interface based on the arguments sent. The kind
1337 * of output interface to be created is decided by the iface_name arg.
1338 * If iface_name is "file", the arg argument will hold the filename to be
1339 * used for logging purposes. If iface_name is "syslog", the arg
1340 * argument holds the facility code. If iface_name is "console", arg is
1341 * NULL.
1342 *
1343 * \param iface_name Interface name. Can be "console", "file" or "syslog"
1344 * \param log_format Override for the global_log_format
1345 * \param log_level Override for the global_log_level
1346 * \param log_level Parameter required by a particular interface. Explained in
1347 * the function description
1348 *
1349 * \retval iface_ctx Pointer to the newly created output interface
1350 */
1351static SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(
1352 const char *iface_name, const char *log_format, int log_level, const char *arg)
1353{
1354 int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map);
1355
1356 if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) {
1357 printf("Warning: Supplied log_level_override for op_interface \"%s\" "
1358 "is invalid. Defaulting to not specifying an override\n",
1359 iface_name);
1360 log_level = SC_LOG_NOTSET;
1361 }
1362
1363 switch (iface) {
1365 return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1367 return SCLogInitFileOPIface(arg, 0, 0, log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1369 return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()),
1370 log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1371 default:
1372#ifdef DEBUG
1373 printf("Output Interface \"%s\" not supported by the logging module",
1374 iface_name);
1375#endif
1376 return NULL;
1377 }
1378}
1379#endif
1380#endif
1381
1382/**
1383 * \brief Initializes the logging module.
1384 *
1385 * \param sc_lid The initialization data for the logging module. If sc_lid is
1386 * NULL, we would stick to the default configuration for the
1387 * logging subsystem.
1388 * \initonly
1389 */
1391{
1392 /* De-initialize the logging context, if it has already init by the
1393 * environment variables at the start of the engine */
1395
1396#if defined (OS_WIN32)
1397 if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) {
1398 FatalError("Failed to initialize log mutex.");
1399 }
1400#endif /* OS_WIN32 */
1401
1402 /* sc_log_config is a global variable */
1403 if ((sc_log_config = SCCalloc(1, sizeof(SCLogConfig))) == NULL) {
1404 FatalError("Fatal error encountered in SCLogInitLogModule. Exiting...");
1405 }
1406
1407 SCLogSetLogLevel(sc_lid, sc_log_config);
1408 SCLogSetLogFormat(sc_lid, sc_log_config);
1409 SCLogSetOPIface(sc_lid, sc_log_config);
1410 SCLogSetOPFilter(sc_lid, sc_log_config);
1411
1414
1415 //SCOutputPrint(sc_did->startup_message);
1416
1417 SCSetRustLogLevel(sc_log_global_log_level);
1418}
1419
1420void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid)
1421{
1422 SCConfNode *outputs;
1423 SCLogInitData *sc_lid;
1424 int have_logging = 0;
1425 int max_level = 0;
1426 SCLogLevel min_level = 0;
1427
1428 /* If verbose logging was requested, set the minimum as
1429 * SC_LOG_NOTICE plus the extra verbosity. */
1430 if (verbose) {
1431 min_level = SC_LOG_NOTICE + verbose;
1432 }
1433
1434 outputs = SCConfGetNode("logging.outputs");
1435 if (outputs == NULL) {
1436 SCLogDebug("No logging.output configuration section found.");
1437 return;
1438 }
1439
1440 sc_lid = SCLogAllocLogInitData();
1441 if (sc_lid == NULL) {
1442 SCLogDebug("Could not allocate memory for log init data");
1443 return;
1444 }
1445
1446 /* Get default log level and format. */
1447 const char *default_log_level_s = NULL;
1448 if (SCConfGet("logging.default-log-level", &default_log_level_s) == 1) {
1449 SCLogLevel default_log_level =
1450 SCMapEnumNameToValue(default_log_level_s, sc_log_level_map);
1451 if (default_log_level == -1) {
1452 SCLogError("Invalid default log level: %s", default_log_level_s);
1453 exit(EXIT_FAILURE);
1454 }
1455 sc_lid->global_log_level = MAX(min_level, default_log_level);
1456 } else {
1457 sc_lid->global_log_level = MAX(min_level, SC_LOG_NOTICE);
1458 }
1459
1460 if (SCConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1)
1461 sc_lid->global_log_format = SCLogGetDefaultLogFormat(sc_lid->global_log_level);
1462
1463 (void)SCConfGet("logging.default-output-filter", &sc_lid->op_filter);
1464
1465 SCConfNode *seq_node, *output;
1466 TAILQ_FOREACH(seq_node, &outputs->head, next) {
1467 SCLogLevel level = sc_lid->global_log_level;
1468 SCLogOPIfaceCtx *op_iface_ctx = NULL;
1469 const char *format;
1470 const char *level_s;
1471
1472 output = SCConfNodeLookupChild(seq_node, seq_node->val);
1473 if (output == NULL)
1474 continue;
1475
1476 /* By default an output is enabled. */
1477 const char *enabled = SCConfNodeLookupChildValue(output, "enabled");
1478 if (enabled != NULL && SCConfValIsFalse(enabled))
1479 continue;
1480
1482 const char *type_s = SCConfNodeLookupChildValue(output, "type");
1483 if (type_s != NULL) {
1484 if (strcmp(type_s, "regular") == 0)
1486 else if (strcmp(type_s, "json") == 0) {
1488 }
1489 }
1490
1491 format = SCConfNodeLookupChildValue(output, "format");
1492
1493 level_s = SCConfNodeLookupChildValue(output, "level");
1494 if (level_s != NULL) {
1495 level = SCMapEnumNameToValue(level_s, sc_log_level_map);
1496 if (level == -1) {
1497 SCLogError("Invalid log level: %s", level_s);
1498 exit(EXIT_FAILURE);
1499 }
1500 max_level = MAX(max_level, level);
1501 }
1502
1503 /* Increase the level of extra verbosity was requested. */
1504 level = MAX(min_level, level);
1505
1506 if (strcmp(output->name, "console") == 0) {
1507 op_iface_ctx = SCLogInitConsoleOPIface(format, level, type);
1508 }
1509 else if (strcmp(output->name, "file") == 0) {
1510 if (format == NULL) {
1511 format = SC_LOG_DEF_FILE_FORMAT;
1512 }
1513
1514 const char *filename = SCConfNodeLookupChildValue(output, "filename");
1515 if (filename == NULL) {
1516 FatalError("Logging to file requires a filename");
1517 }
1518 char *path = NULL;
1519 if (!(PathIsAbsolute(filename))) {
1520 path = SCLogGetLogFilename(filename);
1521 } else {
1522 path = SCStrdup(filename);
1523 }
1524 if (path == NULL)
1525 FatalError("failed to setup output to file");
1526 have_logging = 1;
1527 op_iface_ctx = SCLogInitFileOPIface(path, userid, groupid, format, level, type);
1528 SCFree(path);
1529 }
1530 else if (strcmp(output->name, "syslog") == 0) {
1531 int facility = SC_LOG_DEF_SYSLOG_FACILITY;
1532 const char *facility_s = SCConfNodeLookupChildValue(output, "facility");
1533 if (facility_s != NULL) {
1534 facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap());
1535 if (facility == -1) {
1536 SCLogWarning("Invalid syslog "
1537 "facility: \"%s\", now using \"%s\" as syslog "
1538 "facility",
1539 facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR);
1540 facility = SC_LOG_DEF_SYSLOG_FACILITY;
1541 }
1542 }
1543 SCLogDebug("Initializing syslog logging with format \"%s\"", format);
1544 have_logging = 1;
1545 op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type);
1546 }
1547 else {
1548 SCLogWarning("invalid logging method: %s, ignoring", output->name);
1549 }
1550 if (op_iface_ctx != NULL) {
1551 SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid);
1552 }
1553 }
1554
1555 if (daemon && (have_logging == 0)) {
1556 SCLogWarning("no logging compatible with daemon mode selected,"
1557 " suricata won't be able to log. Please update "
1558 " 'logging.outputs' in the YAML.");
1559 }
1560
1561 /* Set the global log level to that of the max level used. */
1562 sc_lid->global_log_level = MAX(sc_lid->global_log_level, max_level);
1563 SCLogInitLogModule(sc_lid);
1564
1565 SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level);
1566 SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format);
1567 SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter);
1568
1569 SCFree(sc_lid);
1570}
1571
1572/**
1573 * \brief Returns a full file path given a filename uses log dir specified in
1574 * conf or DEFAULT_LOG_DIR
1575 *
1576 * \param filearg The relative filename for which we want a full path include
1577 * log directory
1578 *
1579 * \retval log_filename The fullpath of the logfile to open
1580 */
1581static char *SCLogGetLogFilename(const char *filearg)
1582{
1583 const char *log_dir = SCConfigGetLogDirectory();
1584 char *log_filename = SCMalloc(PATH_MAX);
1585 if (unlikely(log_filename == NULL))
1586 return NULL;
1587 snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg);
1588 return log_filename;
1589}
1590
1591/**
1592 * \brief De-Initializes the logging module
1593 */
1595{
1596 SCLogFreeLogConfig(sc_log_config);
1597
1598 /* reset the global logging_module variables */
1602 sc_log_config = NULL;
1603
1604 /* de-init the FD filters */
1606 /* de-init the FG filters */
1608
1609#if defined (OS_WIN32)
1610 SCMutexDestroy(&sc_log_stream_lock);
1611#endif /* OS_WIN32 */
1612}
1613
1614void SCFatalErrorOnInitStatic(const char *arg)
1615{
1616 FatalErrorOnInit("%s", arg);
1617}
1618
1619//------------------------------------Unit_Tests--------------------------------
1620
1621/* The logging engine should be tested to the maximum extent possible, since
1622 * logging code would be used throughout the codebase, and hence we can't afford
1623 * to have a single bug here(not that you can afford to have a bug
1624 * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug
1625 * from the logging module.
1626 */
1627
1628#ifdef UNITTESTS
1629
1630static int SCLogTestInit01(void)
1631{
1632#ifndef OS_WIN32
1633 /* unset any environment variables set for the logging module */
1637
1638 SCLogInitLogModule(NULL);
1639
1640 FAIL_IF_NULL(sc_log_config);
1641
1642 FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level);
1643 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1644 SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface);
1645 FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1646 strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1647 sc_log_config->log_format) == 0);
1648
1650
1651 setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1);
1652 setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1);
1653 setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1);
1654
1655 SCLogInitLogModule(NULL);
1656
1657 FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1658 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1659 SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1660 FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1661 !strcmp("%n- %l", sc_log_config->log_format));
1662
1666
1668#endif
1669 PASS;
1670}
1671
1672static int SCLogTestInit02(void)
1673{
1674#ifndef OS_WIN32
1675 SCLogInitData *sc_lid = NULL;
1676 SCLogOPIfaceCtx *sc_iface_ctx = NULL;
1677 char *logfile = SCLogGetLogFilename("boo.txt");
1678 sc_lid = SCLogAllocLogInitData();
1679 FAIL_IF_NULL(sc_lid);
1680 sc_lid->startup_message = "Test02";
1682 sc_lid->op_filter = "boo";
1683 sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_WARNING, logfile);
1684 SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1685 sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR,
1686 NULL);
1687 SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1688
1689 SCLogInitLogModule(sc_lid);
1690
1691 FAIL_IF_NULL(sc_log_config);
1692
1693 FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1694 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1695 SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface);
1696 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1697 sc_log_config->op_ifaces->next != NULL &&
1698 SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface);
1699 FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1700 strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1701 sc_log_config->log_format) == 0);
1702 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1703 sc_log_config->op_ifaces->log_format != NULL &&
1704 strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0);
1705 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1706 sc_log_config->op_ifaces->next != NULL &&
1707 sc_log_config->op_ifaces->next->log_format == NULL);
1708
1709 SCLogFreeLogInitData(sc_lid);
1711
1712 sc_lid = SCLogAllocLogInitData();
1713 FAIL_IF_NULL(sc_lid);
1714 sc_lid->startup_message = "Test02";
1716 sc_lid->op_filter = "boo";
1717 sc_lid->global_log_format = "kaboo";
1718
1719 SCLogInitLogModule(sc_lid);
1720
1721 FAIL_IF_NULL(sc_log_config);
1722
1723 FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1724 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1725 SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1726 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1727 sc_log_config->op_ifaces->next == NULL);
1728 FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1729 strcmp("kaboo", sc_log_config->log_format) == 0);
1730 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1731 sc_log_config->op_ifaces->log_format == NULL);
1732 FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1733 sc_log_config->op_ifaces->next == NULL);
1734
1735 SCLogFreeLogInitData(sc_lid);
1737 SCFree(logfile);
1738#endif
1739 PASS;
1740}
1741
1742static int SCLogTestInit03(void)
1743{
1744 SCLogInitLogModule(NULL);
1745
1746 SCLogAddFGFilterBL(NULL, "bamboo", -1);
1747 SCLogAddFGFilterBL(NULL, "soo", -1);
1748 SCLogAddFGFilterBL(NULL, "dummy", -1);
1749
1751
1752 SCLogAddFGFilterBL(NULL, "dummy1", -1);
1753 SCLogAddFGFilterBL(NULL, "dummy2", -1);
1754
1756
1758
1759 PASS;
1760}
1761
1762static int SCLogTestInit04(void)
1763{
1764 SCLogInitLogModule(NULL);
1765
1766 SCLogAddFDFilter("bamboo");
1767 SCLogAddFDFilter("soo");
1768 SCLogAddFDFilter("foo");
1769 SCLogAddFDFilter("roo");
1770
1772
1773 SCLogAddFDFilter("loo");
1774 SCLogAddFDFilter("soo");
1775
1777
1778 SCLogRemoveFDFilter("bamboo");
1779 SCLogRemoveFDFilter("soo");
1780 SCLogRemoveFDFilter("foo");
1781 SCLogRemoveFDFilter("noo");
1782
1784
1786
1787 PASS;
1788}
1789
1790static int SCLogTestInit05(void)
1791{
1792 char str[4096];
1793 memset(str, 'A', sizeof(str));
1794 SCLogInfo("%s", str);
1795
1796 PASS;
1797}
1798
1799#endif /* UNITTESTS */
1800
1802{
1803
1804#ifdef UNITTESTS
1805
1806 UtRegisterTest("SCLogTestInit01", SCLogTestInit01);
1807 UtRegisterTest("SCLogTestInit02", SCLogTestInit02);
1808 UtRegisterTest("SCLogTestInit03", SCLogTestInit03);
1809 UtRegisterTest("SCLogTestInit04", SCLogTestInit04);
1810 UtRegisterTest("SCLogTestInit05", SCLogTestInit05);
1811
1812#endif /* UNITTESTS */
1813
1814 return;
1815}
struct HtpBodyChunk_ * next
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition conf.c:576
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint16_t type
Flow * head
Definition flow-hash.h:1
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
void OutputRegisterFileRotationFlag(int *flag)
Register a flag for file rotation notification.
Definition output.c:692
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
#define JB_SET_STRING(jb, key, val)
Definition rust.h:26
uint64_t ts
char * name
Definition conf.h:38
char * val
Definition conf.h:39
Holds the config state used by the logging api.
Definition util-debug.h:171
pcre2_match_data * op_filter_regex_match
Definition util-debug.h:179
char * startup_message
Definition util-debug.h:172
char * log_format
Definition util-debug.h:174
SCLogOPIfaceCtx * op_ifaces
Definition util-debug.h:182
char * op_filter
Definition util-debug.h:176
uint8_t op_ifaces_cnt
Definition util-debug.h:184
SCLogLevel log_level
Definition util-debug.h:173
pcre2_code * op_filter_regex
Definition util-debug.h:178
Structure containing init data, that would be passed to SCInitDebugModule()
Definition util-debug.h:149
const char * op_filter
Definition util-debug.h:160
SCLogOPIfaceCtx * op_ifaces
Definition util-debug.h:163
uint8_t op_ifaces_cnt
Definition util-debug.h:165
SCLogLevel global_log_level
Definition util-debug.h:154
const char * startup_message
Definition util-debug.h:151
const char * global_log_format
Definition util-debug.h:157
Structure to be used when log_level override support would be provided by the logging module.
Definition util-debug.h:107
const char * log_format
Definition util-debug.h:110
char msg[SC_LOG_MAX_LOG_MSG_LEN]
Definition util-debug.h:108
The output interface context for the logging module.
Definition util-debug.h:116
SCLogLevel log_level
Definition util-debug.h:134
const char * log_format
Definition util-debug.h:137
struct SCLogOPIfaceCtx_ * next
Definition util-debug.h:142
SCLogOPIface iface
Definition util-debug.h:117
SCLogOPType type
Definition util-debug.h:120
const char * file
Definition util-debug.h:123
#define MIN(x, y)
size_t strlcat(char *, const char *src, size_t siz)
#define MAX(x, y)
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * GetProgramVersion(void)
get string with program version
Definition suricata.c:1186
#define SCMutexDestroy
#define SCMutex
#define SCMutexUnlock(mut)
#define SCMutexInit(mut, mutattrs)
#define SCMutexLock(mut)
thread_local char t_thread_name[THREAD_NAME_LEN+1]
Definition threads.c:33
#define SCGetThreadIdLong(...)
Definition threads.h:255
const char * SCConfigGetLogDirectory(void)
Definition util-conf.c:38
int SCLogMatchFGFilterWL(const char *file, const char *function, int line)
Checks if there is a match for the incoming log_message with any of the FG filters....
int sc_log_fd_filters_present
int SCLogMatchFDFilter(const char *function)
Checks if there is a match for the incoming log_message with any of the FD filters.
void SCLogReleaseFDFilters(void)
Releases all the FD filters added to the logging module.
int SCLogPrintFGFilters(void)
Prints the FG filters(both WL and BL). Used for debugging purposes.
int SCLogMatchFGFilterBL(const char *file, const char *function, int line)
Checks if there is a match for the incoming log_message with any of the FG filters....
int sc_log_fg_filters_present
void SCLogReleaseFGFilters(void)
int SCLogAddFDFilter(const char *function)
Adds a Function-Dependent(FD) filter.
int SCLogRemoveFDFilter(const char *function)
Removes a Function-Dependent(FD) filter.
int SCLogPrintFDFilters(void)
Prints the FG filters(both WL and BL). Used for debugging purposes.
int SCLogAddFGFilterBL(const char *file, const char *function, int line)
Adds a Blacklist(BL) fine-grained(FG) filter. A FG filter BL filter allows messages that don't match ...
SCEnumCharMap sc_log_op_iface_map[]
Definition util-debug.c:68
int sc_log_module_cleaned
Used to indicate whether the logging module has been cleaned or not.
Definition util-debug.c:111
SCLogOPBuffer * SCLogAllocLogOPBuffer(void)
Allocates an output buffer for an output interface. Used when we want the op_interface log_format to ...
Definition util-debug.c:786
void SCLogDeInitLogModule(void)
De-Initializes the logging module.
SCLogLevel sc_log_global_log_level
Holds the global log level. Is the same as sc_log_config->log_level.
Definition util-debug.c:101
void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid)
int sc_log_module_initialized
Used to indicate whether the logging module has been init or not.
Definition util-debug.c:106
SCEnumCharMap sc_log_slevel_map[]
Definition util-debug.c:54
SCLogInitData * SCLogAllocLogInitData(void)
Returns a pointer to a new SCLogInitData. This is a public interface intended to be used after the lo...
void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, const char *fmt,...)
Definition util-debug.c:742
SCLogLevel SCLogGetLogLevel(void)
void SCFatalErrorOnInitStatic(const char *arg)
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition util-debug.c:767
void SCLogRegisterTests(void)
SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line, const char *function, const char *module, const char *message)
Adds the global log_format to the outgoing buffer.
Definition util-debug.c:652
void SCLog(int x, const char *file, const char *func, const int line, const char *module, const char *fmt,...)
Definition util-debug.c:723
void SCLogInitLogModule(SCLogInitData *sc_lid)
Initializes the logging module.
SCEnumCharMap sc_log_level_map[]
Definition util-debug.c:41
void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid)
Appends an output_interface to the output_interface list sent in head.
#define FatalErrorOnInit(...)
Fatal error IF we're starting up, and configured to consider errors to be fatal errors.
Definition util-debug.h:519
#define SC_LOG_DEF_LOG_FORMAT_REL_CONFIG
Definition util-debug.h:81
#define SC_LOG_FMT_THREAD_NAME
Definition util-debug.h:199
#define SC_LOG_DEF_LOG_FORMAT_DEBUG
Definition util-debug.h:82
#define FatalError(...)
Definition util-debug.h:510
#define SC_LOG_FMT_LINE
Definition util-debug.h:196
SCLogLevel
The various log levels NOTE: when adding new level, don't forget to update SCLogMapLogLevelToSyslogLe...
Definition util-debug.h:32
@ SC_LOG_LEVEL_MAX
Definition util-debug.h:42
@ SC_LOG_INFO
Definition util-debug.h:38
@ SC_LOG_ERROR
Definition util-debug.h:35
@ SC_LOG_NOTSET
Definition util-debug.h:33
@ SC_LOG_PERF
Definition util-debug.h:39
@ SC_LOG_NOTICE
Definition util-debug.h:37
@ SC_LOG_NONE
Definition util-debug.h:34
@ SC_LOG_CONFIG
Definition util-debug.h:40
@ SC_LOG_DEBUG
Definition util-debug.h:41
@ SC_LOG_WARNING
Definition util-debug.h:36
#define SC_LOG_MAX_LOG_MSG_LEN
Definition util-debug.h:85
#define SC_LOG_DEF_LOG_FORMAT_REL_INFO
Definition util-debug.h:80
#define SC_LOG_DEF_LOG_FORMAT_REL_NOTICE
Definition util-debug.h:79
#define SC_LOG_DEF_FILE_FORMAT
Definition util-debug.h:78
#define SC_LOG_ENV_LOG_FACILITY
Definition util-debug.h:58
#define SC_LOG_FMT_TIME
Definition util-debug.h:188
#define SC_LOG_FMT_SUBSYSTEM
Definition util-debug.h:198
#define SC_LOG_FMT_PREFIX
Definition util-debug.h:203
#define SCLogDebug(...)
Definition util-debug.h:275
#define SC_LOG_DEF_LOG_FILE
Definition util-debug.h:97
#define SC_LOG_ENV_LOG_OP_IFACE
Definition util-debug.h:56
#define SC_LOG_FMT_MESSAGE
Definition util-debug.h:200
#define SC_LOG_ENV_LOG_LEVEL
ENV vars that can be used to set the properties for the logging module.
Definition util-debug.h:55
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SC_LOG_FMT_FUNCTION
Definition util-debug.h:197
#define SC_LOG_FMT_LOG_LEVEL
Definition util-debug.h:193
#define SC_LOG_FMT_TID
Definition util-debug.h:191
#define SC_LOG_FMT_PID
Definition util-debug.h:190
#define SC_LOG_DEF_LOG_OP_IFACE
Definition util-debug.h:94
@ SC_LOG_OP_IFACE_CONSOLE
Definition util-debug.h:66
@ SC_LOG_OP_IFACE_SYSLOG
Definition util-debug.h:68
@ SC_LOG_OP_IFACE_FILE
Definition util-debug.h:67
@ SC_LOG_OP_IFACE_MAX
Definition util-debug.h:69
#define SC_LOG_ENV_LOG_FILE
Definition util-debug.h:57
#define SC_LOG_ENV_LOG_FORMAT
Definition util-debug.h:59
#define SC_LOG_FMT_LOG_SLEVEL
Definition util-debug.h:194
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
SCLogOPType
Definition util-debug.h:72
@ SC_LOG_OP_TYPE_REGULAR
Definition util-debug.h:73
@ SC_LOG_OP_TYPE_JSON
Definition util-debug.h:74
#define SC_LOG_DEF_SYSLOG_FACILITY_STR
Definition util-debug.h:100
#define SC_LOG_ENV_LOG_OP_FILTER
Definition util-debug.h:60
#define SC_LOG_DEF_LOG_LEVEL
Definition util-debug.h:91
#define SC_LOG_FMT_TIME_LEGACY
Definition util-debug.h:189
#define SC_LOG_FMT_FILE_NAME
Definition util-debug.h:195
#define SC_LOG_MAX_LOG_FORMAT_LEN
Definition util-debug.h:88
#define SC_LOG_DEF_SYSLOG_FACILITY
Definition util-debug.h:101
#define SC_LOG_FMT_TM
Definition util-debug.h:192
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition util-enum.c:40
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition util-enum.c:68
SCError
Definition util-error.h:26
@ SC_OK
Definition util-error.h:27
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
SCEnumCharMap * SCSyslogGetFacilityMap(void)
returns the syslog facility enum map
Definition util-syslog.c:57
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition util-time.c:267
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:209
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79
#define DEBUG_VALIDATE_BUG_ON(exp)
void setenv(const char *name, const char *value, int overwrite)
void unsetenv(const char *name)
#define LOG_EMERG
#define LOG_DEBUG
#define closelog()
#define LOG_ERR
#define syslog(__pri, __fmt, __param)
#define openlog(__ident, __option, __facility)
#define LOG_NOTICE
#define LOG_WARNING
#define LOG_INFO