Showing posts with label apache. Show all posts
Showing posts with label apache. Show all posts

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 строчки, благодаря тому факту, что в питоне все функции - высшего порядка.

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

Задача: понять по логам Apache сколько байтов мы передали.
NB: файлы мб большие (несколько гигов).

Формат логов примерно следуюший:

217.168.25.4 - - [28/May/2011:14:06:27 +0400] "GET / HTTP/1.0 200 8509

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

wwwlog = open("access-log")
total = 0
for line in wwwlog:
    bytestr = line.rsplit(None,1)[1]
    if bytestr != '-':
        total += int(bytestr)
print "Total", total

И, с генератором:

wwwlog = open("access-log")
bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)

Выглядит компактнее, не правда ли? В данном случае используется выражение-генератор, эдакий "цикл for наоборот", который выдает кортеж из результатов, суммирующийся далее.

2009/09/16

Радости разработки на Django

Недавно заинтересовался разработкой веб-приложений на Python, соотвественно, решил воспользоваться фреймворком Django. В этой заметке хочу описать процесс создания и запуска проекта Django на Apache, ибо запуск приложений на сервере хостера заметно отличается от запуска их на локальном компьютере (что описывается в первых главах DjangoBook), как оказалось.

На моём хостинге уже был установлен Django и соотвествующим образом настроен Apache, поэтому первое, что нужно сделать - это создать проект. В моем случае последовала команда:
~/www/webapp$ django-admin.py startproject mysite
После этого в папке mysite создался проект django, включающий в себя несколько файлов (подробное описание их опускаю, можно найти в DjangoBook).
Далее согласно мануалу нужно создать WSGI-приложение webapp.wsgi следующего содержания:
import os, sys
sys.path.append('/home/www/webapp)
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()
В итоге получаем приветственную страницу Django по ссылке http://сайт/webapp
Чтобы получать доступ к Django из корня сайта, нужно написать rewrite правило в файле .htaccess, который должен располагаться в папочке public_html:
RewriteEngine On
RewriteRule ^(.*)$ /webapp/$1 [L,QSA]
Теперь привественная страничка доступна по нормальной ссылке, далее можно продолжать разработку согласно DjangoBook.