#!/usr/bin/env python # # pythonolog.py - version 1.0 # # A log creation script similar to cronolog but also supports mass vhosting # as described at http://httpd.apache.org/docs/2.0/vhosts/mass.html # # Use this script from Apache like: # # CustomLog "|/path/to/pythonolog.py strftime-spec" [format] # # See 'man strftime' for possible options. Additionally %VHOST # can be used if the first field of the log line is the virtual host. # # For example: # # LogFormat "%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined # CustomLog "|/path/to/pythonolog.py /my/logs/%Y/%m-%d-%VHOST-access_log" combined # # The vhost data is stripped from the resulting logfile. # Any directories that do not exist are created automatically. # # Report bugs to Viraj Alankar import time import sys import os import getopt import re MAXOPEN = 10 logfile = None format = sys.argv[1] want_vhost = format.count('%VHOST') class Logfiles: def __init__(self): self.logs = {} def close_oldest_log(self): oldest = '' for log in self.logs: if not oldest or self.logs[log]['lastused'] < self.logs[oldest]['lastused']: oldest = log if oldest: del self.logs[oldest] def openlog(self, filename): # Make directory if it doesn't exist if filename.count('/'): try: os.makedirs(os.path.dirname(filename)) except OSError: pass self.logs[filename] = {} self.logs[filename]['fileobj'] = open(filename, 'a') self.logs[filename]['lastused'] = 0 def getlog(self, filename): if filename not in self.logs: # Open a new logfile if len(self.logs) >= MAXOPEN: self.close_oldest_log() self.openlog(filename) return self.logs[filename] def write(self, filename, line): output = self.getlog(filename) output['fileobj'].write(line) output['fileobj'].flush() output['lastused'] = time.time() logs = Logfiles() while True: useformat = format line = sys.stdin.readline() if not line: break # Virtualhost parsing if want_vhost: vhost = line.split()[0] line = re.sub(r'^%s\s+' % vhost, '', line) useformat = re.sub(r'%VHOST', vhost, format) filename = time.strftime(useformat) logs.write(filename, line)