blob: 9c643fe51efa55c9a547c2eaf2b0368d94458f73 [file] [log] [blame]
Guido van Rossum4e8aef81994-01-07 10:53:41 +00001#! /usr/local/bin/python
2
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.
9# Default file is /usr/adm/ftpd; a "-" means read stdandard input.
10
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
16import regex
17import string
18import getopt
19
20pat = '^\([a-zA-Z0-9 :]*\)!\(.*\)!\(.*\)!\([<>].*\)!\([0-9]+\)!\([0-9]+\)$'
21prog = regex.compile(pat)
22
23def main():
24 maxitems = 25
25 search = None
26 try:
27 opts, args = getopt.getopt(sys.argv[1:], 'm:s:')
28 except getopt.error, msg:
29 print msg
30 print 'usage: ftpstats [-m maxitems] [file]'
31 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')
44 except IOError, msg:
45 print file, ':', msg
46 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:
63 print 'Bad line', lineno, ':', `line`
64 continue
65 items = prog.group(1, 2, 3, 4, 5, 6)
66 logtime, loguser, loghost, logfile, logbytes, logxxx2 = items
67## print logtime
68## print '-->', loguser
69## print '--> -->', loghost
70## print '--> --> -->', logfile
71## print '--> --> --> -->', logbytes
72## print '--> --> --> --> -->', logxxx2
73## for i in logtime, loghost, logbytes, logxxx2:
74## if '!' in i: print '???', i
75 add(bydate, logtime[-4:] + ' ' + logtime[:6], items)
76 add(bytime, logtime[7:9] + ':00-59', items)
77 direction, logfile = logfile[0], logfile[1:]
78 # The real path probably starts at the last //...
79 while 1:
80 i = string.find(logfile, '//')
81 if i < 0: break
82 logfile = logfile[i+1:]
83 add(byfile, logfile + ' ' + direction, items)
84 logdir = os.path.dirname(logfile)
85## logdir = os.path.normpath(logdir) + '/.'
86 while 1:
87 add(bydir, logdir + ' ' + direction, items)
88 dirhead = os.path.dirname(logdir)
89 if dirhead == logdir: break
90 logdir = dirhead
91 add(byhost, loghost, items)
92 add(byuser, loguser, items)
93 add(bytype, direction, items)
94 except KeyboardInterrupt:
95 print 'Interrupted at line', lineno
96 show(bytype, 'by transfer direction', maxitems)
97 show(bydir, 'by directory', maxitems)
98 show(byfile, 'by file', maxitems)
99 show(byhost, 'by host', maxitems)
100 show(byuser, 'by user', maxitems)
101 showbar(bydate, 'by date')
102 showbar(bytime, 'by time of day')
103
104def showbar(dict, title):
105 n = len(title)
106 print '='*((70-n)/2), title, '='*((71-n)/2)
107 list = []
108 keys = dict.keys()
109 keys.sort()
110 for key in keys:
111 n = len(str(key))
112 list.append((len(dict[key]), key))
113 maxkeylength = 0
114 maxcount = 0
115 for count, key in list:
116 maxkeylength = max(maxkeylength, len(key))
117 maxcount = max(maxcount, count)
118 maxbarlength = 72 - maxkeylength - 7
119 for count, key in list:
120 barlength = int(round(maxbarlength*float(count)/maxcount))
121 bar = '*'*barlength
122 print '%5d %-*s %s' % (count, maxkeylength, key, bar)
123
124def show(dict, title, maxitems):
125 if len(dict) > maxitems:
126 title = title + ' (first %d)'%maxitems
127 n = len(title)
128 print '='*((70-n)/2), title, '='*((71-n)/2)
129 list = []
130 keys = dict.keys()
131 for key in keys:
132 list.append((-len(dict[key]), key))
133 list.sort()
134 for count, key in list[:maxitems]:
135 print '%5d %s' % (-count, key)
136
137def add(dict, key, item):
138 if dict.has_key(key):
139 dict[key].append(item)
140 else:
141 dict[key] = [item]
142
143main()