Настройка логирования (ELK Stack) для веб-приложения

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка логирования (ELK Stack) для веб-приложения
Сложная
~5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Настройка логирования (ELK Stack) для веб-приложения

ELK (Elasticsearch + Logstash + Kibana) или современный вариант с Beats — зрелая платформа для централизованного логирования. Она справляется с объёмами от нескольких гигабайт в сутки до терабайт, но требует внимательной настройки индексов, ресурсов и retention-политики. Без этого кластер быстро деградирует.

Выбор схемы: ELK vs EFK

Классический стек: Filebeat → Logstash → Elasticsearch → Kibana

Упрощённый для небольших объёмов: Filebeat → Elasticsearch (без Logstash, парсинг через ingest pipelines прямо в ES)

Для Kubernetes: Fluent Bit → Elasticsearch → Kibana (Fluent Bit легче Filebeat, нативная интеграция с k8s metadata)

Выбор определяется объёмом трансформаций: если нужны сложные enrichment'ы, grok-парсинг, маршрутизация по нескольким назначениям — Logstash незаменим. Если логи структурированы (JSON) и нужна просто доставка — ingest pipelines достаточно.

Развёртывание через Docker Compose

Для dev/staging окружения:

# docker-compose.yml
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
      - ELASTIC_PASSWORD=changeme
      - "ES_JAVA_OPTS=-Xms2g -Xmx2g"
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    ulimits:
      memlock:
        soft: -1
        hard: -1

  kibana:
    image: docker.elastic.co/kibana/kibana:8.13.0
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=changeme
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

  logstash:
    image: docker.elastic.co/logstash/logstash:8.13.0
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
    ports:
      - "5044:5044"   # Beats input
      - "5000:5000"   # TCP input
    depends_on:
      - elasticsearch

volumes:
  esdata:

Logstash Pipeline

Конфигурация для парсинга Nginx access log и application JSON log:

# logstash/pipeline/main.conf
input {
  beats {
    port => 5044
  }
  tcp {
    port => 5000
    codec => json_lines
  }
}

filter {
  if [fields][log_type] == "nginx_access" {
    grok {
      match => {
        "message" => '%{IPORHOST:client_ip} - %{DATA:user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{DATA:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status_code:int} %{NUMBER:bytes_sent:int} "%{DATA:referrer}" "%{DATA:user_agent}" %{NUMBER:request_time:float}'
      }
    }
    date {
      match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
      target => "@timestamp"
    }
    geoip {
      source => "client_ip"
      target => "geoip"
    }
    useragent {
      source => "user_agent"
      target => "ua"
    }
    mutate {
      remove_field => ["message", "timestamp"]
    }
  }

  if [fields][log_type] == "app_json" {
    json {
      source => "message"
      target => "app"
    }
    mutate {
      remove_field => ["message"]
    }
  }
}

output {
  if [fields][log_type] == "nginx_access" {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      user => "elastic"
      password => "changeme"
      index => "nginx-access-%{+YYYY.MM.dd}"
    }
  } else {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      user => "elastic"
      password => "changeme"
      index => "app-logs-%{+YYYY.MM.dd}"
    }
  }
}

Filebeat на серверах приложений

# /etc/filebeat/filebeat.yml
filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
    fields:
      log_type: nginx_access
    fields_under_root: false
    multiline:
      # Nginx access log — однострочный, multiline не нужен

  - type: log
    enabled: true
    paths:
      - /var/www/app/storage/logs/laravel.log
    fields:
      log_type: app_json
    multiline:
      pattern: '^\['
      negate: true
      match: after
      max_lines: 50

output.logstash:
  hosts: ["logstash-server:5044"]
  ssl.enabled: false

# Метаданные хоста
processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_fields:
      target: ''
      fields:
        environment: production
        service: web-app

Отправка логов приложения напрямую

Для Laravel — через кастомный Monolog handler:

// config/logging.php
'channels' => [
    'logstash' => [
        'driver' => 'custom',
        'via' => App\Logging\LogstashLogger::class,
        'host' => env('LOGSTASH_HOST', 'logstash'),
        'port' => env('LOGSTASH_PORT', 5000),
        'level' => 'debug',
    ],
    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'logstash'],
    ],
],
// app/Logging/LogstashLogger.php
namespace App\Logging;

use Monolog\Logger;
use Monolog\Handler\SocketHandler;
use Monolog\Formatter\JsonFormatter;

class LogstashLogger
{
    public function __invoke(array $config): Logger
    {
        $handler = new SocketHandler(
            "tcp://{$config['host']}:{$config['port']}"
        );
        $handler->setFormatter(new JsonFormatter());

        return new Logger('app', [$handler]);
    }
}

Теперь каждый Log::error(...) отправляет структурированный JSON напрямую в Logstash.

Index Lifecycle Management (ILM)

Без ILM индексы растут бесконтрольно и заполняют диск. Политика для application logs:

PUT _ilm/policy/app-logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "5gb",
            "max_age": "1d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "3d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "freeze": {},
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": { "delete": {} }
      }
    }
  }
}

Index template привязывает политику к паттерну:

PUT _index_template/app-logs-template
{
  "index_patterns": ["app-logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "index.lifecycle.name": "app-logs-policy",
      "index.lifecycle.rollover_alias": "app-logs"
    }
  }
}

Kibana: основные настройки

После первого запуска:

  1. Stack Management → Index Patterns → создать паттерн app-logs-* с полем @timestamp
  2. Discover → выбрать паттерн → убедиться что данные поступают
  3. Dashboards → создать дашборд с виджетами:
    • Top error messages (Terms aggregation по app.message.keyword)
    • HTTP status distribution (Pie chart по status_code)
    • Request rate (Date histogram по @timestamp)
    • Error rate by service (Bar chart с фильтром app.level: error)

Saved searches для быстрого доступа:

  • app.level: error AND environment: production
  • status_code >= 500
  • request_time > 3

Производительность Elasticsearch

Критичные настройки для production:

# /etc/elasticsearch/elasticsearch.yml
cluster.name: app-logging
node.name: es-node-1

# Запрет свопа
bootstrap.memory_lock: true

# Heap — не более 50% RAM, не более 31g (JVM compressed oops limit)
# Устанавливается через ES_JAVA_OPTS или jvm.options

# Slow log для отладки медленных запросов
index.search.slowlog.threshold.query.warn: 2s
index.indexing.slowlog.threshold.index.warn: 1s

# Thread pool для bulk indexing
thread_pool.write.queue_size: 200

Оптимальное количество шардов: 1 шард ≈ 20-40 GB. Слишком много мелких шардов (oversharding) — частая причина деградации кластера.

Алерты через Kibana Alerting

// Watcher для алертинга на 5xx ошибки
PUT _watcher/watch/high-error-rate
{
  "trigger": { "schedule": { "interval": "5m" } },
  "input": {
    "search": {
      "request": {
        "indices": ["nginx-access-*"],
        "body": {
          "query": {
            "bool": {
              "filter": [
                { "range": { "@timestamp": { "gte": "now-5m" } } },
                { "range": { "status_code": { "gte": 500 } } }
              ]
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": { "ctx.payload.hits.total.value": { "gt": 50 } }
  },
  "actions": {
    "notify_telegram": {
      "webhook": {
        "method": "POST",
        "url": "https://api.telegram.org/bot<TOKEN>/sendMessage",
        "body": "{\"chat_id\": \"<CHAT_ID>\", \"text\": \"5xx error spike: {{ctx.payload.hits.total.value}} errors in 5m\"}"
      }
    }
  }
}

Сроки

Развёртывание ELK через Docker Compose, настройка Filebeat на 3-5 серверах, базовые pipeline для Nginx и приложения, ILM-политика, начальные дашборды в Kibana: 2-3 рабочих дня.

Полноценная настройка с парсингом всех типов логов, alerting, настройкой безопасности (TLS, RBAC), production-конфигурацией кластера с репликацией: 5-7 дней.

Масштабирование существующего кластера или миграция с другой системы логирования оценивается отдельно после аудита.