Hello! I have a setup where logfiles etc. are periodically transferred (rsynced) over a network-link at runtime, and disk space as well as transfer time/bandwidth are relevant.
I didn't find a gzipping filter for APR, and didn't want to implement yet another specialized gzip-implementation like mod_deflate for it, so I took rotatelogs and converted it to use zlib, stripping some unneeded and (in this setup) hard-to-support functionality as well. It might be useful to someone else, so please find it attached for inclusion. I hereby place it under the Apache License 2.0 and transfer all relevant rights to the Apache Software Foundation. Best regards, Andreas -- "God is a comedian playing to an audience too afraid to laugh." -- H.L.Mencken
diff -Nur rotatelogz.orig/Makefile rotatelogz/Makefile
--- rotatelogz.orig/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ rotatelogz/Makefile 2007-04-16 15:41:55.000000000 +0200
@@ -0,0 +1,10 @@
+CC ?= gcc
+LDFLAGS += -lz
+
+all: rotatelogz
+
+install: rotatelogz
+ install -m 755 rotatelogz $(DESTDIR)${prefix}/bin/rotatelogz
+
+clean:
+ rm rotatelogz *~
diff -Nur rotatelogz.orig/rotatelogz.c rotatelogz/rotatelogz.c
--- rotatelogz.orig/rotatelogz.c 1970-01-01 01:00:00.000000000 +0100
+++ rotatelogz/rotatelogz.c 2007-04-16 14:44:00.000000000 +0200
@@ -0,0 +1,246 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Simple program to rotate Apache logs without having to kill the server.
+ *
+ * Contributed by Ben Laurie <ben algroup.co.uk>
+ * Ported to APR by Mladen Turk <mturk mappingsoft.com>
+ *
+ * 2007-04-16
+ *
+ * Heavily modified by Andreas Kotes <count flatline.de>
+ * - Removed APR again
+ * - Removed localtime-support
+ * - Removed filesize-support
+ * - Removed strftime-support for logfile names
+ * - Changed file handling to always use zlib with maximum compression
+ * - Added signal handler so files are closed on forced exit
+ * - Dropped file truncation on errors
+ * - Copy previous file if file exists on startup
+ * (this has the penalty to block shortly on startup!)
+ * - Tested on Linux only
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <zlib.h>
+
+#define BUFSIZE 65536
+#define ERRMSGSZ 128
+
+#ifndef MAX_PATH
+#define MAX_PATH 1024
+#endif
+
+gzFile nLogFD = NULL;
+void termination_handler (int signum) {
+ gzclose(nLogFD);
+}
+
+int main (int argc, const char * const argv[])
+{
+ char buf[BUFSIZE], filename[MAX_PATH], oldfilename[MAX_PATH],
errbuf[ERRMSGSZ];
+ int tLogEnd = 0, tRotation = 0;
+ int nMessCount = 0;
+ size_t nRead, nWrite;
+ int use_strftime = 0;
+ int now = 0;
+ const char *szLogRoot;
+ int f_stdin;
+ gzFile nLogFDprev = NULL;
+ gzFile nLogFDold = NULL;
+ char *ptr = NULL;
+ int argBase = 0;
+ int argFile = 1;
+ int argIntv = 2;
+ int argOffset = 3;
+ struct sigaction new_action, old_action;
+ struct stat statbuf;
+
+ if (argc < (argBase + 3) || argc > (argBase + 4)) {
+ fprintf(stderr,
+ "Usage: %s <logfile> <rotation time in seconds> "
+ "[offset minutes from UTC]\n\n",
+ argv[0]);
+ fprintf(stderr,
+ "Add this:\n\nTransferLog \"|%s.exe /some/where 86400\"\n\n",
+ argv[0]);
+ fprintf(stderr,
+ "to httpd.conf. The generated name will be /some/where.nnnn "
+ "where nnnn is the\nsystem time at which the log nominally "
+ "starts (N.B. if using a rotation time,\nthe time will always "
+ "be a multiple of the rotation time, so you can synchronize\n"
+ "cron scripts with it). At the end of each rotation time or "
+ "when the file size\nis reached a new log is started.\n");
+ exit(1);
+ }
+
+ szLogRoot = argv[argFile];
+
+ tRotation = atoi(argv[argIntv]);
+ if (tRotation <= 0) {
+ fprintf(stderr, "Rotation time must be > 0\n");
+ exit(6);
+ }
+
+ use_strftime = (strchr(szLogRoot, '%') != NULL);
+ f_stdin = fileno(stdin);
+ if (f_stdin < 0) {
+ perror("Unable to work with stdin");
+ exit(1);
+ }
+
+ /* Close logfile correctly when being killed */
+ new_action.sa_handler = termination_handler;
+ sigemptyset (&new_action.sa_mask);
+ new_action.sa_flags = 0;
+ sigaction (SIGINT, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction (SIGINT, &new_action, NULL);
+ sigaction (SIGHUP, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction (SIGHUP, &new_action, NULL);
+ sigaction (SIGTERM, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction (SIGTERM, &new_action, NULL);
+
+ for (;;) {
+ nRead = sizeof(buf);
+ nRead = read(f_stdin, buf, nRead);
+ if (nRead == -1) {
+ exit(3);
+ }
+ if (tRotation) {
+ now = (int)time(NULL);
+ if (nLogFD != NULL && now >= tLogEnd) {
+ nLogFDprev = nLogFD;
+ nLogFD = NULL;
+ }
+ }
+ else {
+ fprintf(stderr, "No rotation time specified\n");
+ exit(2);
+ }
+
+ if (nLogFD == NULL) {
+ int tLogStart;
+ if (tRotation) {
+ tLogStart = (now / tRotation) * tRotation;
+ }
+ else {
+ tLogStart = (int)time(NULL);
+ }
+
+ sprintf(filename, "%s.%010d.gz", szLogRoot, tLogStart);
+ tLogEnd = tLogStart + tRotation;
+
+ /* test for file existence, and copy the contents, if necessary */
+ if ((stat(filename,&statbuf) == 0) && statbuf.st_size) {
+ sprintf(oldfilename, "%s.%010d.gz.old", szLogRoot, tLogStart);
+ if (rename(filename,oldfilename) == -1) {
+ /* silently ignore problems */
+ nLogFD = gzopen(filename,"wb9");
+ } else {
+ nLogFD = gzopen(filename,"wb9");
+ if (nLogFD == NULL) {
+ char error[120];
+ strerror_r(errno, error, sizeof error);
+ fprintf(stderr, "Could not open new log file '%s' (%s)
during copy.\n", filename, error);
+ exit(2);
+ }
+ nLogFDold = gzopen(oldfilename,"rb");
+ if (nLogFDold == NULL) {
+ char error[120];
+ strerror_r(errno, error, sizeof error);
+ fprintf(stderr, "Could not open old log file '%s' (%s)
during copy.\n", oldfilename, error);
+ /* continue with regular logging in this case */
+ } else {
+ char copybuf[BUFSIZE];
+ int bytes;
+ while (!gzeof(nLogFDold)) {
+ bytes = gzread(nLogFDold,copybuf,BUFSIZE);
+ if (bytes)
+ if (gzwrite(nLogFD,copybuf,bytes) != bytes)
+ exit(2);
+ }
+ gzclose(nLogFDold);
+ nLogFDold=NULL;
+ unlink(oldfilename);
+ }
+ }
+ } else {
+ nLogFD = gzopen(filename,"wb9");
+ }
+ if (nLogFD == NULL) {
+ char error[120];
+
+ strerror_r(errno, error, sizeof error);
+
+ /* Uh-oh. Failed to open the new log file. Try to clear
+ * the previous log file, note the lost log entries,
+ * and keep on truckin'. */
+ if (nLogFDprev == NULL) {
+ fprintf(stderr, "Could not open log file '%s' (%s)\n",
filename, error);
+ exit(2);
+ }
+ else {
+ nLogFD = nLogFDprev;
+ /* Try to keep this error message constant length
+ * in case it occurs several times. */
+ snprintf(errbuf, sizeof errbuf,
+ "Continuing log file due to error opening "
+ "new log file, %10d messages lost:
%-25.25s\n",
+ nMessCount, error);
+ nWrite = strlen(errbuf);
+ if (gzwrite(nLogFD, errbuf, nWrite) != nWrite) {
+ fprintf(stderr, "Error writing to the file %s\n",
filename);
+ exit(2);
+ }
+ }
+ }
+ else if (nLogFDprev) {
+ gzclose(nLogFDprev);
+ }
+ nMessCount = 0;
+ }
+ nWrite = nRead;
+ if (gzwrite(nLogFD, buf, nWrite) != nRead) {
+ nMessCount++;
+ sprintf(errbuf,
+ "Error writing to log file. "
+ "%10d messages lost.\n",
+ nMessCount);
+ nWrite = strlen(errbuf);
+ if (gzwrite(nLogFD, errbuf, nWrite) != nWrite) {
+ fprintf(stderr, "Error writing to the file %s\n", filename);
+ exit(2);
+ }
+ }
+ else {
+ nMessCount++;
+ }
+ }
+ /* Of course we never, but prevent compiler warnings */
+ return 0;
+}
signature.asc
Description: Digital signature
