2011/05/29

Парсим логи при помощи генераторов - 2

Дано: сотни логов веб-сервера, разбросанные по разным директориям. Возможно, заархивированные.
Требуется: понять сколько байтов было передано :)

В питоне есть замечательная функция os.walk(), позволяющая блуждать по файловой системе:

import os

for path, dirlist, filelist in os.walk(topdir):
    # path : текущая директория
    # dirlist : список поддиректорий
    # filelist : список файлов
    ...

Для достижения цели потребуется создать несколько функций:
1. Функция-генератор, возвращающая список файлов по заданному шаблону:

import os
import fnmatch
 
def gen_find(filepat,top):
    for path, dirlist, filelist in os.walk(top):
        for name in fnmatch.filter(filelist, filepat):
            yield os.path.join(path, name)

Примеры использования:

pyfiles = gen_find('*.py', '/')
logs = gen_find('access-log*', '/usr/www/')

2. Функция-генератор, которая принимает список файлов, и, если среди них есть архивы, то возвращает распакованные файлы. Если файл не архив, то просто открывает его:

import gzip
import bz2
 
def gen_open(filenames):
    for name in filenames:
        if name.endswith(".gz"):
            yield gzip.open(name)
        elif name.endswith(".bz2"):
            yield bz2.BZ2File(name)
        else:
            yield open(name)

3. Функция (разумеется генератор), которая возвращает единую последовательность результатов, принимая при этом несколько последовательностей (в нашем случае передаем открытые файлы, а получаем последовательность строк):

def gen_cat(sources):
    for s in sources:
        for item in s:
            yield item

Ну вот, после реализации всех этих функций осталось только немного подправить прошлый исходник, чтобы он теперь работал с любым количеством файлов:

filenames = gen_find('access-log*', '/usr/www')
logfiles = gen_open(filenames)
loglines = gen_cat(logfiles)
bytecolumn = (line.rsplit(None, 1)[1] for line in loglines)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)

Особые эстеты могут свернуть этот исходник вплоть до 1 строчки, благодаря тому факту, что в питоне все функции - высшего порядка.

No comments:

Post a Comment