]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Allow size units B, K, M, G and combination of
authorRainer Jung <rjung@apache.org>
Sun, 11 Jan 2009 22:45:53 +0000 (22:45 +0000)
committerRainer Jung <rjung@apache.org>
Sun, 11 Jan 2009 22:45:53 +0000 (22:45 +0000)
time and size based rotation for rotatelogs.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@733531 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/man/rotatelogs.8
docs/manual/programs/rotatelogs.xml
support/rotatelogs.c

diff --git a/CHANGES b/CHANGES
index 58450a721d3d7b6859dbcc69716b73f23281214c..fb8b90fc463d1de233d5cdc91539267e0be1df67 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
 Changes with Apache 2.3.2
 [ When backported to 2.2.x, remove entry from this file ]
 
+ *) rotatelogs: Allow size units B, K, M, G and combination of
+    time and size based rotation. [Rainer Jung]
+
  *) rotatelogs: Add flag for verbose (debug) output. [Rainer Jung]
 
  *) rotatelogs: Allow to trigger log file rotation from outside
index b3a9888506c7ea6999a21098665e799cb1caf216..42b98eb9fe27b00d5dc815dc2a208cbef09ee137 100644 (file)
@@ -27,7 +27,7 @@ rotatelogs \- Piped logging program to rotate Apache logs
 .SH "SYNOPSIS"
  
 .PP
-\fBrotatelogs\fR [ -\fBl\fR ] [ -\fBf\fR ] [ -\fBv\fR ] \fIlogfile\fR \fIrotationtime\fR|\fIfilesize\fRM [ \fIoffset\fR ]
+\fBrotatelogs\fR [ -\fBl\fR ] [ -\fBf\fR ] [ -\fBv\fR ] \fIlogfile\fR \fIrotationtime\fR|\fIfilesize\fR(B|K|M|G) [ \fIoffset\fR ]
  
 
 .SH "SUMMARY"
@@ -55,8 +55,10 @@ The path plus basename of the logfile\&. If \fIlogfile\fR includes any '%' chara
 \fIrotationtime\fR
 The time between log file rotations in seconds\&. The rotation occurs at the beginning of this interval\&. For example, if the rotation time is 3600, the log file will be rotated at the beginning of every hour; if the rotation time is 86400, the log file will be rotated every night at midnight\&. (If no data is logged during an interval, no file will be created\&.)  
 .TP
-\fIfilesize\fRM
-The maximum file size in megabytes followed by the letter M to specify size rather than time\&.  
+\fIfilesize\fR(B|K|M|G)
+The maximum file size followed by exactly one of the letters B (Bytes), K (KBytes), M (MBytes) or G (GBytes)\&.
+.br
+When time and size are specified, the size must be given after the time\&. Rotation will occur whenever either time or size limits are reached\&.
 .TP
 \fIoffset\fR
 The number of minutes offset from UTC\&. If omitted, zero is assumed and UTC is used\&. For example, to use local time in the zone UTC -5 hours, specify a value of -300 for this argument\&. In most cases, -l should be used instead of specifying an offset\&.  
index df2bd5bd2d698bebdb92b114213ca0ba27235e49..29022f5a9c2a6237444a812561f6121e6f0b5b58 100644 (file)
@@ -41,7 +41,7 @@
      [ -<strong>f</strong> ]
      [ -<strong>v</strong> ]
      <var>logfile</var>
-     <var>rotationtime</var>|<var>filesize</var>M 
+     <var>rotationtime</var>|<var>filesize</var>(B|K|M|G) 
      [ <var>offset</var> ]</code></p>
 </section>
 
@@ -91,10 +91,15 @@ of every hour; if the rotation time is 86400, the log file will be
 rotated every night at midnight.  (If no data is logged during an
 interval, no file will be created.)</dd>
 
-<dt><code><var>filesize</var>M</code></dt>
+<dt><code><var>filesize</var>(B|K|M|G)</code></dt>
 
-<dd>The maximum file size in megabytes followed by the letter
-<code>M</code> to specify size rather than time.</dd>
+<dd>The maximum file size in followed by exactly one of the letters
+<code>B</code> (Bytes), <code>K</code> (KBytes), <code>M</code> (MBytes)
+or <code>G</code> (GBytes).
+<br/>
+When time and size are specified, the size must be given after the time.
+Rotation will occur whenever either time or size limits are reached.
+</dd>
 
 <dt><code><var>offset</var></code></dt>
 
index 8e602880745d55866596c8013846e233fe3d8850..64f7a24d8e08f53ccd8ae10fdbc66cb6950c4ab0 100644 (file)
@@ -153,6 +153,10 @@ static void usage(const char *argv0, const char *reason)
     exit(1);
 }
 
+/*
+ * Get the unix time with timezone corrections
+ * given in the config struct.
+ */
 static int get_now(rotate_config_t *config)
 {
     apr_time_t tNow = apr_time_now();
@@ -169,6 +173,9 @@ static int get_now(rotate_config_t *config)
     return (int)apr_time_sec(tNow) + utc_offset;
 }
 
+/*
+ * Close a file and destroy the associated pool.
+ */
 static void closeFile(rotate_config_t *config, apr_pool_t *pool, apr_file_t *file)
 {
     if (file != NULL) {
@@ -186,6 +193,9 @@ static void closeFile(rotate_config_t *config, apr_pool_t *pool, apr_file_t *fil
     }
 }
 
+/*
+ * Dump the configuration parsing result to STDERR.
+ */
 static void dumpConfig (rotate_config_t *config)
 {
     fprintf(stderr, "Rotation time interval:      %12d\n", config->tRotation);
@@ -198,6 +208,22 @@ static void dumpConfig (rotate_config_t *config)
     fprintf(stderr, "Rotation file name: %21s\n", config->szLogRoot);
 }
 
+/*
+ * Check whether we need to rotate.
+ * Possible reasons are:
+ * - No log file open (ROTATE_NEW)
+ * - User forces us to rotate (ROTATE_FORCE)
+ * - Our log file size is already bigger than the
+ *   allowed maximum (ROTATE_SIZE)
+ * - The next log time interval expired (ROTATE_TIME)
+ *
+ * When size and time constraints are both given,
+ * it suffices that one of them is fulfilled.
+ *
+ * If the method finds a reason for rotation,
+ * and it hasn't been called while log data is available,
+ * it will close the open log file as a side effect.
+ */
 static void checkRotate(rotate_config_t *config, rotate_status_t *status)
 {
 
@@ -207,11 +233,6 @@ static void checkRotate(rotate_config_t *config, rotate_status_t *status)
     else if (status->checkReason == CHECK_SIG_FORCE) {
         status->rotateReason = ROTATE_FORCE;
     }
-    else if (config->tRotation) {
-        if (get_now(config) >= status->tLogEnd) {
-            status->rotateReason = ROTATE_TIME;
-        }
-    }
     else if (config->sRotation) {
         apr_finfo_t finfo;
         apr_off_t current_size = -1;
@@ -223,6 +244,16 @@ static void checkRotate(rotate_config_t *config, rotate_status_t *status)
         if (current_size > config->sRotation) {
             status->rotateReason = ROTATE_SIZE;
         }
+        else if (config->tRotation) {
+            if (get_now(config) >= status->tLogEnd) {
+                status->rotateReason = ROTATE_TIME;
+            }
+        }
+    }
+    else if (config->tRotation) {
+        if (get_now(config) >= status->tLogEnd) {
+            status->rotateReason = ROTATE_TIME;
+        }
     }
     else {
         fprintf(stderr, "No rotation time or size specified\n");
@@ -246,6 +277,17 @@ static void checkRotate(rotate_config_t *config, rotate_status_t *status)
     return;
 }
 
+/*
+ * Open a new log file, and if successful
+ * also close the old one.
+ *
+ * The timestamp for the calculation of the file
+ * name of the new log file will be the actual millisecond
+ * timestamp, except when a regular rotation based on a time
+ * interval is configured and the previous interval
+ * is over. Then the timestamp is the starting time
+ * of the actual interval.
+ */
 static void doRotate(rotate_config_t *config, rotate_status_t *status)
 {
 
@@ -343,7 +385,7 @@ static void doRotate(rotate_config_t *config, rotate_status_t *status)
 static void external_rotate(int signal)
 {
     /*
-     * Set marker for signal triggered rotation
+     * Set marker for signal triggered rotation check
      */
     if (signal == SIG_FORCE) {
         status.checkReason = CHECK_SIG_FORCE;
@@ -364,6 +406,61 @@ static void external_rotate(int signal)
 }
 #endif
 
+/*
+ * Get a size or time param from a string.
+ * Parameter 'last' indicates, whether the
+ * argument is the last commadnline argument.
+ * UTC offset is only allowed as a last argument
+ * in order to make is distinguishable from the
+ * rotation interval time.
+ */
+static const char *get_time_or_size(rotate_config_t *config,
+                                    const char *arg, int last) {
+    char *ptr = NULL;
+    /* Byte multiplier */
+    unsigned int mult = 1;
+    if ((ptr = strchr(arg, 'B')) != NULL) { /* Found KB size */
+        mult = 1;
+    }
+    else if ((ptr = strchr(arg, 'K')) != NULL) { /* Found KB size */
+        mult = 1024;
+    }
+    else if ((ptr = strchr(arg, 'M')) != NULL) { /* Found MB size */
+        mult = 1024 * 1024;
+    }
+    else if ((ptr = strchr(arg, 'G')) != NULL) { /* Found GB size */
+        mult = 1024 * 1024 * 1024;
+    }
+    if (ptr) { /* rotation based on file size */
+        if (config->sRotation > 0) {
+            return "Rotation size parameter allowed only once";
+        }
+        if (*(ptr+1) == '\0') {
+            config->sRotation = atoi(arg) * mult;
+        }
+        if (config->sRotation == 0) {
+            return "Invalid rotation size parameter";
+        }
+    }
+    else if ((config->sRotation > 0 || config->tRotation > 0) && last) {
+        /* rotation based on elapsed time */
+        if (config->use_localtime) {
+            return "UTC offset parameter is not valid with -l";
+        }
+        config->utc_offset = atoi(arg) * 60;
+    }
+    else { /* rotation based on elapsed time */
+        if (config->tRotation > 0) {
+            return "Rotation time parameter allowed only once";
+        }
+        config->tRotation = atoi(arg);
+        if (config->tRotation <= 0) {
+            return "Invalid rotation time parameter";
+        }
+    }
+    return NULL;
+}
+
 int main (int argc, const char * const argv[])
 {
     char buf[BUFSIZE];
@@ -373,7 +470,7 @@ int main (int argc, const char * const argv[])
     apr_status_t rv;
     char c;
     const char *optarg;
-    char *ptr = NULL;
+    const char *err = NULL;
 
     apr_app_initialize(&argc, &argv, NULL);
     atexit(apr_terminate);
@@ -415,37 +512,27 @@ int main (int argc, const char * const argv[])
         usage(argv[0], NULL /* specific error message already issued */ );
     }
 
-    if ((argc - opt->ind < 2) || (argc - opt->ind > 3) ) {
+    /*
+     * After the initial flags we need 2 to 4 arguments,
+     * the file name, either the rotation interval time or size
+     * or both of them, and optionally the UTC offset.
+     */
+    if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) {
         usage(argv[0], "Incorrect number of arguments");
     }
 
     config.szLogRoot = argv[opt->ind++];
 
-    ptr = strchr(argv[opt->ind], 'M');
-    if (ptr) { /* rotation based on file size */
-        if (*(ptr+1) == '\0') {
-            config.sRotation = atoi(argv[opt->ind]) * 1048576;
-        }
-        if (config.sRotation == 0) {
-            usage(argv[0], "Invalid rotation size parameter");
-        }
-    }
-    else { /* rotation based on elapsed time */
-        config.tRotation = atoi(argv[opt->ind]);
-        if (config.tRotation <= 0) {
-            usage(argv[0], "Invalid rotation time parameter");
-        }
-    }
-    opt->ind++;
-
-    if (opt->ind < argc) { /* have UTC offset */
-        if (config.use_localtime) {
-            usage(argv[0], "UTC offset parameter is not valid with -l");
+    /* Read in the remaining flags, namely time, size and UTC offset. */
+    for(; opt->ind < argc; opt->ind++) {
+        if ((err = get_time_or_size(&config, argv[opt->ind],
+                                    opt->ind < argc - 1 ? 0 : 1)) != NULL) {
+            usage(argv[0], err);
         }
-        config.utc_offset = atoi(argv[opt->ind]) * 60;
     }
 
     config.use_strftime = (strchr(config.szLogRoot, '%') != NULL);
+
     if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) {
         fprintf(stderr, "Unable to open stdin\n");
         exit(1);