Categories

Checkio.ORG

Subscribe to Posts

Email:

  • 04Apr

    Продолжаем о UCSVLOG. Начало читайте тут – Часть 1. Проблема и Идея, потом тут мы продолжили – Часть 2. Решение , ну а сейчас о плюхах

     Плюшки это типо сладости, которые тебе дают, если ты прилежно все делаешь. Так и с логами. Если ты правильно и аккуратно их пишешь – то в результате получаешь правильную и четкую аналитику любой сложности и не только.

    django-ucsvlog

    Проект лежит на bitbucket.org

     Первым для себя применением ucsvlog я нашел в как апой к Django. Он был создан за долго до того, как у Django появились свои логи. И пока миграцию на них я не планирую, а думаю, как объеденить и взять что-то хорошее с джанговских и сделать процесс миграции с джанговских на UCSVLOG более простым.

     Блоком в данном случае у нас будет запрос пользователя. Подключается с помощью одной или двух мидлварь, каждая из которых открывает блок.

     Первая ‘djucsvlog.middleware.LogRequestInfo‘ идет как самой первой в Вашем списке мидлварь,а значит должна запускаться еще до того, как какая-либо из них начнет работать.

     Она открывает блок, в который кладется информация о запросе, а в settings задается список полей которые мы хотим записываться, например имя домена, путь, гет, пост параметры, файлы или BROWSER_UUID_COOKIE.

    BROWSER_UUID_COOKIE – это простой механизм, который по средствам кук следит за действиями пользователя. Когда приходит пользователь и у нег нет нашей куки – мы ему создаем ее и при каждом его запросе кладет ее в лог. Далее это позволит сводить свою аналитику.
    Как дополнительная возможность – это вести лог файлов, которые аплоадит пользователей. Т.е. мы в отдельное место сохраняем все аплоады пользователей, а в логах отмечаем – что и куда мы сохранено.

     Вторая ‘djucsvlog.middleware.LogViewInfo‘ записывается последней мидлварей, она опциональная, т.е. работать будет и без нее, сюда кладется инфа накопленная с других мидлварь, например информация о залогиненом пользователе или любая другая информация, которая может быть собранная уже с ваших мидлварь.

     Последнее – это указать у себя в сетингсах шаблон имени файла UCSVLOG_FILE, и можно начинать играться.

     Во время работы сам объект логера лежит в глобальной области видимости. Т.е. воспользоваться им можно в любой момент.

     За время работы с django-ucsvlog у нас накопилось много настроек для кастомизации этих логов. Все они лежат в djucsvlog.settings.py немного документированные, в лучших традициях опенсорса, с указанием дефолтных значений. Такие как – правило формирования отчет об ексепшене, буферизация, правило определение IP пользователя, возможность сохранять отдельно загружаемые файлы, а в лог класть инфу о том, куда мы сохранили текущий загруженый файл.
     + UCSVLOG_CHANGE_MODEL в этом дикте можно указать – за изменением каких моделей вы хотите следить ( предварительно указав ‘djucsvlog.components.change_model’ в списке компонентов UCSVLOG_COMPONENTS ), и какие поля этих моделей вы хотите класть в лог файл в момент их изменения. Т.е. теперь благодаря логам вы можете связывать изменения любой модели с определенным пользователем – ваще мечта.

    Пример settings.py вашего приложения:

    1. MIDDLEWARE_CLASSES = (
    2.     'djucsvlog.middleware.LogRequestInfo', ##первый
    3.     'django.middleware.common.CommonMiddleware',
    4.     'django.contrib.sessions.middleware.SessionMiddleware',
    5.     'django.middleware.csrf.CsrfViewMiddleware',
    6.     'django.middleware.locale.LocaleMiddleware',
    7.     'django.contrib.auth.middleware.AuthenticationMiddleware',
    8.     'django.contrib.messages.middleware.MessageMiddleware',
    9.     'django.middleware.transaction.TransactionMiddleware',
    10.     'djucsvlog.middleware.LogViewInfo', ## Второй
    11. )
    12. UCSVLOG_COMPONENTS = (
    13.         'djucsvlog.components.change_model',
    14.     ) # указываем список компонентов ( расширений )
    15.  
    16. UCSVLOG_FILE_VERSION = 'v3' # о смысле такого хука мы расскажем позже
    17. UCSVLOG_FILE = '/var/log/django/console-%(year)s-%(month)s-%(day)s-'+UCSVLOG_FILE_VERSION+'.ucsv'
    18.  
    19. #  По умолчанию False тоже, но если мы хотим, чтоб логи не велись, а выводились в консоль то делаем тру
    20. UCSVLOG_PRINT = False
    21.  
    22. # Эти поля будут класться в лог в момент закрытия блока запроса, т.е. в самом конце
    23. UCSVLOG_RESPONSE_FIELDS = ['status','ctype','content']
    24.  
    25. # кастомные пользовательские функции для логирования
    26. def server_ip(request,*args,**kwargs):
    27.     return request.META.get('REMOTE_ADDR', '0.0.0.0')
    28.  
    29. def ucsvlog_last_login(request,*args,**kwargs):
    30.     return request.session.get('last_login','')
    31.  
    32. # поля, которые мы созраняем при открытии реквеста ( в первой мидлвари )
    33. UCSVLOG_REQUEST_FIELDS = ['http_host','browser_uuid','remote_addr',server_ip,\
    34.               'path','get','post','save_files','http_user_agent',\
    35.               'http_referer','http_accept_language']
    36.  
    37. UCSVLOG_VIEW_OPEN_FIELDS = ['userid',ucsvlog_last_login] # во второй мидлвари
    38. UCSVLOG_RESPONSE_FIELDS = ['ctype','content','status','headers'] #при закрытии
    39. UCSVLOG_REQUEST_REQ_REMOTE_ADDR_REAL_IP = 'HTTP_X_REAL_IP'
    40. # каталог с исходниками, относительно него будет писаться инфа о вызове функций
    41. UCSVLOG_RELATED_FOLDER = PRJ_ROOT

    Большая часть этих настроек имеют значения по умолчанию, поэтому заведется и с такими вот:

    1. MIDDLEWARE_CLASSES = (
    2.     'djucsvlog.middleware.LogRequestInfo', ##первый
    3.     'django.middleware.common.CommonMiddleware',
    4.     'django.contrib.sessions.middleware.SessionMiddleware',
    5.     'django.middleware.csrf.CsrfViewMiddleware',
    6.     'django.middleware.locale.LocaleMiddleware',
    7.     'django.contrib.auth.middleware.AuthenticationMiddleware',
    8.     'django.contrib.messages.middleware.MessageMiddleware',
    9.     'django.middleware.transaction.TransactionMiddleware',
    10.     'djucsvlog.middleware.LogViewInfo', ## Второй
    11. )
    12. UCSVLOG_FILE = '/var/log/django/console-%(year)s-%(month)s-%(day)s.ucsv'

    django-ucsvlog-analytics

    Проект лежит на bitbucket.org

     Но все самое вкусное для этих логов, благодаря их хорошей структуризации – должно лежать в аналитике.
     Аналитике представленна набором базовых коммнад, которые расширяются исходя из нужд конкретной задачи.
     Приятной особенностью в написании логов является то, что на вход функций анализа приходят не массивы, а объекты класса Row , у которого есть множество свойтсв, заполеныне исходя из настроек django-ucsvlog. Т.к. к примеру, когда приходит row из первого индекса реквеста то у него уже есть к примеру аттрибуты row.data_path или row.data_ip
     Но этот бонус также накладывает и свои ограничения, о которых я расскажу позже.

    BaseSimpleAnalyticCommand – простой анализатор

     Это самый простой метод анализа. Подходит в случае если вы своим логам хотите задать все один и довольно конктерный вопрос. “Дай мне количество хитов за период?” или “Дай мне топ стран”. В этом случае команде кормится набор логфайлов, а в вашу функцию collect_row передаются объекты строк, где вы можете проводить анализ и выдавать пользователю. Тут в принципе ничего сверхествественного не происходит.

     Вот пример команды, которая собирает из Ваших логов топ accepted languages

    1. from djucsvlog_analytics.analytic_commands import BaseSimpleAnalyticCommand
    2.  
    3. class Command(BaseSimpleAnalyticCommand):
    4.     data = {}
    5.     # переопределяя эту функцию – вы указываете,
    6.     # какие записи вы ходите видеть в анализе
    7.     # в нашем случае мы хотим видеть только
    8.     # первые записи блока реквеста,
    9.     # потому что только в них есть инфа о
    10.     # браузере пользователя
    11.     def filter_row(self,row):
    12.         return row.is_a_req
    13.    
    14.     # собственно функция анализа тех записей, которые
    15.     # прошли через фильтер
    16.     def collect_row(self,row):
    17.         al = row.data_http_accept_language.\
    18.            split(';')[0].split(',')[0].split('-')[0]
    19.         if al in self.data:
    20.             self.data[al]+=1
    21.         else:
    22.             self.data[al] = 1
    23.  
    24.     # и вывод результатов
    25.     def output_results(self):
    26.         for item in  sorted(self.data.items(),\
    27.                      key=lambda a:a[1]):
    28.             print item[0], item[1]

     Если это сохранить как команду djucsvlog_test_simple_analytics то запуск будет выглядить следующим образом:

    1. $ python manage.py djucsvlog_test_simple_analytics /var/log/django/stats-2012-3-21-v3.ucsv  –settings=settings.analytics

    djucsvlog_user_path_convertor

     Это уже команда на основе базового класса BaseAnalyticCommand ( наследник от BaseSimpleAnalyticCommand ).

     Очень полезна, когда для одних логов вы хотите провести более детальный анализ. Когда Вам нужен не просто маленький отчет, а когда Вам надо разобраться дельано со сложившейся проблемой с трафиком. Это очень похоже на то, когда трафик есть а продаже нет. Почему?

     Идея проста convertor собирает из логов sqlite3 БД и кладет в один файл, при этом может дополнить его информацией о браузере, оси и стране пользователя. Таблици внутри него не просто набор строк, а связные таблицы. Хосты имеют много пользователей, пользователи имеют много реквестов, а реквес имеет много лог записей. Сам этот файл уже по сути часть анализа можно просто зайти в нее и на уровне SQL получать необходимые выборки и сводить статистику.

     djucsvlog_user_path_convertor – это именно наша идея конвертации в такую вот струкруту БД. Если вы заходите сделать свой конвертато в БД, то просто пишите команду, наследник от BaseAnalyticCommand.

    Ниже несколько примеров запуска такой команды в наших проектах

    1. $ python manage.py djucsvlog_user_path_convertor /var/log/django/* \
    2.         –out=/tmp/django.userpath.db

    Это мы просто конвертим все файлы из папки /var/log/django/ в базу

    1. $ python manage.py djucsvlog_user_path_convertor /var/log/django/* \
    2.         –out=/tmp/django.userpath.db –force-new

    Указываем, что если БД уже есть, то в нее не дописывать а создавать заново

    1. $ python manage.py djucsvlog_user_path_convertor /var/log/django/* \
    2.         –out=/tmp/django.userpath.db –force-new\
    3.        –geoip-db=/var/geodb/2012-04-01.db

    Передаем ссылку на базу GEO IP для добавления дополнительного поля со страной

    djucsvlog_user_path_analytics

     Но мы очень быстро поняли, что очень много задач не решаются просто SQL командой, поэтому мы к sqlite3 базе начали дописывать скриптики для ее анализа, и все это свернули в отдельную команды, на вход которой передается один или несколько sqlite файлов и параметры для анализа. Причем параметры разделаются на задачи и на условия. Т.е. мы при вызове команды можем передать ей на вход несколько задач например топ браузеров или топ стран, и условия например пользователи, которые зашли на определенную страницу, пользователи, которые сделали больше определенного количества шагов. Или как связка – дай мне следующий шаг после переданного.

     Сама команда является наследником от BaseAnalyticReadCommand, а задачи являются наследниками от BaseAnalyticElement, список условий передаются при создании элемента задачи

     Ниже несколько примеров использования этой команды:

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db –get-entry-points

    Получаем ТОП точек входа на сайт

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db /tmp/django_2.userpath.db \
    3.        –get-entry-points

    Для анализа можно указывать не один файл

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db /tmp/django_2.userpath.db \
    3.        –get-entry-points –after-path=/

    Какой был следующий шаг после /

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db
    3.        –top-404

    Невероятно полезная команда после переверстки

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db
    3.        –get-country-ip

    Дай топ стран

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db
    3.        –get-country-ip –get-os

    топ стран и топ осей

    1. $ python manage.py djucsvlog_user_path_analytics \
    2.          /tmp/django.userpath.db
    3.        –get-country-ip –get-os –after-steps=3

    топ стран и топ осей пользователей которые сделали на сайте больше 3х шагов

     Тут мне даже сложно будет перечеслить все возможности которые есть у этой команды, а сколько всего Вы еще можете дописать!!! :)

    Следующие 2 возможности особо мне теплы, т.к. кроме того что они добавляют аналитику они еще и существенно облегчают жизнь программисту.

    BaseStreamCommand – отложеная статистика

     Раньше, для сбора онлайн статистики о ваших пользователях – Вам надо было в момент захода этого пользователя раскидывать записи по таблицам и возможно совершать какие-то дополнительные расчеты. Причем это надо было делать максимально быстро, чтоб пользователь не видел никаких задержек. С четко структурированными логами, такими как ucsvlog, нет необходимости делать это в момент захода пользователя. Достаточно просто дочитывать периодически логи, которые пишутся, и уже в момент чтений, уже раскидывать статистику. При этом ваши расчеты уже никого не задерживают. Я назвал это “отложенная статистика”, т.к. мы откладывает всю работу по ее расчет в отдельную команду.

     Вы пишите команду на вход которой подаются новые записи из каталога с логами. Причем подаются эти записи именно в хронологии возникновения их в логах. Т.е. если ваш сервис пишет 10 различных лог файлов одновременно и команда в момент запуска определила, что все они выросли с момента последнего запуска, то она будет выдавать к вам на вход записи с разных файлов в разброс в зависимости от того, где записи появляются раньше. Чтоб аналитика в этом случае была максимально четкой.

     Особенности работы такой команды является индексный файл ( sqlite3 ), в котором она держит данные которые используются между ее вызовами, например такие как – последние размеры лог файлов

     Помимо того плюса ускоренной работы пользователя является еще и то, что в случае, когда клиент захочет расширить онлайн статистику, например добавить в нее дополнительный ТОП – ему не надо будет ждать пока она накопится. Мы просто дописываем команду по сбору статистики, которая в момент первого запуска просто накопит недостающие данные и пойдет считать стату дальше.

     Наследника BaseStreamBlockCommand, передает анализу не одну строку,а уже собранный блок.

    BaseConvertBlockCommand – конвертация логов.

     Последней плюшкой анализатора, которая нами в данным момент обкатывается еще – это конвертатор.

     Меня всегда расстраивал тот факт, что логи надо удалять :( А при использования django-ucsvlog апетиты засунуть в них чего по больше только растут, в результате они и стают очень толстыми. Самое грустное, что единственным правилом для удаления логов всегда служил их срок, который прямо пропорционален размеру вашего винта и размеру плодящихся логов. Говоря короче большие логи живут меньше, т.к. надо удалять их быстрее, чтоб освобождать место другим логам.

     Но я не хочу удалять все логи, я хочу удалять из логов только ненужное. Мне через месяц будет неважен call_info т.е. место, где были вызваны эти логи. Мне будет все также все равно на заходы пользователя на всякие информационные страници, или к примеру стуки всяких мониторингов меня тоже будут не волновать. Но я хочу держать как можно дольше процесс совершения покупки и процессинга карты. Для этого и делается конвертатор, который перегоняет логи из толстых, в которых часть инфы актуальна только несколько дней, в тонкие, в которых остается инфа, актуальность которой максимально долгая.

     Ваша команда наследник от BaseConvertBlockCommand легко может с этим справляться.

     Вот пример команды, которая делает это у меня:

    1. class Command(BaseConvertBlockCommand):
    2.     def filter_convert_row(self,row):
    3.         if not row.is_a_req:
    4.             return True
    5.         return not(row.data_path.startswith('/info') \
    6.             or row.data_path.startswith('/test-exception') \
    7.             or row.data_path.startswith('/check-back') \
    8.             or row.data_path.startswith('/calculate-statistics') \
    9.             or row.data_path.startswith('/captcha') \
    10.             or row.data_path.startswith('/media') \
    11.             or row.data_path.startswith('/favicon'))

     Тут указывается фильтр – какие строки надо оставить. Какие столбци надо оставить указывается в сетингсах. Детали смотрите в сетингсах, там под это выделен подраздел.

     Самое приятное в стриминге и конверторе – это то, что абсолютно не важно – сколько сервисов ведут свой лог. У Вас может быть ucsvlog на твистеде, отдельный на Django, еще отдельные логи ведут кроновские команды. А вот стриминг с конвертором берут и объединяют их в один поток, в один файл, где вы в хронологии сможете посмотреть события каждого из них. ( Да и не только питон, сам формат логов очень простой )

    Версионность логов.

     Ваша структура логов будет меняться с тем, как меняется и растет Ваш проект. И разные версии логов не должны мешаться в файлах. Поэтому я в формат файла добавляю маркер версии. И для каждой версии создаю отдельный сетингс для анализатора.

     Например, когда я только подключил ucsvlog к системе имена всех файлов логов оканчиваются на v1.ucsv. Потом я добавил дополнительные поля в строку открытия реквеста, и изменил формат файлов на v2.ucsv, но также создал файл analytics/v1.py в которую положил настройки для первой версии логов. Теперь когда я буду парсить логи из первой версии я буду использовать этот сетингс.

    1. $ python manage.py djucsvlog_user_path_convertor \
    2.      /var/logs/django/*-v1.ucsv \
    3.      –settings=analytics.v1

    Тоже самое с каждой следующей версией

    Заключение

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

     Вобщем подключайтесь, Вам понравится, я уверен :)

    Share and Enjoy:
    • Facebook
    • LinkedIn
    • Twitter
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Posted by Oduvan @ 12:07 am

    Tags: , , , ,

blog comments powered by Disqus