From 3e6606d082cb9896591123f3fa7a9c80921436e6 Mon Sep 17 00:00:00 2001 From: Adrian Lienhard Date: Tue, 31 May 2011 11:56:28 +0200 Subject: [PATCH] Added support for proxy server and for speeding up the replay. Refactored and cleaned up the code and added option parsing. Added a readme file. --- README.md | 24 +++++++++++ apache-log-replay.py | 97 +++++++++++++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba76760 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Script to replay HTTP requests from an Apache access logfile + +Features + +- Takes the time between requests into account +- Replaying can be sped up by a given factor +- Optionally send all requests to a selected (proxy) server + +## Installation + +Requires Python >= 2.6 + +Simply download the file and execute it... + +## Usage + + Usage: apache-log-replay.py [options] logfile + + Options: + -h, --help show this help message and exit + -p PROXY, --proxy=PROXY + send requests to server PROXY + -s SPEEDUP, --speedup=SPEEDUP + make time run faster by factor SPEEDUP \ No newline at end of file diff --git a/apache-log-replay.py b/apache-log-replay.py index e55bb1d..888b1ec 100755 --- a/apache-log-replay.py +++ b/apache-log-replay.py @@ -1,49 +1,88 @@ -#!/usr/bin/env python2.5 -from datetime import datetime +"""Replay requests from an HTTP access log file. + +- Takes time between requests into account, with option to speed up the replay. +- Allows one to send all requests to a selected server (proxy). +""" + import sys import time -from urllib2 import urlopen +import urllib2 +from datetime import datetime +from optparse import OptionParser -def main(host, filename): - logfile = open(filename, "r") - requests = [] - for line in logfile: - parts = line.split(" ") - if len(parts) != 24: - continue - time_text = parts[3][1:] - request_time = datetime.strptime(time_text, "%d/%b/%Y:%H:%M:%S") - path = parts[6] - requests.append((request_time, path)) - if not requests: - print "Seems like I don't know how to parse this file!" - return +# Constants that specify access log format (indices +# specify position after splitting on spaces) +HOST_INDEX = 0 +TIME_INDEX = 3 +PATH_INDEX = 6 + +def main(filename, proxy, speedup=1): + """Setup and start replaying.""" + requests = _parse_logfile(filename) + _setup_http_client(proxy) + _replay(requests, speedup) +def _replay(requests, speedup): + """Replay the requests passed as argument""" total_delta = requests[-1][0] - requests[0][0] print "%d requests to go (time: %s)" % (len(requests), total_delta) last_time = requests[0][0] - for request_time, path in requests: - time_delta = request_time - last_time + for request_time, host, path in requests: + time_delta = (request_time - last_time) // speedup if time_delta: - if time_delta.seconds > 10: + if time_delta and time_delta.seconds > 10: print "(next request in %d seconds)" % time_delta.seconds time.sleep(time_delta.seconds) last_time = request_time - url = host + path + url = "http://" + host + path try: req_result = "OK" - urlopen(url) + urllib2.urlopen(url) except Exception: req_result = "FAILED" print ("[%s] REQUEST: %s -- %s" - % (request_time.strftime("%H:%M:%S"), url, req_result)) + % (request_time.strftime("%H:%M:%S"), url, req_result)) -def usage(): - print "%s " % sys.argv[0] +def _setup_http_client(proxy): + """Configure proxy server and install HTTP opener""" + proxy_config = {'http': proxy} if proxy else {} + proxy_handler = urllib2.ProxyHandler(proxy_config) + opener = urllib2.build_opener(proxy_handler) + urllib2.install_opener(opener) +def _parse_logfile(filename): + """Parse the logfile and return a list with tuples of the form + (, , ) + """ + logfile = open(filename, "r") + requests = [] + for line in logfile: + parts = line.split(" ") + time_text = parts[TIME_INDEX][1:] + request_time = datetime.strptime(time_text, "%d/%b/%Y:%H:%M:%S") + host = parts[HOST_INDEX] + path = parts[PATH_INDEX] + requests.append((request_time, host, path)) + if not requests: + print "Seems like I don't know how to parse this file!" + return requests + if __name__ == "__main__": - if not len(sys.argv) == 3: - usage() + """Parse command line options.""" + usage = "usage: %prog [options] logfile" + parser = OptionParser(usage) + parser.add_option('-p', '--proxy', + help='send requests to server PROXY', + dest='proxy', + default=None) + parser.add_option('-s', '--speedup', + help='make time run faster by factor SPEEDUP', + dest='speedup', + type='int', + default=1) + (options, args) = parser.parse_args() + if len(args) == 1: + main(args[0], options.proxy, options.speedup) else: - main(sys.argv[1], sys.argv[2]) - + parser.error("incorrect number of arguments") + \ No newline at end of file