blob: cb0c24293030270cb877330acc858081b52da695 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum4e8aef81994-01-07 10:53:41 +00002
3# Extract statistics from ftp daemon log.
4
5# Usage:
6# ftpstats [-m maxitems] [-s search] [file]
7# -m maxitems: restrict number of items in "top-N" lists, default 25.
8# -s string: restrict statistics to lines containing this string.
Andrew M. Kuchling0ec0b722004-07-17 14:44:17 +00009# Default file is /usr/adm/ftpd; a "-" means read standard input.
Guido van Rossum4e8aef81994-01-07 10:53:41 +000010
11# The script must be run on the host where the ftp daemon runs.
12# (At CWI this is currently buizerd.)
13
14import os
15import sys
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000016import re
Guido van Rossum4e8aef81994-01-07 10:53:41 +000017import string
18import getopt
19
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000020pat = '^([a-zA-Z0-9 :]*)!(.*)!(.*)!([<>].*)!([0-9]+)!([0-9]+)$'
21prog = re.compile(pat)
Guido van Rossum4e8aef81994-01-07 10:53:41 +000022
23def main():
Tim Peterse6ddc8b2004-07-18 05:56:09 +000024 maxitems = 25
25 search = None
26 try:
27 opts, args = getopt.getopt(sys.argv[1:], 'm:s:')
Guido van Rossumb940e112007-01-10 16:19:56 +000028 except getopt.error as msg:
Collin Winter6f2df4d2007-07-17 20:59:35 +000029 print(msg)
30 print('usage: ftpstats [-m maxitems] [file]')
Tim Peterse6ddc8b2004-07-18 05:56:09 +000031 sys.exit(2)
32 for o, a in opts:
33 if o == '-m':
34 maxitems = string.atoi(a)
35 if o == '-s':
36 search = a
37 file = '/usr/adm/ftpd'
38 if args: file = args[0]
39 if file == '-':
40 f = sys.stdin
41 else:
42 try:
43 f = open(file, 'r')
Guido van Rossumb940e112007-01-10 16:19:56 +000044 except IOError as msg:
Collin Winter6f2df4d2007-07-17 20:59:35 +000045 print(file, ':', msg)
Tim Peterse6ddc8b2004-07-18 05:56:09 +000046 sys.exit(1)
47 bydate = {}
48 bytime = {}
49 byfile = {}
50 bydir = {}
51 byhost = {}
52 byuser = {}
53 bytype = {}
54 lineno = 0
55 try:
56 while 1:
57 line = f.readline()
58 if not line: break
59 lineno = lineno + 1
60 if search and string.find(line, search) < 0:
61 continue
62 if prog.match(line) < 0:
Collin Winter6f2df4d2007-07-17 20:59:35 +000063 print('Bad line', lineno, ':', repr(line))
Tim Peterse6ddc8b2004-07-18 05:56:09 +000064 continue
65 items = prog.group(1, 2, 3, 4, 5, 6)
66 (logtime, loguser, loghost, logfile, logbytes,
67 logxxx2) = items
68## print logtime
69## print '-->', loguser
70## print '--> -->', loghost
71## print '--> --> -->', logfile
72## print '--> --> --> -->', logbytes
73## print '--> --> --> --> -->', logxxx2
74## for i in logtime, loghost, logbytes, logxxx2:
75## if '!' in i: print '???', i
76 add(bydate, logtime[-4:] + ' ' + logtime[:6], items)
77 add(bytime, logtime[7:9] + ':00-59', items)
78 direction, logfile = logfile[0], logfile[1:]
79 # The real path probably starts at the last //...
80 while 1:
81 i = string.find(logfile, '//')
82 if i < 0: break
83 logfile = logfile[i+1:]
84 add(byfile, logfile + ' ' + direction, items)
85 logdir = os.path.dirname(logfile)
86## logdir = os.path.normpath(logdir) + '/.'
87 while 1:
88 add(bydir, logdir + ' ' + direction, items)
89 dirhead = os.path.dirname(logdir)
90 if dirhead == logdir: break
91 logdir = dirhead
92 add(byhost, loghost, items)
93 add(byuser, loguser, items)
94 add(bytype, direction, items)
95 except KeyboardInterrupt:
Collin Winter6f2df4d2007-07-17 20:59:35 +000096 print('Interrupted at line', lineno)
Tim Peterse6ddc8b2004-07-18 05:56:09 +000097 show(bytype, 'by transfer direction', maxitems)
98 show(bydir, 'by directory', maxitems)
99 show(byfile, 'by file', maxitems)
100 show(byhost, 'by host', maxitems)
101 show(byuser, 'by user', maxitems)
102 showbar(bydate, 'by date')
103 showbar(bytime, 'by time of day')
Guido van Rossum4e8aef81994-01-07 10:53:41 +0000104
105def showbar(dict, title):
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000106 n = len(title)
Benjamin Petersond7b03282008-09-13 15:58:53 +0000107 print('='*((70-n)//2), title, '='*((71-n)//2))
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000108 list = []
Skip Montanaro1e8ce582007-08-06 21:07:53 +0000109 for key in sorted(dict.keys()):
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000110 n = len(str(key))
111 list.append((len(dict[key]), key))
112 maxkeylength = 0
113 maxcount = 0
114 for count, key in list:
115 maxkeylength = max(maxkeylength, len(key))
116 maxcount = max(maxcount, count)
117 maxbarlength = 72 - maxkeylength - 7
118 for count, key in list:
119 barlength = int(round(maxbarlength*float(count)/maxcount))
120 bar = '*'*barlength
Collin Winter6f2df4d2007-07-17 20:59:35 +0000121 print('%5d %-*s %s' % (count, maxkeylength, key, bar))
Guido van Rossum4e8aef81994-01-07 10:53:41 +0000122
123def show(dict, title, maxitems):
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000124 if len(dict) > maxitems:
125 title = title + ' (first %d)'%maxitems
126 n = len(title)
Benjamin Petersond7b03282008-09-13 15:58:53 +0000127 print('='*((70-n)//2), title, '='*((71-n)//2))
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000128 list = []
Skip Montanaro1e8ce582007-08-06 21:07:53 +0000129 for key in dict.keys():
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000130 list.append((-len(dict[key]), key))
131 list.sort()
132 for count, key in list[:maxitems]:
Collin Winter6f2df4d2007-07-17 20:59:35 +0000133 print('%5d %s' % (-count, key))
Guido van Rossum4e8aef81994-01-07 10:53:41 +0000134
135def add(dict, key, item):
Collin Winter6f2df4d2007-07-17 20:59:35 +0000136 if key in dict:
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000137 dict[key].append(item)
138 else:
139 dict[key] = [item]
Guido van Rossum4e8aef81994-01-07 10:53:41 +0000140
Johannes Gijsbers7a8c43e2004-09-11 16:34:35 +0000141if __name__ == "__main__":
142 main()