From 47a5b493d748e899c478ec7f75c4858fee4552ee Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 14 Feb 2017 08:41:40 +0100 Subject: [PATCH] output-json: rotate log file based on time Rotate log file based on time. Support both rotating based on a timer (XXs, XXm, XXd, XXw) and rotating based on a absolute time, like each minute, hour or day. --- src/util-logopenfile.c | 38 +++++++++++++++++++++ src/util-logopenfile.h | 12 +++++-- src/util-time.c | 77 ++++++++++++++++++++++++++++++++++++++++++ src/util-time.h | 2 ++ 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 67b57f0f7b..cc1f0b1fb9 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -136,6 +136,14 @@ static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ct SCConfLogReopen(log_ctx); } + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + int ret = 0; if (log_ctx->fp == NULL && log_ctx->is_sock) @@ -290,6 +298,36 @@ SCConfLogOpenGeneric(ConfNode *conf, snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } + /* Rotate log file based on time */ + const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); + if (rotate_int != NULL) { + time_t now = time(NULL); + log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; + + /* Use a specific time */ + if (strcmp(rotate_int, "minute") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 60; + } else if (strcmp(rotate_int, "hour") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 3600; + } else if (strcmp(rotate_int, "day") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 86400; + } + + /* Use a timer */ + else { + log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); + if (log_ctx->rotate_interval == 0) { + SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, + "invalid rotate-interval value"); + exit(EXIT_FAILURE); + } + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 201106cc59..c84acffd40 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -102,6 +102,13 @@ typedef struct LogFileCtx_ { int sock_type; uint64_t reconn_timer; + /** The next time to rotate log file, if rotate interval is + specified. */ + time_t rotate_time; + + /** The interval to rotate the log file */ + uint64_t rotate_interval; + /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; @@ -133,8 +140,9 @@ typedef struct LogFileCtx_ { #define LOGFILE_RECONN_MIN_TIME 500 /* flags for LogFileCtx */ -#define LOGFILE_HEADER_WRITTEN 0x01 -#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_HEADER_WRITTEN 0x01 +#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_ROTATE_INTERVAL 0x04 LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); diff --git a/src/util-time.c b/src/util-time.c index 7f6ab49a67..3e2b6058bb 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -512,3 +512,80 @@ int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t return 0; } + +/** + * \brief Parse string containing time size (1m, 1h, etc). + * + * \param str String to parse. + * + * \retval size on success. + * \retval 0 on failure. + */ +uint64_t SCParseTimeSizeString (const char *str) +{ + uint64_t size = 0; + uint64_t modifier = 1; + char last = str[strlen(str)-1]; + + switch (last) + { + case '0' ... '9': + break; + /* seconds */ + case 's': + break; + /* minutes */ + case 'm': + modifier = 60; + break; + /* hours */ + case 'h': + modifier = 60 * 60; + break; + /* days */ + case 'd': + modifier = 60 * 60 * 24; + break; + /* weeks */ + case 'w': + modifier = 60 * 60 * 24 * 7; + break; + /* invalid */ + default: + return 0; + } + + errno = 0; + size = strtoumax(str, NULL, 10); + if (errno) { + return 0; + } + + return (size * modifier); +} + +/** + * \brief Get seconds until a time unit changes. + * + * \param str String containing time type (minute, hour, etc). + * \param epoch Epoch time. + * + * \retval seconds. + */ +uint64_t SCGetSecondsUntil (const char *str, time_t epoch) +{ + uint64_t seconds = 0; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + + if (strcmp(str, "minute") == 0) + seconds = 60 - tp->tm_sec; + else if (strcmp(str, "hour") == 0) + seconds = (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); + else if (strcmp(str, "day") == 0) + seconds = (3600 * (24 - tp->tm_hour)) + (60 * (60 - tp->tm_min)) + + (60 - tp->tm_sec); + + return seconds; +} diff --git a/src/util-time.h b/src/util-time.h index ae7ec2f525..4bf965e729 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -60,6 +60,8 @@ int SCStringPatternToTime(char *string, char **patterns, int num_patterns, struct tm *time); int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t size); +uint64_t SCParseTimeSizeString (const char *str); +uint64_t SCGetSecondsUntil (const char *str, time_t epoch); #endif /* __UTIL_TIME_H__ */