|
1501
|
1 #! /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
|
|
|
14 import os
|
|
|
15 import sys
|
|
|
16 import regex
|
|
|
17 import string
|
|
|
18 import getopt
|
|
|
19
|
|
|
20 pat = '^\([a-zA-Z0-9 :]*\)!\(.*\)!\(.*\)!\([<>].*\)!\([0-9]+\)!\([0-9]+\)$'
|
|
|
21 prog = regex.compile(pat)
|
|
|
22
|
|
|
23 def 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
|
|
|
104 def 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
|
|
|
124 def 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
|
|
|
137 def add(dict, key, item):
|
|
|
138 if dict.has_key(key):
|
|
|
139 dict[key].append(item)
|
|
|
140 else:
|
|
|
141 dict[key] = [item]
|
|
|
142
|
|
|
143 main()
|