Каждый из проектов, который перерастает этап прототипа, нуждается в организации логирования. Грамотное логирования решает уйму проблем и помогает понять состояние проекта. На начальном этапе логирование в файл меня устраивало пока проект не разросся и поиск по логам не начал отнимать время.
Решением было создание централизованного лог хранилища с агрегацией логов и поиском. Выбор пал на ELK стек. ELK — сочетание трех OpenSource проектов: ElasticSearch, Logstash и Kibana. ELK хранит логи, строит графики и есть поддержка полнотекстового поиска с фильтрами. В статье описывается процесс настройки ELK стека для хранения логов Django приложения.
Установка ELK
Для установки ELK стека будет использоваться Docker, за основу взят репозиторий docker-elk. Изменим настройку Logstash-а, добавим GROK паттерн для матчинга nginx логов и изменим output секцию, чтобы логи Django приложения и nginx логи сохранялись в разных индексах ElasticSearch-а. В итоге logstash.conf выглядит так:
input {
beats {
port => 5000
host => "0.0.0.0"
}
}
filter {
if [type] == "nginx" {
grok {
match => { "message" => "%{IPORHOST:remote_ip} - %{DATA:user_name} \[%{HTTPDATE:access_time}\] \"%{WORD:http_method} %{DATA:url} HTTP/%{NUMBER:http_version}\" %{NUMBER:response_code} %{NUMBER:body_sent_bytes} \"%{DATA:referrer}\" \"%{DATA:agent}\"" }
}
}
}
output {
if [type] == "nginx" {
elasticsearch {
hosts => "elasticsearch:9200"
index => "nginx-%{+YYYY.MM.dd}"
}
}
else if [type] == "django" {
elasticsearch {
hosts => "elasticsearch:9200"
index => "django-%{+YYYY.MM.dd}"
}
}
else {
elasticsearch {
hosts => "elasticsearch:9200"
index => "unknown_messages"
}
}
}
После внесения изменений запускаем стек:
docker-compose up
После запуска стек слушает следующее порты:
- 5000: Logstash TCP input.
- 9200: Elasticsearch HTTP
- 9300: Elasticsearch TCP transport
- 5601: Kibana
Архитектура логирования
Рассмотрим архитектуру логирования Django приложения.
Как видно из схемы, приложение состоит из сервисов: nginx, django application, celery worker. Каждый из сервисов отправлял логи в ELK стек. Рассмотрим настройку каждого сервиса по отдельности.
Запись Nginx логов в ELK
Для работы с nginx логами потребуется дополнительный сервис Filebeat. Процесс установки Filebeat детально описан на официальном сайте. Пример установки Filebeat сервиса на Ubuntu сервер:
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.4.0-amd64.deb
sudo dpkg -i filebeat-6.4.0-amd64.deb
Filebeat будет читать логи из файла и отправлять в Logstash. Пример конфигурации:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
fields:
type: nginx
fields_under_root: true
scan_frequency: 5s
output.logstash:
hosts: ["logstash:5000"]
Запускаем наш Filebeat сервис и наблюдаем за появлением логов в Kibana.
Запись Django логов в ELK
Для взаимодействия Django с сервисом Logstash установите дополнительный пакет Python-logstash.
pip install python-logstash
Изменим настройки Django приложения, чтобы логи отправлялись в Logstash сервис.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': 'velname)s %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'logstash': {
'level': 'INFO',
'class': 'logstash.TCPLogstashHandler',
'host': 'logstash',
'port': 5000,
'version': 1,
'message_type': 'django', # 'type' поле для logstash сообщения.
'fqdn': False,
'tags': ['django'], # список тег.
},
},
'loggers': {
'django.request': {
'handlers': ['logstash'],
'level': 'INFO',
'propagate': True,
},
...
}
}
После этого приложение будет отправлять логи в Logstash. Пример использования:
import logging
logger = logging.getLogger(__name__)
def test_view(request, arg1, arg):
...
if is_error:
# Отправляем лог сообщение
logger.error('Something went wrong!')
После этого настройте Kibana под себя, чтобы отображать необходимую информацию. Пример скриншотов собственной настройки:
Система собирает логи сервисов, позволяет по ним удобно искать, строить графики и визуализации, позволяя в кратчайшие сроки обнаружить и исправлять проблемы.