Go to the documentation of this file.
37 #if defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SYS_TYPES_H)
38 #define BUILD_WITH_UNIXSOCKET
39 #include <sys/types.h>
40 #include <sys/socket.h>
44 #ifdef HAVE_LIBHIREDIS
48 #define LOGFILE_NAME_MAX 255
50 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
56 #ifdef BUILD_WITH_UNIXSOCKET
64 SCLogOpenUnixSocketFp(
const char *path,
int sock_type,
int log_err)
66 struct sockaddr_un saun;
70 memset(&saun, 0x00,
sizeof(saun));
72 s = socket(PF_UNIX, sock_type, 0);
75 saun.sun_family = AF_UNIX;
76 strlcpy(saun.sun_path, path,
sizeof(saun.sun_path));
78 if (connect(s, (
const struct sockaddr *)&saun,
sizeof(saun)) < 0)
90 "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno));
102 static int SCLogUnixSocketReconnect(
LogFileCtx *log_ctx)
104 int disconnected = 0;
116 gettimeofday(&
tv, NULL);
117 now = (uint64_t)
tv.tv_sec * 1000;
118 now +=
tv.tv_usec / 1000;
130 }
else if (disconnected) {
131 SCLogWarning(
"Reconnect failed: %s (will keep trying)", strerror(errno));
134 return log_ctx->
fp ? 1 : 0;
137 static int SCLogFileWriteSocket(
const char *buffer,
int buffer_len,
143 if (
ctx->fp == NULL &&
ctx->is_sock) {
144 SCLogUnixSocketReconnect(
ctx);
150 if (
ctx->fp != NULL) {
151 int fd = fileno(
ctx->fp);
152 ssize_t size = send(fd, buffer, buffer_len,
ctx->send_flags);
156 if (errno == EAGAIN || errno == EWOULDBLOCK) {
157 SCLogDebug(
"Socket would block, dropping event.");
158 }
else if (errno == EINTR) {
160 SCLogDebug(
"Interrupted system call, trying again.");
163 SCLogDebug(
"Too many interrupted system calls, "
167 SCLogDebug(
"Send failed: %s", strerror(errno));
173 if (reopen && tries++ == 0) {
174 if (SCLogUnixSocketReconnect(
ctx)) {
186 static inline void OutputWriteLock(pthread_mutex_t *
m)
195 static void SCLogFileFlushNoLock(
LogFileCtx *log_ctx)
201 static void SCLogFileFlush(
LogFileCtx *log_ctx)
203 OutputWriteLock(&log_ctx->
fp_mutex);
204 SCLogFileFlushNoLock(log_ctx);
213 static int SCLogFileWriteNoLock(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
226 time_t now = time(NULL);
251 SCLogFileFlushNoLock(log_ctx);
263 static int SCLogFileWrite(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
265 OutputWriteLock(&log_ctx->
fp_mutex);
268 #ifdef BUILD_WITH_UNIXSOCKET
270 ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx);
274 ret = SCLogFileWriteNoLock(buffer, buffer_len, log_ctx);
287 static char *SCLogFilenameFromPattern(
const char *pattern)
289 char *filename =
SCMalloc(PATH_MAX);
290 if (filename == NULL) {
303 static void SCLogFileCloseNoLock(
LogFileCtx *log_ctx)
318 static void SCLogFileClose(
LogFileCtx *log_ctx)
321 SCLogFileCloseNoLock(log_ctx);
325 static char ThreadLogFileHashCompareFunc(
326 void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
331 if (p1 == NULL || p2 == NULL)
336 static uint32_t ThreadLogFileHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
343 static void ThreadLogFileHashFreeFunc(
void *data)
365 SCLogError(
"Unable to allocate threads container");
370 ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc);
372 FatalError(
"Unable to initialize thread/entry hash table");
377 SCLogError(
"Unable to allocate threads append setting");
404 static FILE *SCLogOpenFileFp(
405 const char *path,
const char *append_setting, uint32_t mode,
const uint32_t buffer_size)
409 char *filename = SCLogFilenameFromPattern(path);
410 if (filename == NULL) {
421 ret = fopen(filename,
"a");
423 ret = fopen(filename,
"w");
427 SCLogError(
"Error opening file: \"%s\": %s", filename, strerror(errno));
432 int r = _chmod(filename, (mode_t)mode);
434 int r = fchmod(fileno(ret), (mode_t)mode);
437 SCLogWarning(
"Could not chmod %s to %o: %s", filename, mode, strerror(errno));
443 if (buffer_size == 0) {
445 SCLogConfig(
"Setting output to %s non-buffered", filename);
447 if (setvbuf(ret, NULL, _IOFBF, buffer_size) < 0)
448 FatalError(
"unable to set %s to buffered: %d", filename, buffer_size);
449 SCLogConfig(
"Setting output to %s buffered [limit %d bytes]", filename, buffer_size);
469 const char *default_filename,
472 char log_path[PATH_MAX];
474 const char *filename, *filetype;
477 if (conf == NULL || log_ctx == NULL || default_filename == NULL) {
478 SCLogError(
"SCConfLogOpenGeneric(conf %p, ctx %p, default %p) "
479 "missing an argument",
480 conf, log_ctx, default_filename);
483 if (log_ctx->
fp != NULL) {
484 SCLogError(
"SCConfLogOpenGeneric: previously initialized Log CTX "
491 if (filename == NULL)
492 filename = default_filename;
497 snprintf(log_path, PATH_MAX,
"%s", filename);
499 snprintf(log_path, PATH_MAX,
"%s/%s", log_dir, filename);
504 if (rotate_int != NULL) {
505 time_t now = time(NULL);
509 if (strcmp(rotate_int,
"minute") == 0) {
512 }
else if (strcmp(rotate_int,
"hour") == 0) {
515 }
else if (strcmp(rotate_int,
"day") == 0) {
531 if (filetype == NULL)
540 if (buffer_size_value != NULL) {
544 "buffer-size - %s. Killing engine",
550 SCLogDebug(
"buffering: %s -> %d", buffer_size_value, buffer_size);
553 if (filemode != NULL &&
StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) {
562 log_ctx->
json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT|
567 if (json_flags != 0) {
571 log_ctx->
json_flags &= ~(JSON_PRESERVE_ORDER);
588 #ifdef BUILD_WITH_UNIXSOCKET
590 if (strcasecmp(filetype,
"unix_stream") == 0 || strcasecmp(filetype,
"unix_dgram") == 0) {
591 FatalError(
"Socket file types do not support threaded output");
596 SCLogConfig(
"buffering setting ignored for %s output types", filetype);
600 if (strcasecmp(filetype,
"unix_stream") == 0) {
601 #ifdef BUILD_WITH_UNIXSOCKET
605 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
609 }
else if (strcasecmp(filetype,
"unix_dgram") == 0) {
610 #ifdef BUILD_WITH_UNIXSOCKET
614 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
619 strcasecmp(filetype,
"file") == 0) {
625 if (log_ctx->
fp == NULL)
637 "%s.filetype. Expected \"regular\" (default), \"unix_stream\", "
643 SCLogError(
"Failed to allocate memory for filename");
647 #ifdef BUILD_WITH_UNIXSOCKET
650 SCLogInfo(
"Setting logging socket of non-blocking in live mode.");
654 SCLogInfo(
"%s output device (%s) initialized: %s", conf->
name, filetype,
675 SCLogWarning(
"Can't re-open LogFileCtx without a filename.");
679 if (log_ctx->
fp != NULL) {
688 if (log_ctx->
fp == NULL) {
706 lf_ctx->
Write = SCLogFileWrite;
707 lf_ctx->
Close = SCLogFileClose;
708 lf_ctx->
Flush = SCLogFileFlush;
732 FatalError(
"Unable to allocate thread/hash-entry entry");
739 FatalError(
"Unable to add thread/hash-entry mapping");
759 SCLogDebug(
"%s: Adding reference for thread %" PRIi64
760 " (local thread id %d) to file %s [ctx %p]",
767 thread_id, parent_ctx->
filename, parent_ctx);
768 if (LogFileNewThreadedCtx(
771 ret_ctx = entry->
ctx;
778 ret_ctx = entry->
ctx;
784 SCLogDebug(
"Existing file for thread/entry %p reference to file %s [ctx %p]", entry,
795 static bool LogFileThreadedName(
796 const char *original_name,
char *threaded_name,
size_t len, uint32_t unique_id)
800 if (strcmp(
"/dev/null", original_name) == 0) {
807 FatalError(
"Invalid filename for threaded mode \"%s\"; "
808 "no basename found.",
813 char *dot = strrchr(base,
'.');
815 char *tname =
SCStrdup(original_name);
824 dot = strrchr(original_name,
'.');
825 ptrdiff_t dotpos = dot - original_name;
826 tname[dotpos] =
'\0';
827 char *ext = tname + dotpos + 1;
828 if (strlen(tname) && strlen(ext)) {
829 snprintf(threaded_name,
len,
"%s.%u.%s", tname, unique_id, ext);
831 FatalError(
"Invalid filename for threaded mode \"%s\"; "
832 "filenames must include an extension, e.g: \"name.ext\"",
837 snprintf(threaded_name,
len,
"%s.%u", original_name, unique_id);
848 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
853 SCLogError(
"Unable to allocate thread file context entry %p", entry);
857 *thread = *parent_ctx;
861 if (!LogFileThreadedName(log_path, fname,
sizeof(fname), entry->
slot_number)) {
862 SCLogError(
"Unable to create threaded filename for log");
865 SCLogDebug(
"%s: thread open -- using name %s [replaces %s] - thread %d [slot %d]",
868 if (thread->
fp == NULL) {
873 SCLogError(
"Unable to duplicate filename for context entry %p", entry);
877 thread->
Write = SCLogFileWriteNoLock;
878 thread->
Close = SCLogFileCloseNoLock;
888 thread->
parent = parent_ctx;
889 thread->
entry = entry;
898 thread->
Close(thread);
914 if (lf_ctx == NULL) {
934 if (lf_ctx->
fp != NULL) {
935 lf_ctx->
Close(lf_ctx);
941 if (lf_ctx->
prefix != NULL) {
963 #ifdef HAVE_LIBHIREDIS
965 if (lf_ctx->redis_setup.stream_format != NULL) {
966 SCFree(lf_ctx->redis_setup.stream_format);
971 memset(lf_ctx, 0,
sizeof(*lf_ctx));
980 file_ctx->
Flush(file_ctx);
996 #ifdef HAVE_LIBHIREDIS
uint64_t SCParseTimeSizeString(const char *str)
Parse string containing time size (1m, 1h, etc).
int SCRunmodeGet(void)
Get the current run mode.
#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val)
wrapper for declaring an atomic variable and initializing it to a specific value
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
int(* Write)(const char *buffer, const int buffer_len, const void *init_data, void *thread_data)
Called for each EVE log record.
#define LOGFILE_RECONN_MIN_TIME
#define DEFAULT_LOG_MODE_APPEND
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
#define JSON_ESCAPE_SLASH
int SCConfLogReopen(LogFileCtx *log_ctx)
Reopen a regular log file with the side-affect of truncating it.
bool IsRunModeOffline(enum RunModes run_mode_to_check)
#define SCClearErrUnlocked
int ConfValIsTrue(const char *val)
Check if a value is true.
void HashTableFree(HashTable *ht)
thread_local char t_thread_name[THREAD_NAME_LEN+1]
int SCConfLogOpenGeneric(ConfNode *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
size_t strlcpy(char *dst, const char *src, size_t siz)
void(* ThreadDeinit)(const void *init_data, void *thread_data)
Called to deinitialize each thread.
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.
int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
#define DEFAULT_LOG_FILETYPE
#define SCMutexUnlock(mut)
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
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)
LogThreadedFileCtx * threads
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
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 SCMutexInit(mut, mutattrs)
uint64_t bytes_since_last_flush
#define SCGetThreadIdLong(...)
ConfNode * ConfNodeLookupChild(const ConfNode *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)
void(* Deinit)(void *init_data)
Final call to deinitialize this filetype.
int ParseSizeStringU32(const char *size, uint32_t *res)
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
const char * ConfigGetLogDirectory(void)
#define SCLogError(...)
Macro used to log ERROR messages.
#define LOGFILE_ROTATE_INTERVAL
int ConfValIsFalse(const char *val)
Check if a value is false.
thread_local SCError sc_errno
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.
int(* ThreadInit)(const void *init_data, const ThreadId thread_id, void **thread_data)
Initialize thread specific data.
void OutputUnregisterFileRotationFlag(int *flag)
Unregister a file rotation flag.
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.