]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
output-json: rotate log file based on time
authorMats Klepsland <mats.klepsland@gmail.com>
Tue, 14 Feb 2017 07:41:40 +0000 (08:41 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 6 Apr 2017 14:19:45 +0000 (16:19 +0200)
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
src/util-logopenfile.h
src/util-time.c
src/util-time.h

index 67b57f0f7b714b3e999b07ce3b45ed8f05a64410..cc1f0b1fb96e4ee3a3532c10447a744a9d46699f 100644 (file)
@@ -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;
index 201106cc598b085aab4399ebddc2e988f0e2be1b..c84acffd407681439a9fa76b20687dc2e8d0b660 100644 (file)
@@ -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 *);
index 7f6ab49a677b381dfba560dcfd2610efd94724c8..3e2b6058bbff34ebe30576646ce979e31758e342 100644 (file)
@@ -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;
+}
index ae7ec2f5251af73827218f3805bc3283b64bb072..4bf965e729ffa90912c4b00beff2c72bcb073302 100644 (file)
@@ -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__ */