From: Rainer Jung Date: Sun, 11 Jan 2009 22:45:53 +0000 (+0000) Subject: Allow size units B, K, M, G and combination of X-Git-Tag: 2.3.2~180 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=618c7592fc759ec3ca9b784894c4f40ea0ca087a;p=thirdparty%2Fapache%2Fhttpd.git Allow size units B, K, M, G and combination of 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 --- diff --git a/CHANGES b/CHANGES index 58450a721d3..fb8b90fc463 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 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 diff --git a/docs/man/rotatelogs.8 b/docs/man/rotatelogs.8 index b3a9888506c..42b98eb9fe2 100644 --- a/docs/man/rotatelogs.8 +++ b/docs/man/rotatelogs.8 @@ -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\&. diff --git a/docs/manual/programs/rotatelogs.xml b/docs/manual/programs/rotatelogs.xml index df2bd5bd2d6..29022f5a9c2 100644 --- a/docs/manual/programs/rotatelogs.xml +++ b/docs/manual/programs/rotatelogs.xml @@ -41,7 +41,7 @@ [ -f ] [ -v ] logfile - rotationtime|filesizeM + rotationtime|filesize(B|K|M|G) [ offset ]

@@ -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.) -
filesizeM
+
filesize(B|K|M|G)
-
The maximum file size in megabytes followed by the letter -M to specify size rather than time.
+
The maximum file size in followed by exactly one of the letters +B (Bytes), K (KBytes), M (MBytes) +or G (GBytes). +
+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. +
offset
diff --git a/support/rotatelogs.c b/support/rotatelogs.c index 8e602880745..64f7a24d8e0 100644 --- a/support/rotatelogs.c +++ b/support/rotatelogs.c @@ -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);