import httpcodes
import sys
import os
import api
import time
try:
import DNS
except ImportError:
DNS = None
def iterwatch(watch_func, iterator):
"""
Make a new iterator which yields all the items from iterator,
but first calls watch_func(item) for each item.
"""
for item in iterator:
watch_func(item)
yield item
def pass_through(watchers):
"""
Make a single watcher from a list of watchers, by using
pass_through to send data from one watcher to the next.
"""
watcher = last_watcher = watchers[0]
for next_watcher in watchers[1:]:
last_watcher.pass_through = next_watcher
last_watcher = next_watcher
return watcher
def make_link(url, max=70, follow=False):
if max and len(url) > max:
text = url[:max-20] + '...' + url[-20:]
else:
text = url
if not follow:
rel = ' rel="nofollow"'
else:
rel = ''
return '%s' % (url, rel, text)
class Watcher(api.Pipe):
pass_through = None
_abstract = 'Watcher'
def title__get(self):
return self.__class__.__name__
title = property(title__get)
def is_abstract(cls):
return cls.__name__ == cls._abstract
is_abstract = classmethod(is_abstract)
def name__get(self):
return self.__class__.__name__
name = property(name__get)
def add_pass_through(self, pass_through):
self.pass_through = pass_through
return self
def iterlog(self, log_items):
if not self.pass_through:
return iter(self.watchiter(log_items))
else:
return iter(self.pass_through.iterlog(
self.watchiter(log_items)))
def watchiter(self, log_items):
for log in log_items:
self(log)
yield log
class Hits(Watcher):
count = 0
min_time = time.time()+100
max_time = 0
bytes = 0
def __call__(self, log):
self.min_time = min(self.min_time, log.utime)
self.max_time = max(self.max_time, log.utime)
self.count += 1
self.bytes += log.bytes
def report(self):
diff = self.max_time - self.min_time
self.days = diff / 60 / 60 / 24
self.weeks = self.days / 7.0
self.months = self.weeks / 7.0
parts = [
'Total hits: %s' % self.format_amount(self.count),
'%s/day (%i days)' %
(self.format_amount(self.count / self.days), self.days),
'%s/week (%i weeks)' %
(self.format_amount(self.count / self.weeks), self.weeks),
'%s/month (%.1f months)' %
(self.format_amount(self.count / self.months), self.months),
]
self.add_byte_report(parts)
return '
'.join(parts)
def add_byte_report(self, parts):
parts.extend([
'Traffic: %s' % self.format_bytes(self.bytes),
'%s/month' % (self.format_bytes(self.bytes/self.months)),
])
def format_amount(self, count):
s = str(int(count))
parts = []
while len(s) > 3:
parts.append(s[-3:])
s = s[:-3]
parts.append(s)
parts.reverse()
return ','.join(parts)
def format_bytes(self, bytes):
if bytes < 1000:
return '%i bytes' % bytes
if bytes < 1000*1000:
return '%iKb' % (bytes/1000)
if bytes < 1000*1000*10:
return '%.1fMb' % (bytes/1000./1000.)
if bytes < 1000*1000*1000:
return '%iMb' % (bytes/1000/1000)
return '%.1fGb' % (bytes/1000/1000/1000)
class Bytes(Hits):
def __call__(self, log):
self.min_time = min(self.min_time, log.utime)
self.max_time = max(self.max_time, log.utime)
self.count += log.bytes
def format_amount(self, bytes):
if bytes > 1024:
if bytes > 1024*1024:
if bytes > 1024*1024*1024:
return '%.1fGb' % (bytes / 1024.0 / 1024.0 / 1024.0)
return '%.1fMb' % (bytes / 1024.0 / 1024.0)
return '%iKb' % (bytes / 1024)
else:
return '%i bytes'
class UniqueHits(Hits):
def __init__(self, **kw):
Hits.__init__(self, **kw)
self.seen = {}
def __call__(self, log):
self.min_time = min(self.min_time, log.utime)
self.max_time = max(self.max_time, log.utime)
if not self.seen.has_key(log.client):
self.count += 1
self.seen[log.client] = None
def add_byte_report(self, bytes):
pass
class AccumulateCriteria(Watcher):
allow_empty = False
_abstract = 'AccumulateCriteria'
minimum = 0
maximum = None
exclude_media = False
top = None
media_extensions = ('gif', 'jpg', 'png', 'css', 'js', 'swf', 'ico')
configurable = Watcher.configurable + [
api.Configurable('minimum', int, 'Minimum count to display'),
api.Configurable('maximum', int, 'Maximum count to display'),
api.Configurable('top', api.top_or_percent, 'Top number or percent'),
api.Configurable('exclude_media', bool, 'Don\'t match media files'),
]
def __init__(self, **kw):
Watcher.__init__(self, **kw)
self.data = {}
def __call__(self, log):
if self.exclude_media:
ext = log.url.split('.')[-1].lower()
if ext in self.media_extensions:
return
value = self.criteria(log)
if value is None and not self.allow_empty:
return
self.data[value] = self.data.get(value, 0) + 1
def report(self):
rows = []
items = self.data.items()
items.sort(lambda a, b: cmp(b[1], a[1]))
top = self.top
if top and top < 1: # %
top = int(len(items) * top)
max_count = 0
for n, (value, count) in enumerate(items):
if top and n > top:
break
if count < self.minimum:
continue
if self.maximum and count > self.maximum:
continue
formatted = self.format(value)
if formatted is None:
continue
if not max_count:
max_count = count
length = int(100 * count / max_count)
if length >= 10:
bar = '%s%%' % (length, length)
else:
bar = ''
rows.append('
No results found
' return '