root/livinglogic.python.aplora/aplora.py @ 0:8bf1bc5d3dab

Revision 0:8bf1bc5d3dab, 4.3 KB (checked in by Walter Doerwald <walter@…>, 14 years ago)

New project: Logging Apache requests to Oracle.

Line 
1#!/usr/local/bin/python2.3
2# -*- coding: iso-8859-1 -*-
3
4## Copyright 2004/2005 by LivingLogic AG, Bayreuth/Germany.
5## Copyright 2004/2005 by Walter Dörwald
6##
7## All Rights Reserved
8##
9## Permission to use, copy, modify, and distribute this software and its documentation
10## for any purpose and without fee is hereby granted, provided that the above copyright
11## notice appears in all copies and that both that copyright notice and this permission
12## notice appear in supporting documentation, and that the name of LivingLogic AG or
13## the author not be used in advertising or publicity pertaining to distribution of the
14## software without specific, written prior permission.
15##
16## LIVINGLOGIC AG AND THE AUTHOR DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17## INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18## LIVINGLOGIC AG OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
19## DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20## IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21## IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23"""
24This script can be used with Apache's piped logging to log HTTP request
25to an Oracle database.
26"""
27
28__version__ = "$Revision$"[11:-1]
29
30
31import os, datetime, cgi, Cookie, urlparse
32
33
34class Logger(object):
35    def __init__(self, oracle, connect, procname):
36        os.environ["ORACLE_HOME"] = oracle
37        import cx_Oracle
38        self.cx_Oracle = cx_Oracle
39        db = cx_Oracle.connect(connect)
40        self.c = db.cursor()
41        self.connect = connect
42        self.procname = procname
43
44    def findcoid(self, path, query):
45        # Find Content-Object-ID in URL
46        coid = None
47        pos1 = path.find("_id_")
48        if pos1 >= 0:
49            pos2 = path.find("_", pos1+4)
50            if pos2 >= 0:
51                coid = path[pos1+4:pos2]
52   
53        # Retry with a query parameter
54        if coid is None and query:
55            query = query[1:] # drop the ?
56            query = cgi.parse_qs(query)
57            if "id" in query:
58                coid = query["id"][0]
59        return coid
60   
61    def findsession(self, sessionin, sessionout, path):
62        if sessionout and sessionout != "-":
63            cookie = Cookie.SimpleCookie()
64            cookie.load(sessionout)
65            if "JSESSIONID" in cookie:
66                return cookie["JSESSIONID"].value
67        (scheme, server, path, params, query, frag) = urlparse.urlparse(path)
68        if params.startswith("jsessionid="):
69            return params[11:]
70        if sessionin and sessionin != "-":
71            return sessionin
72        return None
73
74    def run(self, stream):
75        while True:
76            line = stream.readline()
77            fields = [field.decode("string-escape").encode("latin-1") for field in line.rstrip("\n").split("\t")]
78
79            field = iter(fields)
80            instance = field.next()
81            try:
82                reqstart = int(field.next())
83            except ValueError:
84                reqstart = None
85            else:
86                reqstart = datetime.datetime.fromtimestamp(reqstart)
87            reqtime = 1e-6*float(field.next())
88            client = field.next()
89            useragent = field.next()
90            path = field.next()
91            query = field.next()
92            method = field.next()
93            status = int(field.next())
94            bytesin = int(field.next())
95            bytesout = int(field.next())
96            bytesbodyout = int(field.next())
97            referer = field.next()
98            contenttype = field.next()
99            sessionin = field.next()
100            sessionout = field.next()
101   
102            reqstart = self.cx_Oracle.Timestamp(reqstart.year, reqstart.month, reqstart.day, reqstart.hour, reqstart.minute, reqstart.second)
103   
104            (mimetype, options) = cgi.parse_header(contenttype)
105            charset = options.get("charset", None)
106   
107            data = [
108                reqstart,
109                reqtime,
110                instance,
111                client,
112                useragent,
113                path+query,
114                method,
115                status,
116                bytesin,
117                bytesout,
118                bytesbodyout,
119                None, #req.content_encoding,
120                mimetype,
121                charset,
122                referer,
123                self.findsession(sessionin, sessionout, path),
124                self.findcoid(path, query),
125            ]
126            self.c.callproc(self.procname, data)
127
128
129if __name__ == "__main__":
130    import sys, optparse
131    p = optparse.OptionParser(usage="usage: %prog [options]", version="%%prog %s" % __version__)
132    p.add_option("-o", "--oracle", dest="oracle", help="Value for ORACLE_HOME", default="/oracle/Client")
133    p.add_option("-c", "--connect", dest="connect", help="Oracle connect string", default=None)
134    p.add_option("-p", "--procname", dest="procname", help="Name of insert procedure", default="log_insert")
135    (options, args) = p.parse_args()
136    logger = Logger(oracle=options.oracle, connect=options.connect, procname=options.procname)
137    logger.run(sys.stdin)
Note: See TracBrowser for help on using the browser.