Не так давно я рассказывал о том, как настроить ELK Stack для централизованного хранения логов. Сегодня хочу подробно рассказать о том, как создать координатную географическую карту на основе логов nginx и составить дашборд для него же. На этом дашборде очень удобно мониторить состояние веб проекта - расследовать инициденты, анализировать ошибки.
Введение
Начнем создание дашборда с самого сложного - настройки гео карты запросов. На официальном сайте есть подробный мануал на тему создания GeoIP карты. В нем вроде бы все понятно. Никаких особых настроек не требуется. Все работает из коробки. Но у меня никак не хотело работать все то, что там описано. Пришлось прилично поковыряться с elasticsearch и его шаблонами, чтобы разобраться в чем причина.
Все дело в том, что описанный в инструкции способ работает из коробки, только если вы используете стандартный шаблон для индексов в формате logstash-*. Скорее всего у вас будет много разных шаблонов и индексов после того, как вы запустите систему в промышленную эксплуатацию.
Основная сложность тут в том, что для работы geoip карты вам нужны в шаблоне поля с типом geo_point. После создания индекса, тип полей уже нельзя поменять. То есть просто преобразовать данные на основе ip в координаты не сложно, это умеет делать модуль geoip в logstash. Но вот дальше вы никак не превратите координаты в виде числа в geo_point данные. Нужно в самом начале создать шаблон с такими полями.
Надеюсь понятно объяснил :) Если не понятно сразу, то сообразите дальше по ходу моего рассказа. Я сам пока разобрался в этой кухне, прилично поковырялся и нагуглился.
В дальнейшем я буду считать, что ваш elasticsearch и kibana настроены примерно как у меня в инструкции. Фильтр logstash, отвечающий за обработку логов nginx выглядит следующим образом:
if [type] == "nginx-ext-access" { grok { match => [ "message" , "%{COMBINEDAPACHELOG}+%{GREEDYDATA:extra_fields}"] overwrite => [ "message" ] } mutate { convert => ["response", "integer"] convert => ["bytes", "integer"] convert => ["responsetime", "float"] } geoip { source => "clientip" target => "geoip" add_tag => [ "nginx-geoip" ] } date { match => [ "timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ] remove_field => [ "timestamp" ] } useragent { source => "agent" } }
И вот так логи уходят в elasticsearch
if [type] == "nginx-ext-access" { elasticsearch { hosts => "localhost:9200" index => "nginx-ext-%{+YYYY.MM.dd}" } }
Создание index шаблона
Как я уже сказал выше, для того, чтобы у вас заработала geoip карта, у вас должны быть в шаблоне индекса поля типа geo_point. Если их не будет, то вы сразу при создании визуализации с Coordinate Map получите ошибку:
No Compatible Fields: The "nginx-*" index pattern does not contain any of the following field types: geo_point
Что я только не делал, после того, как получил эту ошибку. Я проверял работу geoip модуля. Смотрел поля с координатами на основе ip адреса. Все было в порядке и все было на месте.
Но geoip карта в Kibana не работала. Погуглив немного эту тему, я потихоньку стал понимать, в чем тут дело.
Для начала посмотрим шаблон нашего индекса с логами nginx. Для этого идем в Management -> Index Management. Выбираем наш индекс и смотрим Mapping. Нас интересует поле location.
Оно имеет тип float, а нам нужно, судя по статье на сайте, тип geo_point.
Дальше стал разбираться, как изменить тип поля в шаблоне. Оказалось, что это сделать нельзя. Тип полей можно установить только в момент создания индекса из шаблона. Значит нужно понять, как сделать свой шаблон с нужными полями.
Для начала посмотрим, какие шаблоны у нас сейчас установлены. Для этого идем в Dev Tools и выполняем команду:
GET /_template
Обращаем внимание на шаблон logstash. В нем есть все, что нам нужно. Если ваш индекс будет иметь шаблон logstash-*, то вам ничего настраивать не надо, все заработает из коробки. Мы же добавим новый шаблон nginx* и установим у него параметры полей, необходимые для работы geoip карты.
Выполняем следующий код для создания шаблона nginx по аналогии с шаблоном logstash.
PUT _template/nginx { "index_patterns": [ "nginx*" ], "settings": { "index": { "refresh_interval": "5s" } }, "mappings": { "_default_": { "dynamic_templates": [ { "message_field": { "path_match": "message", "match_mapping_type": "string", "mapping": { "type": "text", "norms": false } } }, { "string_fields": { "match": "*", "match_mapping_type": "string", "mapping": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } ], "properties": { "@timestamp": { "type": "date" }, "@version": { "type": "keyword" }, "geoip": { "dynamic": true, "properties": { "ip": { "type": "ip" }, "location": { "type": "geo_point" }, "latitude": { "type": "half_float" }, "longitude": { "type": "half_float" } } } } } }, "aliases": {} }
Проверяем список доступных шаблонов.
Все в порядке. Теперь новые индексы, попадающие под этот шаблон, будут содержать необходимые поля. Можете либо удалить текущие индексы, для создания новых, либо подождать, когда они сами создадутся в соответствии с вашими правилами.
Прежде чем двигаться дальше, проверьте, что у вас в шаблоне индекса действительно есть поле geo_point. Идем в Management -> Index Patterns и смотрим поля нашего индекса, предварительно обновив их, нажав Refresh field list.
Если у вас так же, можно двигаться дальше.
На всякий случай расскажу про неправильный путь, по которому я пошел изначально, пытаясь решить проблему с шаблоном. Я узнал, что logstash хранит свои шаблоны в директории /usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/logstash-output-elasticsearch-9.2.0-java/lib/logstash/outputs/elasticsearch (пипец какой путь :)). Я решил изменить его шаблон, для этого просто отредактировал файл elasticsearch-template-es6x.json, поменяв шаблон для индекса. Перезапустил logstash, но ничего не изменилось. Этот шаблон был залит в elasticsearch при первом запуске. Потом уже не меняется. Его надо удалить, чтобы он установился заново с моими изменениями. Я не стал это делать, а просто загрузил новый шаблон.
Настройка координатной карты в Kibana
Теперь создадим географическую карту с распределением запросов nginx по этой карте на основе ip адресов. Идем в раздел Visualize и добавляем Coordinate Map. Выбираем индекс с логами nginx. Указываем в карте поле с координатами - geoip.location.
Запускаете визуализацию и смотрите результат.
Теперь эту карту можно добавить на дашборд вместе с остальными графиками. Не буду рассказывать, как добавить обычные графики. Там хоть и не совсем все очевидно, но не так сложно. Лучше самим разобраться и порисовать различные графики, чтобы понять, какая визуализация для вас наиболее удобна. Я подобрал по своему вкусу. Много раз перерисовывал и переделывал, пока не удовлетворился результатом.
Настройка Dashboard для nginx
Я настроил вот такой дашборд в Kibana для логов Nginx (кликабельно, большая картинка, откройте в отдельной вкладке, чтобы рассмотреть).
Здесь представлена следующая информация:
- Geoip карта
- Распределение запросов по странам.
- Список самых популярных урлов.
- Список самых активных IP.
- Распределение запросов по типам ответов.
- Траффик.
- Непосредственно логи nginx в чистом виде.
С таким дашбордом очень удобно расследовать инциденты и просто смотреть статистику. Выбираем, к примеру, код ошибки и смотрим всю информацию по нему. Сразу подсвечиваются ip, которые спамят запросы. По ним тут же можно получить всю информацию - откуда они и по каким урлам спамят. И так далее. В общем, очень удобно. Я уже не представляю большой веб проект без такого дашборда. Раньше анализ логов для меня был гораздо сложнее. И как я раньше админил без такого инструмента :) Век живи - век учись.
Заключение
Я долго размышлял над дашбордом для логов nginx. Рисовал графики, выбирал данные. В итоге остановился на таком варианте. Больше ничего полезного для вывода придумать не смог. Кстати, сама Geo карта тут больше для красоты. Я ей не пользуюсь. Практической пользы в ней не вижу. Если у вас есть советы по каким-то еще полезным данным, которые можно вывести - делитесь. Конечно, можно добавить инфу по юзерагентам, системам и браузерам. Но мне кажется, такие вещи удобнее смотреть в сторонней аналитике. Там будут более точные данные.
Отдельно стоит добавить в логи nginx информацию о request_time, upstream_response_time, upstream_cache_status и т.д. Потом эту информацию распарсить и сделать отдельный дашборд для мониторинга быстродействия и ответов upstream. Но это уже будет отдельная штука. А здесь у меня представлена общая информация для первичного анализа.
Если у вас есть желание научиться строить и поддерживать высокодоступные и надежные системы, научиться непрерывной поставке ПО, мониторингу и логированию web приложений, рекомендую познакомиться с онлайн-курсом «DevOps практики и инструменты» в OTUS. Курс не для новичков, для поступления нужны базовые знания по сетям и установке Linux на виртуалку. Обучение длится 5 месяцев, после чего успешные выпускники курса смогут пройти собеседования у партнеров.
Проверьте себя на вступительном тесте и смотрите подробнее программу по ссылке.
При выполнении PUT _template/nginx, выдаёт ошибку Root mapping definition has unsupported parameters. Я так понимаю в 7-ой версии что-то по этому поводу помеялось.
В общем надо просто удалить строчку
"_default_": {
и соответствующую закрывающую скобку } внизу. Только что дальше всё равно не понятно. Похоже, в 7-ой версии по-другому
Столкнулся с этой же проблемой и решил ее так. Index Managment -> Index Template шиблон "Logstash" на который ссылается автор статьи теперь в "Legacy index templates" и скоро будет удален, но в нем правильный mapping для geoip. Открываем шаблон (нажав на него, не через редактирование) и смотрим mapping в режиме JSON, копируем.
Далее у меня создан шаблон под который подпадают нужные мне index nginx, у меня это logstash-ngx-*, редактирую его и вставляю в разделе mapping json из Logstash шаблона. Пересоздаю index (или можно дождаться создание новых) и вуаля - все как надо!
Информация в статье явно неактуальная, я не стал рисковать и переустановил эластик по мануалу для 7-ой версии.
Ну конкретно в части шаблонов да есть изменения, в остальном пока проблем не заметил. Поделитесь ссылкой на мануал по 7xx версии?
Скажем так, основное все то же самое и осталось, плюс-минус. Но частностей много поменялось. ELK постоянно развивается и обновляется. Веб интерфейс сильно изменился. Простым копипастом, как на момент публикации статьи, уже не настроить. Надо разбираться. Со статьей это проще, чем без неё.
Владимир, я верно понимаю, если у меня в Kibana ip адреса посетителей сайта в разделе "message"(109.238.247.83 - - [26/Nov/2020:16:30:32 +0300 - 0.001] 304 "GET /sitemap.xml HTTP/1.0" 0 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0" "-") то я НЕ смогу вычлинять ипшники для построения графиков на их основе, верно?
Да, адрес должен быть в отдельном поле, по которому будет обработка результатов. Для этого как раз нужен grok фильтр. Разобрать message на составные данные и поместить их каждое в свой раздел.
Владимир, фильтр который будет всё это разбирать, добавляется в logstash/filter.cfg?
или еще какие-то манипуляции нужны со стороны filebeat'а? сейчас в нём по сути так
------
filebeat.inputs:
- type: log
- /var/log/nginx/*
------
Статья же как раз об этом. Все подробно описано. Да, фильтр logstash этим занимается. Filebeat просто передает лог как есть, без обработки.
У меня всё получилось, кроме GEO карты (((
Сливаю логи через filebeat, обрабатываю логстешем.
Создаю визуализацию, но в списке индексов nginx-* нет, хотя другие есть.
Гео-метки есть (их похоже генерирует сам logstash) и графики по ним рисуются нормально.
Что же пошло не так?
Да, таки невнимательно читал ))
Требуется поменять тип данных с FLOAT на geo_point.
Странно, что из коробки это настроено не правильно ...
Здравствуйте! у меня вопрос как разделить log nginx, system,postgresql, mysql
например: nginx отдельный индекс, postgresql отдельный индекс, systemlog отдельный ииндекс
Это делается в настройках logstash. На разные логи ставятся метки в filebeat, потом на основе этих меток раскладываются по разным индексам в logstash. У меня где-то в статьях есть такие примеры. Уже не помню где.
спасибо за ваши статьи!
но не могу понять как добавить визуализацию в виде логов по типу ваших [nginx-ext]Messages. с остальным разобрался вроде.
То же всю голову сломал и не пойму как это сделать, в интернете ответа не нашел ((
Нужно сохранить Поиск в режиме Discovery, где выбрано поле message. А потом в Dashboard добавить этот сохраненный поиск.
А как вывести график трафика? timestamp + ?
Сначала этот трафик надо как-то завести и хранить в elasticsearch.
У меня проксировании в nginx почему-то работает, только если в kibana.yml host указать 0.0.0.0, если оставляю стандартный localhost - то выдает ошибку http 502
Сам nginx где установлен? На сервере с Kibana?
И да, большое спасибо за статью.
Кстати, в типе данных bytes индекса nginx-* можно указать байты. Тогда смотреть отчеты по трафику можно будет в привычных кило- и мега-байтах, в зависимости от размера числа.
Кстати да, это может быть полезно. Хотя лично я не смотрю эти графики, так как в zabbix все это более наглядно и привычно.
Как разделять сайты в elk, если nginx проксирует больше количество сайтов ?
В логе порой невозможно однозначно определить к какому сайту принадлежит запись.
Сделал так:
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$host"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
В elk появилось поле extra_fields, впринципе этого мне достаточно.
Надо в nginx добавить в формат логов информацию о виртуальном домене. В grok фильтре потом разбирать эти строки. Не сложно, я делал так.
Привет, у меня такая проблема
No Compatible Fields: The "nginx-*" index pattern does not contain any of the following field types: geo_point
Я сделал чётко как на первой статье. значить у нас всё одинаков, значить у меня не должны быть проблемы, так вот у меня к тебе бро такой вопрос:
когда реч идёт о фильтре имеется виду filter.conf ?, там надо польностью заменить файлы или добавить надо?, потому что они отличаются.
когда реь идёт о отправке логов имеется виду файл output.conf ?, там тоже всё надо стиреть и добавить новые записи или вместе они должны быть? они тоже отличаются
а на input.conf не чьё не добовляется?
а можно просто изменённый конфиг скинте please :)
1. Вообще то эта статья как раз рассказывает, как решить проблему с этой ошибкой - index pattern does not contain any of the following field types: geo_point.
2. filter.conf в разных статьях разный. Не нужно к нему привязываться. Надо брать мои примеры и вставлять их к себе. Дальше будет много статей по elk, они все будут написаны по разным серверам, и конфиги там будут разные. Я буду приводить только нужные параметры, которые надо будет адаптировать под свой конфиг.
3. По output.conf то же самое, что и по filter. Надо смотреть мои примеры и адаптировать под свои конфиги.
Эта статья не подходит под copy/past Надо вдумчиво разбирать, что я пишу и адаптировать под себя. Как и все по теме elk. Она требует осмысления и понимания, иначе не настроить. В этом я убедился я сам, когда разбирался и настраивал разные вещи.
Знаю что не по теме, но подскажите пожалуйста! У Вас на сайте если реклама блокируется, появляется баннер "нет рекламы - меньше статьей", что это плагин или это какой-нибудь свой инструмент?