]> granicus.if.org Git - apache/commitdiff
Allow to trigger rotatelogs log file rotation from
authorRainer Jung <rjung@apache.org>
Sun, 11 Jan 2009 17:36:07 +0000 (17:36 +0000)
committerRainer Jung <rjung@apache.org>
Sun, 11 Jan 2009 17:36:07 +0000 (17:36 +0000)
using HUP and INT signals to the rotatelogs process.

This is helpful, when log activity is low, but you want
rotatelogs to close the open log files.

SIGHUP triggers checking the rules given during startup,
SIGINT forces rotate independently form those rules.

When the signal triggers a rotation, the open file
is closed immediately. The new file is opened when
new log data arrives, or in case "-f" was given it
is opened immediately.

Based on my patch in BZ 44427.

Note on Windows: The new functionality is undefined when
SIGHUP or SIGINT are not available. Does the use case
make sense on Windows? If so, which signals should we use?

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@733493 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 09c23071ebdfa46881764c4d62612fa34b773205..464c8a3263dee1ae3723b384704eafa674b77076 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 to trigger log file rotation from outside
+    using HUP and INT signals. PR 44427 [Rainer Jung]
+
  *) mod_ssl: Fix merging of SSLRenegBufferSize directive. PR 46508
     [<tlhackque yahoo.com>]
 
index 156224edbcd3484fdc8ea4e74f656522881e8e54..ee89afd2c63185fe3080fa9e6cfe7b7e22646428 100644 (file)
@@ -33,7 +33,7 @@ rotatelogs \- Piped logging program to rotate Apache logs
 .SH "SUMMARY"
  
 .PP
-rotatelogs is a simple program for use in conjunction with Apache's piped logfile feature\&. It supports rotation based on a time interval or maximum size of the log\&.
+rotatelogs is a simple program for use in conjunction with Apache's piped logfile feature\&. It supports rotation based on a time interval or maximum size of the log\&. Rotation happens automatically during log activity, but can also be triggered externally with the signals SIGHUP (checks the configured rotation rules) and SIGINT (force rotate)\&.
  
 
 .SH "OPTIONS"
index 68214dff0efb4e71f3d2c14796638e5e1330d38d..7d2bf30ca0a275c714fd35fe908ff8ff683e5d40 100644 (file)
 <summary>
      <p><code>rotatelogs</code> is a simple program for use in
      conjunction with Apache's piped logfile feature.  It supports
-     rotation based on a time interval or maximum size of the log.</p>
+     rotation based on a time interval or maximum size of the log.
+     Rotation happens automatically during log activity, but can also
+     be triggered externally with the signals SIGHUP (checks the
+     configured rotation rules) and SIGINT (force rotate).</p>
 </summary>
 
 <section id="synopsis"><title>Synopsis</title>
index 4ba339ec63248a7742a326501b149dcd615bfd62..83ae6ceaae0687cd0d873b39b5df5c74877c1e76 100644 (file)
@@ -46,6 +46,7 @@
 #include "apr_general.h"
 #include "apr_time.h"
 #include "apr_getopt.h"
+#include "apr_signal.h"
 
 #if APR_HAVE_STDLIB_H
 #include <stdlib.h>
 #define MAX_PATH        1024
 #endif
 
+#ifdef SIGHUP
+#ifdef SIGINT
+#define HAVE_SIGNALS    1
+#define SIG_CHECK       SIGHUP
+#define SIG_FORCE       SIGINT
+#endif
+#endif
+
+#define REASON_LOG      0
+#define REASON_CHECK    1
+#define REASON_FORCE    2
+
 typedef struct rotate_config rotate_config_t;
 
 struct rotate_config {
@@ -87,6 +100,7 @@ struct rotate_status {
     char filename[MAX_PATH];
     char errbuf[ERRMSGSZ];
     int needsRotate;
+    int reason;
     int tLogEnd;
     int now;
     int nMessCount;
@@ -141,11 +155,23 @@ static int get_now(int use_localtime, int utc_offset)
     return (int)apr_time_sec(tNow) + utc_offset;
 }
 
+void closeFile(apr_pool_t *pool, apr_file_t *file) {
+    if (file != NULL) {
+        apr_file_close(file);
+        if (pool) {
+            apr_pool_destroy(pool);
+        }
+    }
+}
+
 void checkRotate(rotate_config_t *config, rotate_status_t *status) {
 
     if (status->nLogFD == NULL) {
         status->needsRotate = 1;
     }
+    else if (status->reason == REASON_FORCE) {
+        status->needsRotate = 1;
+    }
     else if (config->tRotation) {
         status->now = get_now(config->use_localtime, config->utc_offset);
         if (status->now >= status->tLogEnd) {
@@ -169,6 +195,16 @@ void checkRotate(rotate_config_t *config, rotate_status_t *status) {
         exit(2);
     }
 
+    /*
+     * Let's close the file before immediately
+     * if we got here via a signal.
+     */
+    if (status->needsRotate &&
+        (status->reason != REASON_LOG)) {
+        closeFile(status->pfile, status->nLogFD);
+        status->nLogFD = NULL;
+        status->pfile = NULL;
+    }
     return;
 }
 
@@ -184,8 +220,18 @@ void doRotate(rotate_config_t *config, rotate_status_t *status) {
 
     status->now = get_now(config->use_localtime, config->utc_offset);
     if (config->tRotation) {
+        int tLogEnd;
         tLogStart = (status->now / config->tRotation) * config->tRotation;
-        status->tLogEnd = tLogStart + config->tRotation;
+        tLogEnd = tLogStart + config->tRotation;
+        /*
+         * Check if rotation was forced and the last rotation
+         * interval is not yet over. Use the value of now instead
+         * of the time interval boundary for the file name then.
+         */
+        if ((status->reason == REASON_FORCE) && (tLogStart < status->tLogEnd)) {
+            tLogStart = status->now;
+        }
+        status->tLogEnd = tLogEnd;
     }
     else {
         tLogStart = status->now;
@@ -236,15 +282,45 @@ void doRotate(rotate_config_t *config, rotate_status_t *status) {
             }
         }
     }
-    else if (status->nLogFDprev) {
-        apr_file_close(status->nLogFDprev);
-        if (status->pfile_prev) {
-            apr_pool_destroy(status->pfile_prev);
-            status->pfile_prev = NULL;
-        }
+    else {
+        closeFile(status->pfile_prev, status->nLogFDprev);
+        status->nLogFDprev = NULL;
+        status->pfile_prev = NULL;
     }
     status->nMessCount = 0;
+    /*
+     * Reset marker for signal triggered rotation
+     */
+    status->reason = REASON_LOG;
+}
+
+#ifdef HAVE_SIGNALS
+/*
+ * called on SIG_CHECK and SIG_FORCE
+ */
+static void external_rotate(int signal)
+{
+    /*
+     * Set marker for signal triggered rotation
+     */
+    if (signal == SIG_FORCE) {
+        status.reason = REASON_FORCE;
+    }
+    else {
+        status.reason = REASON_CHECK;
+    }
+    /*
+     * Close old file conditionally
+     */
+    checkRotate(&config, &status);
+    /*
+     * Open new file if force flag was set
+     */
+    if (config.force_open && status.needsRotate) {
+        doRotate(&config, &status);
+    }
 }
+#endif
 
 int main (int argc, const char * const argv[])
 {
@@ -273,6 +349,7 @@ int main (int argc, const char * const argv[])
     status.nLogFDprev = NULL;
     status.tLogEnd = 0;
     status.needsRotate = 0;
+    status.reason = REASON_LOG;
     status.now = 0;
     status.nMessCount = 0;
 
@@ -337,9 +414,23 @@ int main (int argc, const char * const argv[])
         doRotate(&config, &status);
     }
 
+#ifdef HAVE_SIGNALS
+    apr_signal(SIG_CHECK, external_rotate);
+    apr_signal(SIG_FORCE, external_rotate);
+#endif
+
     for (;;) {
         nRead = sizeof(buf);
-        if (apr_file_read(f_stdin, buf, &nRead) != APR_SUCCESS) {
+#ifdef HAVE_SIGNALS
+        apr_signal_unblock(SIG_CHECK);
+        apr_signal_unblock(SIG_FORCE);
+#endif
+        rv = apr_file_read(f_stdin, buf, &nRead);
+#ifdef HAVE_SIGNALS
+        apr_signal_block(SIG_FORCE);
+        apr_signal_block(SIG_CHECK);
+#endif
+        if (rv != APR_SUCCESS) {
             exit(3);
         }
         checkRotate(&config, &status);