From d73d0412d567722dbe5ba4fb9e86b18839b9f0f2 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Sun, 11 Jan 2009 17:36:07 +0000 Subject: [PATCH] Allow to trigger rotatelogs log file rotation from 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 | 3 + docs/man/rotatelogs.8 | 2 +- docs/manual/programs/rotatelogs.xml | 5 +- support/rotatelogs.c | 107 +++++++++++++++++++++++++--- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 09c23071eb..464c8a3263 100644 --- 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 [] diff --git a/docs/man/rotatelogs.8 b/docs/man/rotatelogs.8 index 156224edbc..ee89afd2c6 100644 --- a/docs/man/rotatelogs.8 +++ b/docs/man/rotatelogs.8 @@ -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" diff --git a/docs/manual/programs/rotatelogs.xml b/docs/manual/programs/rotatelogs.xml index 68214dff0e..7d2bf30ca0 100644 --- a/docs/manual/programs/rotatelogs.xml +++ b/docs/manual/programs/rotatelogs.xml @@ -28,7 +28,10 @@

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 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).

Synopsis diff --git a/support/rotatelogs.c b/support/rotatelogs.c index 4ba339ec63..83ae6ceaae 100644 --- a/support/rotatelogs.c +++ b/support/rotatelogs.c @@ -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 @@ -64,6 +65,18 @@ #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); -- 2.50.1