Go to the documentation of this file.
38 #if defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SYS_TYPES_H)
39 #define BUILD_WITH_UNIXSOCKET
40 #include <sys/types.h>
41 #include <sys/socket.h>
45 #ifdef HAVE_LIBHIREDIS
49 #define LOGFILE_NAME_MAX 255
51 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
62 #ifdef BUILD_WITH_UNIXSOCKET
70 SCLogOpenUnixSocketFp(
const char *path,
int sock_type,
int log_err)
72 struct sockaddr_un saun;
76 memset(&saun, 0x00,
sizeof(saun));
78 s = socket(PF_UNIX, sock_type, 0);
81 saun.sun_family = AF_UNIX;
82 strlcpy(saun.sun_path, path,
sizeof(saun.sun_path));
84 if (connect(s, (
const struct sockaddr *)&saun,
sizeof(saun)) < 0)
96 "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno));
108 static int SCLogUnixSocketReconnect(
LogFileCtx *log_ctx)
110 int disconnected = 0;
122 gettimeofday(&
tv, NULL);
123 now = (uint64_t)
tv.tv_sec * 1000;
124 now +=
tv.tv_usec / 1000;
136 }
else if (disconnected) {
137 SCLogWarning(
"Reconnect failed: %s (will keep trying)", strerror(errno));
140 return log_ctx->
fp ? 1 : 0;
143 static int SCLogFileWriteSocket(
const char *buffer,
int buffer_len,
149 if (
ctx->fp == NULL &&
ctx->is_sock) {
150 SCLogUnixSocketReconnect(
ctx);
156 if (
ctx->fp != NULL) {
157 int fd = fileno(
ctx->fp);
158 ssize_t size = send(fd, buffer, buffer_len,
ctx->send_flags);
162 if (errno == EAGAIN || errno == EWOULDBLOCK) {
163 SCLogDebug(
"Socket would block, dropping event.");
164 }
else if (errno == EINTR) {
166 SCLogDebug(
"Interrupted system call, trying again.");
169 SCLogDebug(
"Too many interrupted system calls, "
173 SCLogDebug(
"Send failed: %s", strerror(errno));
179 if (reopen && tries++ == 0) {
180 if (SCLogUnixSocketReconnect(
ctx)) {
192 static inline void OutputWriteLock(pthread_mutex_t *
m)
201 static void SCLogFileFlushNoLock(
LogFileCtx *log_ctx)
207 static void SCLogFileFlush(
LogFileCtx *log_ctx)
209 OutputWriteLock(&log_ctx->
fp_mutex);
210 SCLogFileFlushNoLock(log_ctx);
219 static bool HandleLogRotation(
LogFileCtx *log_ctx)
229 time_t now = time(NULL);
245 static int SCLogFileWriteNoLock(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
251 HandleLogRotation(log_ctx);
271 SCLogFileFlushNoLock(log_ctx);
283 static int SCLogFileWrite(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
285 OutputWriteLock(&log_ctx->
fp_mutex);
288 #ifdef BUILD_WITH_UNIXSOCKET
290 ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx);
294 ret = SCLogFileWriteNoLock(buffer, buffer_len, log_ctx);
307 static char *SCLogFilenameFromPattern(
const char *pattern)
309 char *filename =
SCMalloc(PATH_MAX);
310 if (filename == NULL) {
323 static void SCLogFileCloseNoLock(
LogFileCtx *log_ctx)
338 static void SCLogFileClose(
LogFileCtx *log_ctx)
341 SCLogFileCloseNoLock(log_ctx);
345 static char ThreadLogFileHashCompareFunc(
346 void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
351 if (p1 == NULL || p2 == NULL)
356 static uint32_t ThreadLogFileHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
363 static void ThreadLogFileHashFreeFunc(
void *data)
385 SCLogError(
"Unable to allocate threads container");
390 ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc);
392 FatalError(
"Unable to initialize thread/entry hash table");
397 SCLogError(
"Unable to allocate threads append setting");
424 static FILE *SCLogOpenFileFp(
425 const char *path,
const char *append_setting, uint32_t mode,
const uint32_t buffer_size)
429 char *filename = SCLogFilenameFromPattern(path);
430 if (filename == NULL) {
441 ret = fopen(filename,
"a");
443 ret = fopen(filename,
"w");
447 SCLogError(
"Error opening file: \"%s\": %s", filename, strerror(errno));
452 int r = _chmod(filename, (mode_t)mode);
454 int r = fchmod(fileno(ret), (mode_t)mode);
457 SCLogWarning(
"Could not chmod %s to %o: %s", filename, mode, strerror(errno));
463 if (buffer_size == 0) {
465 SCLogConfig(
"Setting output to %s non-buffered", filename);
467 if (setvbuf(ret, NULL, _IOFBF, buffer_size) < 0)
468 FatalError(
"unable to set %s to buffered: %d", filename, buffer_size);
469 SCLogConfig(
"Setting output to %s buffered [limit %d bytes]", filename, buffer_size);
489 char log_path[PATH_MAX];
491 const char *filename, *filetype;
494 if (conf == NULL || log_ctx == NULL || default_filename == NULL) {
495 SCLogError(
"SCConfLogOpenGeneric(conf %p, ctx %p, default %p) "
496 "missing an argument",
497 conf, log_ctx, default_filename);
500 if (log_ctx->
fp != NULL) {
501 SCLogError(
"SCConfLogOpenGeneric: previously initialized Log CTX "
508 if (filename == NULL)
509 filename = default_filename;
514 snprintf(log_path, PATH_MAX,
"%s", filename);
516 snprintf(log_path, PATH_MAX,
"%s/%s", log_dir, filename);
527 if (rotate_int != NULL) {
528 time_t now = time(NULL);
532 if (strcmp(rotate_int,
"minute") == 0) {
535 }
else if (strcmp(rotate_int,
"hour") == 0) {
538 }
else if (strcmp(rotate_int,
"day") == 0) {
554 if (filetype == NULL)
563 if (buffer_size_value != NULL) {
567 "buffer-size - %s. Killing engine",
573 SCLogDebug(
"buffering: %s -> %d", buffer_size_value, buffer_size);
576 if (filemode != NULL &&
StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) {
585 log_ctx->
json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT|
590 if (json_flags != 0) {
593 log_ctx->
json_flags &= ~(JSON_PRESERVE_ORDER);
608 #ifdef BUILD_WITH_UNIXSOCKET
610 if (strcasecmp(filetype,
"unix_stream") == 0 || strcasecmp(filetype,
"unix_dgram") == 0) {
611 FatalError(
"Socket file types do not support threaded output");
616 SCLogConfig(
"buffering setting ignored for %s output types", filetype);
620 if (strcasecmp(filetype,
"unix_stream") == 0) {
621 #ifdef BUILD_WITH_UNIXSOCKET
625 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
629 }
else if (strcasecmp(filetype,
"unix_dgram") == 0) {
630 #ifdef BUILD_WITH_UNIXSOCKET
634 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
639 strcasecmp(filetype,
"file") == 0) {
645 if (log_ctx->
fp == NULL)
661 "%s.filetype. Expected \"regular\" (default), \"unix_stream\", "
667 SCLogError(
"Failed to allocate memory for filename");
671 #ifdef BUILD_WITH_UNIXSOCKET
674 SCLogInfo(
"Setting logging socket of non-blocking in live mode.");
678 SCLogInfo(
"%s output device (%s) initialized: %s", conf->
name, filetype,
699 SCLogWarning(
"Can't re-open LogFileCtx without a filename.");
703 if (log_ctx->
fp != NULL) {
712 if (log_ctx->
fp == NULL) {
730 lf_ctx->
Write = SCLogFileWrite;
731 lf_ctx->
Close = SCLogFileClose;
732 lf_ctx->
Flush = SCLogFileFlush;
756 FatalError(
"Unable to allocate thread/hash-entry entry");
763 FatalError(
"Unable to add thread/hash-entry mapping");
783 SCLogDebug(
"%s: Adding reference for thread %" PRIi64
784 " (local thread id %d) to file %s [ctx %p]",
791 thread_id, parent_ctx->
filename, parent_ctx);
792 if (LogFileNewThreadedCtx(
795 ret_ctx = entry->
ctx;
802 ret_ctx = entry->
ctx;
808 SCLogDebug(
"Existing file for thread/entry %p reference to file %s [ctx %p]", entry,
819 static bool LogFileThreadedName(
820 const char *original_name,
char *threaded_name,
size_t len, uint32_t unique_id)
824 if (strcmp(
"/dev/null", original_name) == 0) {
831 FatalError(
"Invalid filename for threaded mode \"%s\"; "
832 "no basename found.",
837 char *dot = strrchr(base,
'.');
839 char *tname =
SCStrdup(original_name);
848 dot = strrchr(original_name,
'.');
849 ptrdiff_t dotpos = dot - original_name;
850 tname[dotpos] =
'\0';
851 char *ext = tname + dotpos + 1;
852 if (strlen(tname) && strlen(ext)) {
853 snprintf(threaded_name,
len,
"%s.%u.%s", tname, unique_id, ext);
855 FatalError(
"Invalid filename for threaded mode \"%s\"; "
856 "filenames must include an extension, e.g: \"name.ext\"",
861 snprintf(threaded_name,
len,
"%s.%u", original_name, unique_id);
872 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
877 SCLogError(
"Unable to allocate thread file context entry %p", entry);
881 *thread = *parent_ctx;
885 if (!LogFileThreadedName(log_path, fname,
sizeof(fname), entry->
slot_number)) {
886 SCLogError(
"Unable to create threaded filename for log");
889 SCLogDebug(
"%s: thread open -- using name %s [replaces %s] - thread %d [slot %d]",
892 if (thread->
fp == NULL) {
897 SCLogError(
"Unable to duplicate filename for context entry %p", entry);
902 thread->
Write = SCLogFileWrite;
903 thread->
Close = SCLogFileClose;
905 thread->
Write = SCLogFileWriteNoLock;
906 thread->
Close = SCLogFileCloseNoLock;
918 thread->
parent = parent_ctx;
919 thread->
entry = entry;
928 thread->
Close(thread);
944 if (lf_ctx == NULL) {
969 if (lf_ctx->
fp != NULL) {
970 lf_ctx->
Close(lf_ctx);
976 if (lf_ctx->
prefix != NULL) {
998 #ifdef HAVE_LIBHIREDIS
1000 if (lf_ctx->redis_setup.stream_format != NULL) {
1001 SCFree(lf_ctx->redis_setup.stream_format);
1006 memset(lf_ctx, 0,
sizeof(*lf_ctx));
1015 file_ctx->
Flush(file_ctx);
1029 SCLogDebug(
"heartbeat disabled; skipping flush registration");
1038 if (entry == NULL) {
1039 SCLogError(
"Unable to allocate memory for flush entry");
1060 SCLogDebug(
"heartbeat disabled; skipping flush deregistration");
1091 if (entry->
ctx != NULL) {
1111 #ifdef HAVE_LIBHIREDIS
uint64_t SCParseTimeSizeString(const char *str)
Parse string containing time size (1m, 1h, etc).
int SCConfValIsTrue(const char *val)
Check if a value is true.
SCEveFileTypeDeinitFunc Deinit
Final call to deinitialize this filetype.
bool IsRunModeOffline(enum SCRunModes run_mode_to_check)
#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val)
wrapper for declaring an atomic variable and initializing it to a specific value
SCEveFileTypeWriteFunc Write
Called for each EVE log record.
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
uint64_t SCGetSecondsUntil(const char *str, time_t epoch)
Get seconds until a time unit changes.
void LogFileFlush(LogFileCtx *file_ctx)
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define LOGFILE_RECONN_MIN_TIME
#define TAILQ_FOREACH(var, head, field)
#define DEFAULT_LOG_MODE_APPEND
int SCConfValIsFalse(const char *val)
Check if a value is false.
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
#define SCMUTEX_INITIALIZER
#define TAILQ_INSERT_TAIL(head, elm, field)
#define JSON_ESCAPE_SLASH
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
int SCConfLogReopen(LogFileCtx *log_ctx)
Reopen a regular log file with the side-affect of truncating it.
#define SCClearErrUnlocked
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
thread_local char t_thread_name[THREAD_NAME_LEN+1]
size_t strlcpy(char *dst, const char *src, size_t siz)
void OutputRegisterFileRotationFlag(int *flag)
Register a flag for file rotation notification.
int SCTimeToStringPattern(time_t epoch, const char *pattern, char *str, size_t size)
Convert epoch time to string pattern.
#define TAILQ_HEAD_INITIALIZER(head)
#define TAILQ_REMOVE(head, elm, field)
SCRunMode SCRunmodeGet(void)
Get the current run mode.
int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
SCEveFileTypeThreadDeinitFunc ThreadDeinit
Called to deinitialize each thread.
#define DEFAULT_LOG_FILETYPE
SCEveFileTypeThreadInitFunc ThreadInit
Initialize thread specific data.
#define SCMutexUnlock(mut)
int OutputFlushInterval(void)
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Remove an item from the hash table.
ThreadId internal_thread_id
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
#define LOGFILE_EVE_BUFFER_SIZE
#define SCLogWarning(...)
Macro used to log WARNING messages.
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
void LogFileUnregisterForFlush(LogFileCtx *ctx)
Unregister a LogFileCtx from flush operations.
LogThreadedFileCtx * threads
void LogFileFlushAll(void)
Flush all registered LogFileCtx instances.
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
const char * SCConfigGetLogDirectory(void)
const char * SCBasename(const char *path)
@ LOGFILE_TYPE_UNIX_DGRAM
bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx)
@ LOGFILE_TYPE_UNIX_STREAM
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
#define SCMutexInit(mut, mutattrs)
uint64_t bytes_since_last_flush
#define SCGetThreadIdLong(...)
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
struct LogFileCtx_ * parent
LogFileCtx * LogFileEnsureExists(ThreadId thread_id, LogFileCtx *parent_ctx)
LogFileEnsureExists() Ensure a log file context for the thread exists.
void(* Flush)(struct LogFileCtx_ *fp)
int PathIsAbsolute(const char *path)
Check if a path is absolute.
ThreadLogFileHashEntry * entry
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
int ParseSizeStringU32(const char *size, uint32_t *res)
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
#define SCLogError(...)
Macro used to log ERROR messages.
int SCConfLogOpenGeneric(SCConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
#define LOGFILE_ROTATE_INTERVAL
thread_local SCError sc_errno
#define TAILQ_HEAD(name, type)
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
SCLogLevel sc_log_global_log_level
Holds the global log level. Is the same as sc_log_config->log_level.
void MemBufferWriteString(MemBuffer *dst, const char *fmt,...)
void(* Close)(struct LogFileCtx_ *fp)
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
void LogFileRegisterForFlush(LogFileCtx *ctx)
Register a LogFileCtx for flush operations.
void OutputUnregisterFileRotationFlag(int *flag)
Unregister a file rotation flag.
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
#define DEBUG_VALIDATE_BUG_ON(exp)
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.