Dashboard для логов Nginx в Kibana+Elasticsearch

Не так давно я рассказывал о том, как настроить ELK Stack для централизованного хранения логов. Сегодня хочу подробно рассказать о том, как создать координатную географическую карту на основе логов nginx и составить дашборд для него же. На этом дашборде очень удобно мониторить состояние веб проекта - расследовать инициденты, анализировать ошибки.

Углубленный онлайн-курс по MikroTik.

Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном онлайн-курcе по администрированию MikroTik. Автор курcа – сертифицированный тренер MikroTik Дмитрий Скоромнов. Более 40 лабораторных работ по которым дается обратная связь. В три раза больше информации, чем в MTCNA.

Введение

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

No Compatible Fields: The "nginx-*" index pattern does not contain any of the following field types: geo_point

Что я только не делал, после того, как получил эту ошибку. Я проверял работу geoip модуля. Смотрел поля с координатами на основе ip адреса. Все было в порядке и все было на месте.

geoip данные для карты запросов

Но geoip карта в Kibana не работала. Погуглив немного эту тему, я потихоньку стал понимать, в чем тут дело.

Для начала посмотрим шаблон нашего индекса с логами nginx. Для этого идем в Management -> Index Management. Выбираем наш индекс и смотрим Mapping. Нас интересует поле location.

mapping индекса с nginx логами

Оно имеет тип float, а нам нужно, судя по статье на сайте, тип geo_point.

Тип поля geo_point для координат

Дальше стал разбираться, как изменить тип поля в шаблоне. Оказалось, что это сделать нельзя. Тип полей можно установить только в момент создания индекса из шаблона. Значит нужно понять, как сделать свой шаблон с нужными полями.

Для начала посмотрим, какие шаблоны у нас сейчас установлены. Для этого идем в Dev Tools и выполняем команду:

GET /_template

Просмотр template в elasticsearch

Обращаем внимание на шаблон 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": {}
  }

Проверяем список доступных шаблонов.

Новый шаблон для логов nginx в elasticsearch

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

Прежде чем двигаться дальше, проверьте, что у вас в шаблоне индекса действительно есть поле geo_point. Идем в Management -> Index Patterns и смотрим поля нашего индекса, предварительно обновив их, нажав Refresh field list.

Просмотр полей для индекса nginx в kibana

Если у вас так же, можно двигаться дальше.

На всякий случай расскажу про неправильный путь, по которому я пошел изначально, пытаясь решить проблему с шаблоном. Я узнал, что 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.

Настройка Coordinate Map в Kibana

Запускаете визуализацию и смотрите результат.

Geoip карта в Kibana и Elasticsearch для запросов nginx

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

Настройка Dashboard для nginx

Я настроил вот такой дашборд в Kibana для логов Nginx (кликабельно, большая картинка, откройте в отдельной вкладке, чтобы рассмотреть).

Dashboard для nginx в kibana

Здесь представлена следующая информация:

  1. Geoip карта
  2. Распределение запросов по странам.
  3. Список самых популярных урлов.
  4. Список самых активных IP.
  5. Распределение запросов по типам ответов.
  6. Траффик.
  7. Непосредственно логи nginx в чистом виде.

С таким дашбордом очень удобно расследовать инциденты и просто смотреть статистику. Выбираем, к примеру, код ошибки и смотрим всю информацию по нему. Сразу подсвечиваются ip, которые спамят запросы. По ним тут же можно получить всю информацию - откуда они и по каким урлам спамят. И так далее. В общем, очень удобно. Я уже не представляю большой веб проект без такого дашборда. Раньше анализ логов для меня был гораздо сложнее. И как я раньше админил без такого инструмента :) Век живи - век учись.

Заключение

Не понравилась статья и хочешь научить меня администрировать? Пожалуйста, я люблю учиться. Комментарии в твоем распоряжении. Расскажи, как сделать правильно!

Я долго размышлял над дашбордом для логов nginx. Рисовал графики, выбирал данные. В итоге остановился на таком варианте. Больше ничего полезного для вывода придумать не смог. Кстати, сама Geo карта тут больше для красоты. Я ей не пользуюсь. Практической пользы в ней не вижу. Если у вас есть советы по каким-то еще полезным данным, которые можно вывести - делитесь. Конечно, можно добавить инфу по юзерагентам, системам и браузерам. Но мне кажется, такие вещи удобнее смотреть в сторонней аналитике. Там будут более точные данные.

Отдельно стоит добавить в логи nginx информацию о request_time, upstream_response_time, upstream_cache_status и т.д. Потом эту информацию распарсить и сделать отдельный дашборд для мониторинга быстродействия и ответов upstream. Но это уже будет отдельная штука. А здесь у меня представлена общая информация для первичного анализа.

Углубленный онлайн-курс по MikroTik.

Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном онлайн-курcе по администрированию MikroTik. Автор курcа – сертифицированный тренер MikroTik Дмитрий Скоромнов. Более 40 лабораторных работ по которым дается обратная связь. В три раза больше информации, чем в MTCNA.

Помогла статья? Подписывайся на telegram канал автора

Анонсы всех статей, плюс много другой полезной и интересной информации, которая не попадает на сайт.

Автор Zerox

Владимир, системный администратор, автор сайта. Люблю настраивать сервера, изучать что-то новое, делиться знаниями, писать интересные и полезные статьи. Открыт к диалогу и сотрудничеству. Если вам интересно узнать обо мне побольше, то можете послушать интервью. Запись на моем канале - https://t.me/srv_admin/425 или на сайте в контактах.

33 комментария

  1. Короче пацаны, я сутки не спал, что только не делал, а решение оказалось довольно простым. Держите актуалочку на 12.2023.
    Версия 7.17.15, также актуально для 8.11. Обратите внимание, при установке пакет logstash,elastic,kibana должны быть одной версии.
    Для данных версий чтобы протестировать geoip, специально скачивать модуль geoip не нужно, он уже установлен. Также специально указывать в filter.conf путь до базы данных тоже не нужно, так как в этих версиях уже есть дефолтная база geoip(не с самыми свежими адресами).

    Значит, когда мы в output указали значение index, например nginx-%{+YYYY.MM.dd}, это означает что когда вы войдёте в Discovery, этот индекс будет взят за основу и предложит вам к созданию индекс, например nginx-2023.11.30.
    Теперь этот индекс хранится в Managment - Index Management.
    Чтобы убедиться что наш индекс не поддерживает GeoIP, вы можете зайти в Management - Dev Tools, выполнить запрос GET /_template чтобы увидеть какие вообще в принципе могут быть шаблоны(template) для значений индекса(indicies). В выпавшем справа окне найдите через Ctrl + F шаблон для "geoip" выглядит он так:

    "geoip" : {
    "dynamic" : true,
    "properties" : {
    "ip" : {
    "type" : "ip"
    },
    "latitude" : {
    "type" : "half_float"
    },
    "location" : {
    "type" : "geo_point"
    },
    "longitude" : {
    "type" : "half_float"
    }
    }
    }

    Теперь, мы выполним запрос к нашему индексу GET /nginx-2023.11.30, в выпавшем окне сделаем поиск шаблона значений для "geoip" и убедимся что у нас его нет, или почти все значения отсутствуют. Сначала я пошёл неправильным путем и начал править индекс методом PUT и POST, пытаясь вставить в нужное место шаблон "geoip", я не понял почему, но ничего не выходило. Рабочий метод заключается в следующем:
    1. Заходим в Managment - Index Management - Index Patterns
    2. Выбираем один единственный индексный шаблон, который и есть тот который мы создали при первом входе.
    3. Делаем поиск Полей(fields), пишем geo, ещё раз убеждаемся что ничего нет. (Убеждаемся в отсутствии для понимания складывающейся картины)
    4. Жмём на Add Field чтобы добавить поле в индексный шаблон. Указываем в названии geoip.location, тип поля ставим geo_point.
    5. Возвращаемся в Discover, слева в Available fields теперь доступен geoip.location, жмём на него, затем Visualize, ВСЁ! ПОЗДРАВЛЯЮ!

    P.S. Для тестирование предлагаю вам использовать команду изменяющую исходный IP входящего пакета, выполните её на сервере с nginx:
    iptables -t nat -A INPUT -s -j SNAT --to

    Спасибо принимаю в телегу @borisov_023 :)

    • после -s "ваш IP клиента от которого будете делать запрос до nginx", после --to "IP адрес на который хотите изменить, например 46.138.249.1"

    • Спасибо за полезную информацию.

  2. Дмитрий

    При выполнении 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 постоянно развивается и обновляется. Веб интерфейс сильно изменился. Простым копипастом, как на момент публикации статьи, уже не настроить. Надо разбираться. Со статьей это проще, чем без неё.

  3. Андрей

    Владимир, я верно понимаю, если у меня в 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 просто передает лог как есть, без обработки.

  4. У меня всё получилось, кроме GEO карты (((
    Сливаю логи через filebeat, обрабатываю логстешем.
    Создаю визуализацию, но в списке индексов nginx-* нет, хотя другие есть.
    Гео-метки есть (их похоже генерирует сам logstash) и графики по ним рисуются нормально.
    Что же пошло не так?

    • Да, таки невнимательно читал ))
      Требуется поменять тип данных с FLOAT на geo_point.
      Странно, что из коробки это настроено не правильно ...

  5. Здравствуйте! у меня вопрос как разделить log nginx, system,postgresql, mysql
    например: nginx отдельный индекс, postgresql отдельный индекс, systemlog отдельный ииндекс

    • Это делается в настройках logstash. На разные логи ставятся метки в filebeat, потом на основе этих меток раскладываются по разным индексам в logstash. У меня где-то в статьях есть такие примеры. Уже не помню где.

  6. спасибо за ваши статьи!
    но не могу понять как добавить визуализацию в виде логов по типу ваших [nginx-ext]Messages. с остальным разобрался вроде.

  7. У меня проксировании в nginx почему-то работает, только если в kibana.yml host указать 0.0.0.0, если оставляю стандартный localhost - то выдает ошибку http 502

  8. И да, большое спасибо за статью.

  9. Кстати, в типе данных bytes индекса nginx-* можно указать байты. Тогда смотреть отчеты по трафику можно будет в привычных кило- и мега-байтах, в зависимости от размера числа.

    • Кстати да, это может быть полезно. Хотя лично я не смотрю эти графики, так как в zabbix все это более наглядно и привычно.

  10. Как разделять сайты в 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 фильтре потом разбирать эти строки. Не сложно, я делал так.

  11. Привет, у меня такая проблема
    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. Она требует осмысления и понимания, иначе не настроить. В этом я убедился я сам, когда разбирался и настраивал разные вещи.

  12. Знаю что не по теме, но подскажите пожалуйста! У Вас на сайте если реклама блокируется, появляется баннер "нет рекламы - меньше статьей", что это плагин или это какой-нибудь свой инструмент?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить комментарий" Я даю согласие на обработку персональных данных.
Используешь Telegram? Подпишись на канал автора →
This is default text for notification bar