Система сбора, анализа, уведомлений и визуализации логов на syslog-ng,elasticsearch,kibana,grafana,elasticalert

image


Что мы получим после этой статьи:


Систему сбора и анализа логов на syslog-ng, elasticsearch в качестве хранилища данных, kibana и grafana в качестве систем визуализации данных, kibana для удобного поиска по логам, elasticalert для отправки уведомлений по событиям. Приготовьтесь, туториал объемный.


Какие логи будем собирать:


  • все системные логи разложенные по индексам в зависимости от их facility (auth, syslog, messages и т.д.);
  • логи nginx — access и error;
  • логи pm2;
  • и др.


Обоснование выбора системы


Почему я выбрал связку с syslog-ng в качестве отправителя, парсера и приемщика логов? Да потому-что он очень быстрый, надежный, не требовательный к ресурсам (да да — logstash в качестве агентов на серверах и виртуальных машинах просто убожество в плане пожирания ресурсов и требованием java), с внятным синтаксисом конфигов (вы видели rsyslog? — это тихий ужас), с широкими возможностями — парсинг, фильтрация, большое количество хранилищ данных (postgresql, mysql, elasticsearch, files и т.д.), буферизация (upd не поддерживает буферизацию), сторонние модули и другие фишки.


Требования:


  • Ubuntu 16.04 или debian 8–9;
  • vm для развертывания;
  • Прямые руки.


Приступим или добро пожаловать под кат


Небольшое пояснение.
Только кластер elasticsearch можно использовать в production, система из одной ноды просто загнется. В production используем кластер из master ноды и нескольких датанод. Отказоустойчивый кластер здесь рассматривать не будем. Кому интересно — вперед гуглить. Elastic рекуомендует исполльзовать одинаковую конфигурацию для нод кластера, так как кластер все равно будет работать со скоростью самой медленной ноды. Я использую ноды по 4 cpu и 12 gb озу и 700 gb ssd.


Наша система логов будет состоять из нескольких виртуальных машин — головного сервера (elasticnode1) и датанод elasticsearch (elasticnode2–9), на которых будут только храниться данные.


Сразу поправим файл /etc/hosts, если у вас нет настроенного dns сервера.


10.10.10.210      elasticsearch-node1 elasticnode1
10.10.10.211      elasticsearch-node2 elasticnode2
10.10.10.212      elasticsearch-node3 elasticnode3
10.10.10.213      elasticsearch-node4 elasticnode4
10.10.10.214      elasticsearch-node5 elasticnode5
10.10.10.215      elasticsearch-node6 elasticnode6
10.10.10.216      elasticsearch-node7 elasticnode7
10.10.10.217      elasticsearch-node8 elasticnode8
10.10.10.216      elasticsearch-node9 elasticnode9


Компоненты головного сервера (elasticnode1):


  • syslog-ng — наш главный приемщик, обработчик и отправитель логов;
  • docker — в нем мы поднимем grafana, kibana, elasticalert;
  • kibana — визуализация и поиск логов;
  • grafana — визуализация и отправка уведомлений (на данный момент нельзя слать уведомления используя elasticsearch в качестве хранилища данных);
  • elasticalert (через него и будем слать уведомления из elasticsearch в telegram — куда же без него);
  • elasticsearch — собственно сюда и будем слать все наши данные с нод и отпарсенных файликов;
  • ubuntu 16.04 в качетве ос.


Компоненты датанод (elasticнode2-elasticnode7):


  • elasticsearch;
  • ubuntu 16.04 в качестве ос.


Компоненты отправителей логов:


  • ubuntu или debian;
  • syslog-ng.


На данный момент появилась версия 6 продуктов elasticsearch, kibana и т.д., я же в production использую 5.6.3 — пока не было возможности мигрировать на последнюю версию.


Настраиваем отправители логов.


Устанавливаем syslog-ng последней версии. Ставить будем из репозитория. Здесь установка для Ubuntu 16.04.


systemct disable rsyslog; systemctl stop rsyslog; apt-get purge rsyslog -y

wget -P . http://download.opensuse.org/repositories/home:/laszlo_budai:/syslog-ng/xUbuntu_17.04/Release.key; apt-key add Release.key

echo "deb http://download.opensuse.org/repositories/home:/laszlo_budai:/syslog-ng/xUbuntu_16.10 ./" > /etc/apt/sources.list.d/syslog-ng-obs.list

wget http://no.archive.ubuntu.com/ubuntu/pool/main/j/json-c/libjson-c3_0.12.1-1.1_amd64.deb && dpkg -i libjson-c3_0.12.1-1.1_amd64.deb

apt-get update && apt-get install syslog-ng-core -y


Тюним sysctl.conf


Затираем


: > /etc/sysctl.conf


Вставляем


nano /etc/sysctl.conf


vm.swappiness=1
vm.max_map_count=262144
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 262144 4194304
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_tw_reuse  =  1
net.ipv4.tcp_tw_recycle  =  1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_rmem = 4096 262144 4194304
net.ipv4.tcp_rfc1337 = 1
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_mem = 50576   64768   98152
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 20
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_congestion_control = htcp
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.route.flush = 1
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.ip_forward = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.lo.accept_source_route = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.core.wmem_default = 65536
net.core.somaxconn = 65535
net.core.rmem_default = 65536
net.core.netdev_max_bacтlog = 100000
kernel.sem = 350 358400 64 1024
fs.inotify.max_user_watches = 67108864
fs.file-max = 518144


Применяем


sysctl -p


Настраиваем syslog-ng для пирсинга и отправки логов с клиента на сервер.


Приводим /etc/syslog-ng/syslog-ng.conf к такому виду.


@version: 3.13
@include "scl.conf"

# Настраиваем глобальные параметры
options { 
chain_hostnames(off);
log_fifo_size(1000);
use_dns(no); 
use_fqdn(no);
owner("root");
group("adm");
perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};

@include "/etc/syslog-ng/conf.d/*.conf"


Создаем конфиг отправки логов на сервер.


mkdir -p /etc/syslog-ng/conf.d/


Вставляем сюда следующее содержимое


nano /etc/syslog-ng/conf.d/output.conf


source s_src {
       system();
       internal();
};
destination d_net {
udp("elasticnode1" port(514)
);
};
log { source(s_src); destination(d_net); };


Таким образом мы все логи будет отправлять по udp на 514 порт сервера. Там он с ними разберется — разложит по индексам, отфильтрует и т.д.


Настройка отправки nginx access и error логов, через вывод содержимого лога и отправки по udp на обозначенные порты.


Почему я выбрал вывод содержимого из файла и отправку по udp, а не прямую отправку из nginx на порт? У меня возникали непонятные баги при отправке логов напрямую из nginx (сервер начинал возвращать много 500 и 502 ошибок).


Настройка логов для отправки в nginx. Отреадктируем конфиг nginx.conf.


#формат логов nginx, который будет принимать syslog-ng.
log_format full_format '"$time_iso8601"|"$http_host"|"$remote_addr"|"$http_x_forwarded_for"|"$request_method"|"$request"|"$status"|"$body_bytes_sent"|"$http_referer"|"$request_time"|"$upstream_http_x_cache"|"$uri"|"$upstream_addr"|"$host"|"$upstream_response_length"|"$upstream_status"|"$server_name"|"$http_host"|"$upstream_response_time"|"$upstream_cache_status"|"$http_user_agent"|"$scheme://$host$request_uri"|"$cookie_bar"'; 
access_log /var/log/nginx/access.log full_format;
error_log /var/log/nginx/error.log;


Делаем рестарт nginx. Все логи будут падать (если у вам не переопределено в конфигах) в папку /var/log/nginx/ в 2 файла указанных выше.


Настраиваем syslog-ng на чтение файлов и отправку по udp.


nano /etc/syslog-ng/conf.d/output-nginx-logs.conf


####Отправка логов на сервер nginx_access
destination udp_remote_log_host_nginx_main {
udp("elasticnode1" port(25230)

);
};

###### Источник с логами nginx access##################
source s_tail_log_host_nginx_main { file( "/var/log/nginx/access_main.log"
                    follow_freq(1)    
                    flags(no-parse)             
     );
};

log {source(s_tail_log_host_nginx_main); destination(udp_remote_log_host_nginx_main);};

####Отправка логов на сервер nginx_error
destination d_server_nginx_error {
udp("elasticnode1" port(25231)

);
};

 source s_tail_nginx_error  { file( "/var/log/nginx/error.log"
                    follow_freq(1)    
                    flags(no-parse)             
     );
};
log {source(s_tail_nginx_error ); destination(d_server_nginx_error);};


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


#!/bin/bash
find /var/log/elasticsearch/* -type f -ctime +2 | xargs rm -rf

    for FILES in \
        *.gz \
        *.log.* \
        *.log \
        *.1 \
    ; do
        /usr/bin/find /var/log/ -name "$FILES" -type f  | xargs /bin/rm  -rf
    done
echo "Переинициализация логов nginx"

[ ! -f /var/run/nginx.pid ] || /bin/kill -USR1 `/bin/cat /var/run/nginx.pid`

/usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2>&1


Настраиваем головной сервер с syslog-ng, elasticsearch, kibana, grafana и elasticalert.


Для начала «тюним» систему.


Тюним limits.conf


Затираем


: > /etc/security/limits.conf


Вставляем


nano /etc/security/limits.conf


* - nofile 999999
* soft memlock unlimited
* soft memlock unlimited
* hard memlock unlimited
* soft nofile 999999
* hard nofile 999999
elasticsearch    soft    nofile          65535
elasticsearch    hard    nofile          65535
elasticsearch    soft    memlock         unlimited
elasticsearch    hard    memlock         unlimited


Проверяем


ulimit -a


Тюним sysctl.conf


Затираем


: > /etc/sysctl.conf


Вставляем


nano /etc/sysctl.conf


vm.swappiness=1
vm.max_map_count=262144
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 262144 4194304
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_tw_reuse  =  1
net.ipv4.tcp_tw_recycle  =  1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_rmem = 4096 262144 4194304
net.ipv4.tcp_rfc1337 = 1
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_mem = 50576   64768   98152
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 20
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_congestion_control = htcp
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.route.flush = 1
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.ip_forward = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.lo.accept_source_route = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.core.wmem_default = 65536
net.core.somaxconn = 65535
net.core.rmem_default = 65536
net.core.netdev_max_bacтlog = 100000
kernel.sem = 350 358400 64 1024
fs.inotify.max_user_watches = 67108864
fs.file-max = 518144


Применяем


systctl -p


Отключаем swap.



swapoff -a 


Удаляем rsyslog


systemctl disable rsyslog
systemctl stop rsyslog
apt purge rsyslog -y


Собираем syslog-ng из исходников со всеми модулями последней версии для нашего сервера.


Зависимости:


apt-get install bison gcc+ libglib2.0-0 libpcre3 glib-2.0 libglib2.0-dev flex python-dev libriemann-client-dev riemann-c-client libhiredis-dev libesmtp-dev libnet-dev libmaxminddb-dev libgeoip-dev libdbi-dev autoconf-archive libpixman-1-dev -y 


Устанавливаем granle


wget https://services.gradle.org/distributions/gradle-4.4-bin.zip
mkdir /opt/gradle
unzip -d /opt/gradle gradle-4.4-bin.zip
ls /opt/gradle/gradle-4.4
export PATH=$PATH:/opt/gradle/gradle-4.4/bin
configure && make && make install


Ставим java8 и экспортируем пути


apt-get install openjdk-8-jdk -y

export LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server:$LD_LIBRARY_PATH


Клонируем репозиторий syslog-ng, собираем и устанавливаем


git clone https://github.com/balabit/syslog-ng/
cd syslog-ng
./autogen.sh
./configure --enable-all-modules --enable-systemd 
make -j4 &&  make install
ldconfig -v 


Добавляем init.d скрипт — если вы ничего не меняли при сборке (пути) то все будет работать.


nano /etc/init.d/syslog-ng 


#! /bin/sh
### BEGIN INIT INFO
# Provides:          syslog-ng
# Required-Start:    $local_fs $network $time $remote_fs
# Required-Stop:     $local_fs $network $time $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starting system logging daemon
# Description:       Starting syslog-NG, the next generation
#  syslog daemon.
### END INIT INFO#

set -e

SYSLOGNG_OPTS=""

#we source /etc/default/syslog-ng if exists
[ -r /etc/default/syslog-ng ] && . /etc/default/syslog-ng

# stop syslog-ng before changing its PID file!
PIDFILE="/var/run/syslog-ng.pid"

SYSLOGNG="/usr/sbin/syslog-ng"
NAME="syslog-ng"

PATH=/sbin:/bin:/usr/sbin:/usr/bin
test -f $SYSLOGNG || exit 0

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

case "x$CONSOLE_LOG_LEVEL" in
  x[1-8])
    dmesg -n $CONSOLE_LOG_LEVEL
    ;;
  x)
    ;;
  *)
    log_warning_msg "CONSOLE_LOG_LEVEL is of unaccepted value."
    ;;
esac

create_xconsole() {
    XCONSOLE=/dev/xconsole
    if [ "$(uname -s)" = "GNU/kFreeBSD" ]; then
        XCONSOLE=/var/run/xconsole
        ln -sf $XCONSOLE /dev/xconsole
    fi
    if [ ! -e $XCONSOLE ]; then
        mknod -m 640 $XCONSOLE p
        chown root:adm $XCONSOLE
        [ -x /sbin/restorecon ] && /sbin/restorecon $XCONSOLE
    fi
}

create_pidfiledir() {
    if [ ! -d /var/run/syslog-ng ]
    then
        mkdir -p /var/run/syslog-ng
    fi
}

syslogng_wait() {
    if [ "$2" -ne 0 ]; then
        return 1
    fi

    if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ]; then
        return 0
    fi

    RET=1
    for i in $(seq 1 30); do
        status=0
        syslog-ng-ctl stats >/dev/null 2>&1 || status=$?
        if [ "$status" != "$1" ]; then
            RET=0
            break
        fi
        sleep 1s
    done
    return $RET
}

syslogng_start() {
    log_daemon_msg "Starting system logging" "$NAME"
    create_pidfiledir
    create_xconsole
    start-stop-daemon --start --oknodo --quiet --exec "$SYSLOGNG" \
                      --pidfile "$PIDFILE" -- -p "$PIDFILE" $SYSLOGNG_OPTS
    syslogng_wait 1 $?
    RET="$?"
    log_end_msg $RET
    return $RET
}

syslogng_stop() {
    log_daemon_msg "Stopping system logging" "$NAME"
    start-stop-daemon --stop --oknodo --quiet --name "$NAME" --retry 3 \
                      --pidfile "$PIDFILE"
    syslogng_wait 0 $?
    RET="$?"
    log_end_msg $RET
    return $RET
}

syslogng_reload() {
    log_daemon_msg "Reload system logging" "$NAME"
    if $SYSLOGNG -s $SYSLOGNG_OPTS
    then
      start-stop-daemon --stop --signal 1 --quiet --exec "$SYSLOGNG" \
                        --pidfile "$PIDFILE"
      syslogng_wait 1 $?
      RET="$?"
      log_end_msg $RET
      return $RET
    else
      log_end_msg 1
      return 1
    fi
}

case "$1" in
  start)
    syslogng_start || exit 1
    ;;
  stop)
    syslogng_stop || exit 1
    ;;
  reload|force-reload)
    syslogng_reload || exit 1
    ;;
  restart)
    syslogng_stop
    syslogng_start || exit 1
    ;;
  status)
    status_of_proc "$SYSLOGNG" "$NAME" && exit 0 || exit $?
    ;;
  *)
    echo "Usage: /etc/init.d/$NAME {start|stop|restart|reload|force-reload|status}" >&2
    exit 1
    ;;
esac

exit 0


Даем ему права и делаем unmask


chmod +x /etc/init.d/syslog-ng &&  systemctl unmask syslog-ng


Устанавливаем elasticsearch из пакета deb.


wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.3.deb
dpkg -i elasticsearch-5.6.3.deb


Еще небольшие манипуляции. Создадим каталог для данных и сделаем автозапуска elasticsearch после рестарта системы.


mkdir /elasticsearchdata/ &&  chown -R elasticsearch:elasticsearch /elasticsearchdata/
update-rc.d elasticsearch defaults 95 10
sudo /bin/systemctl daemon-reload
sudo /bin/systemctl enable elasticsearch.service


Настроим elasticsearch на макимальное использование памяти. Для этого elasticsearch.service приводим к такому виду.


nano /usr/lib/systemd/system/elasticsearch.service


[Unit]
Description=Elasticsearch
Documentation=http://www.elastic.co
Wants=network-online.target
After=network-online.target

[Service]
Environment=ES_HOME=/usr/share/elasticsearch
Environment=CONF_DIR=/etc/elasticsearch
Environment=DATA_DIR=/var/lib/elasticsearch
Environment=LOG_DIR=/var/log/elasticsearch
Environment=PID_DIR=/var/run/elasticsearch
EnvironmentFile=-/etc/default/elasticsearch
LimitMEMLOCK=infinity
WorkingDirectory=/usr/share/elasticsearch

User=elasticsearch
Group=elasticsearch

ExecStartPre=/usr/share/elasticsearch/bin/elasticsearch-systemd-pre-exec

ExecStart=/usr/share/elasticsearch/bin/elasticsearch \
                                                -p ${PID_DIR}/elasticsearch.pid \
                                                --quiet \
                                                -Edefault.path.logs=${LOG_DIR} \
                                                -Edefault.path.data=${DATA_DIR} \
                                                -Edefault.path.conf=${CONF_DIR}

# StandardOutput is configured to redirect to journalctl since
# some error messages may be logged in standard output before
# elasticsearch logging system is initialized. Elasticsearch
# stores its logs in /var/log/elasticsearch and does not use
# journalctl by default. If you also want to enable journalctl
# logging, you can simply remove the "quiet" option from ExecStart.
StandardOutput=journal
StandardError=inherit

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Specifies the maximum number of processes
LimitNPROC=2048

# Specifies the maximum size of virtual memory
LimitAS=infinity

# Specifies the maximum file size
LimitFSIZE=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=0

# SIGTERM signal is used to stop the Java process
KillSignal=SIGTERM

# Send the signal only to the JVM rather than its control group
KillMode=process

# Java process is never killed
SendSIGKILL=no

# When a JVM receives a SIGTERM signal it exits with code 143
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

# Built for distribution-5.6.3 (distribution)


Релоадим systemctl после изменения


systemctl daemon-reload


Отредактируем файл /etc/elasticsearch/jvm.options


nano /etc/elasticsearch/jvm.options


Даем половину озу — у меня 12 гигабайт на VM — в heap space поставил 6g, по рекомендациям разработчиков elasticsearch.


# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space
-Xms6g
-Xmx6g


Редактируем конфиг elasticsearch на нашем головном сервере. Приводим к виду


nano /etc/elasticsearch/elasticsearch.yml


network.host: 0.0.0.0
cluster.name: "production"
node.name: elasticnode1
discovery.zen.ping.unicast.hosts: ["elasticnode1", "elasticnode2", "elasticnode3","elasticnode4","elasticnode5","elasticnode6","elasticnode7","elasticnode8","elasticnode9"]
# avoid swapping the Elasticsearch
bootstrap.memory_lock: true
###Make node master - non data
node.master: true
node.data: false
# minimum_master_nodes need to be explicitly set when bound on a public IP
discovery.zen.minimum_master_nodes: 1
path.data: /elasticsearchdata/


Здесь мы поменяли путь для данных, задали имя кластера, указали что он у нас является мастер нодой (управляет распределением данных в кластере), не является дата нодой (не хранит данные), указали список всех нод кластера, отключили swap для elasticsearch (bootstrap.memory_lock: true), указали минимальное количество мастер нод для нашего кластера — 1 (мы здесь не делаем HA).


Запускаем кластер elasticsearch, предварительно почистив старую дата директорию.


rm -rf /var/lib/elasticsearch/* && /etc/init.d/elasticsearch restart


Смотрим здоровье кластера из консоли


curl -XGET 'http://elastinode1:9200/_cluster/state?pretty'

curl http://elastinode1:9200/_nodes/process?pretty


Настраиваем датаноды elasticsearch — elasticnode2–9


Правим файл /etc/hosts как указано выше


Устанавливаем elasticsearch (не забываем про /usr/lib/systemd/system/elasticsearch.service и /etc/elasticsearch/jvm.options) и тюнингуем систем аналогично мастеру. Важно — обязательно должны быть одинаковые версии elasticsearch на всех нодах.


Конфиг elasticsearch на датаноде.


nano /etc/elasticsearch/elasticsearch.yml


network.host: 0.0.0.0
cluster.name: "production"
node.name: elasticnode2
discovery.zen.ping.unicast.hosts: ["elasticnode1", "elasticnode2", "elasticnode3", "elasticnode4", "elasticnode5", "elasticnode6", "elasticnode7", "elasticnode8", "elasticnode9"]
# avoid swapping the Elasticsearch
bootstrap.memory_lock: true
###Make node master - non data
node.master: false 
node.data: true
# minimum_master_nodes need to be explicitly set when bound on a public IP
discovery.zen.minimum_master_nodes: 1
path.data: /elasticsearchdata/ 


Здесь конфиг аналогично мастеру — мы поменяли путь для данных, задали имя кластера, указали что он у нас является датанодой (хранит данные), указали список всех нод кластера, отключили swap для elasticsearch (bootstrap.memory_lock: true), указали минимальное количество мастернод для нашего кластера — 1.


Стартуем ноды, предварительно стерев /var/lib/elasticsearch/ иначе будет выдавать ошибку, так как мы поменяли путь хранения данных.


rm -rf /var/lib/elasticsearch/* && /etc/init.d/elasticsearch restart


Сразу определимся, как добавить новую датаноду и сделать ребалансировку кластера.


Просто добавляем новую ноду в конфиги на все ноды кластера в строку discovery.zen.ping.unicast.hosts, при этом рестарт elasticsearch в текущем кластере делать не надо.


Запускаем процесс ребалансировки на головном сервере с помощь запроса через командную строку


curl -XPUT http://elasticnode1:9200/_cluster/settings -d '{
    "transient" : {
        "cluster.routing.allocation.enable" : "all"
    }
}'


Так же сразу потюним еще одну вещь cluster.routing.allocation.disk.watermark.


curl -XPUT http://elasticnode1:9200/_cluster/settings -d '{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "90%",
    "cluster.routing.allocation.disk.watermark.high": "10gb",
    "cluster.info.update.interval": "1m"
  }
}'


Здесь мы определяем минимальное доступное место для работы кластера, преодолев данный порог он перестанет работать — принимать данные.


Установка kibana и grafana на головной сервер.


Kibana и grafana можно спокойно запускать через docker-compose, что мы и сделаем ниже. В принципе всю систему можно поднять через docker-compose. Ниже я выложу ссылку на репозиторий где все можно поднять одной командой, что в принципе для небольших систем и для тестирования вполне приемлимо. Докер это наше всё.


Ставим докер и docker-compose на ubuntu 16.04


apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |  apt-key add -
add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

apt-get update && apt-get install docker-ce -y
curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose


Создаем файл docker-compose.yml с таким содержанием. Обратите внимание в enviroment kibana.local прописал


"ELASTICSEARCH_URL=http://elasticnode1:9200" - адрес нашего elasticsearch


Содержимое docker-compose.yml


version: '3.3'

services:

  kibana.local:
    image: kibana:5.6.3
    container_name: kibana.local
    hostname: kibana.local
    ports:
      - "5601:5601"
    networks:
      - local-network
    tty: true
    privileged: true
    restart: always
    extra_hosts:
      - "elasticnode1:10.10.10.210"
    environment:
       - "TZ=Asia/Yekaterinburg"
       - "ELASTICSEARCH_URL=http://elasticnode1:9200"

  grafana.local:
    image: grafana/grafana
    container_name: grafana.local
    hostname: grafana.local
    volumes:
      - ./configs/grafana/:/etc/grafana/
      - ./data/grafana/:/var/lib/grafana/
      - ./data/grafana/:/var/log/grafana/
    ports:
      - "13000:3000"
    networks:
      - local-network
    tty: true
    privileged: true
    restart: always
    environment:
      - "TZ=Asia/Yekaterinburg" 
      - "GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,vonage-status-panel,grafana-piechart-panel,grafana-worldmap-panel"

networks:
  local-network:
      driver: bridge


Запускаем docker-compose


docker-compose up -d


В grafana по-умолчанию пользователь и пароль admin admin.


Заходим в kibana — видим что все ок.
image


Идем далее.


Настройка приема системных логов syslog-ng, их обработки и отправки в kibana.


Скачаем сразу базу данных geoip2 maxmind для построения в дальнейшем geoip карты. Анализатор (парсер) geoip2 syslog-ng 2 использует библиотеку maxminddb для поиска географической информации. По заверениям разработчиков он значительно быстрее, чем его предшественник, а также предоставляет более подробную информацию.


Скачаем и распакуем.


cd /usr/local/etc 
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
gunzip GeoLite2-City.mmdb.gz


Сразу проверим на примере.


mmdblookup --file GeoLite2-City.mmdb --ip 1.2.3.4

Вывод

  {
    "city": 
      {
        "geoname_id": 
          3054643 
        "names": 
          {
            "de": 
              "Budapest" 
            "en": 
              "Budapest" 
            "es": 
              "Budapest" 
            "fr": 
              "Budapest" 
            "ja": 
              "ブダペスト" 
            "pt-BR": 
              "Budapeste" 
            "ru": 
              "Будапешт" 
            "zh-CN": 
              "布达佩斯" 
          }
      }
[...]
    "location": 
      {
        "accuracy_radius": 
          100 
        "latitude": 
          47.500000 
        "longitude": 
          19.083300 
        "time_zone": 
          "Europe/Budapest" 
      }
[...]


Окей. Идем далее.


Создадим симлинк каталога в который мы установили syslog-ng в /etc/syslog-ng — так удобнее, для тех кто привык к стандартному расположений syslog-ng.


ln -s /usr/local/etc /etc/syslog-ng


Отредактируем главный конфиг — приведем к такому виду:


nano /usr/local/etc/syslog-ng.conf


@version: 3.13
@include "scl.conf"
@module mod-java

# Настраиваем глобальные параметры
options { 
chain_hostnames(off);
log_fifo_size(1000000);
use_dns(no); 
use_fqdn(no);
owner("root");
group("adm");
perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};

@include "/usr/local/etc/conf.d/*.conf"


Создадим каталог в котором мы будем инклудить все конфиги для удобства.


mkdir -p /usr/local/etc/conf.d


Теперь вставим конфиги по приему системных логов с других машин и отправку их в elasticsearch c разбиением по индексам.


nano /usr/local/etc/conf.d/input.conf


###Принимаем логи на порт по udp 514
source udp-remote-system-logs {
udp(port(514)
log_iw_size(1000)
log_fetch_limit(1000000));};

########################
# Блок с фильтрами
########################
filter f_dbg { level(debug); };
filter f_info { level(info); };
filter f_notice { level(notice); };
filter f_warn { level(warn); };
filter f_err { level(err); };
filter f_crit { level(crit .. emerg); };

filter f_debug { level(debug) and not facility(auth, authpriv, news, mail); };
filter f_error { level(err .. emerg) ; };
filter f_messages { level(info,notice,warn) and 
                    not facility(auth,authpriv,cron,daemon,mail,news); };

filter f_auth { facility(auth, authpriv) and not filter(f_debug); };
filter f_cron { facility(cron) and not filter(f_debug); };
filter f_daemon { facility(daemon) and not filter(f_debug); };
filter f_kern { facility(kern) and not filter(f_debug); };
filter f_lpr { facility(lpr) and not filter(f_debug); };
filter f_local { facility(local0, local1, local3, local4, local5,
                        local6, local7) and not filter(f_debug); };
filter f_mail { facility(mail) and not filter(f_debug); };
filter f_news { facility(news) and not filter(f_debug); };
filter f_syslog3 { not facility(auth, authpriv, mail) and not filter(f_debug); };
filter f_user { facility(user) and not filter(f_debug); };
filter f_uucp { facility(uucp) and not filter(f_debug); };

filter f_cnews { level(notice, err, crit) and facility(news); };
filter f_cother { level(debug, info, notice, warn) or facility(daemon, mail); };

filter f_ppp { facility(local2) and not filter(f_debug); };
filter f_console { level(warn .. emerg); };

###Куда будем писать логи - в данном случае в elasticsearch 
###Каждому типу лога сделаем свой отдельный индекс с добавление года и месяца создания, чтобы потом можно было легко их найти

########################
# auth logs 
########################
destination d_elastic_auth {
  elasticsearch2(
    index("auth-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs);filter(f_auth); destination(d_elastic_auth); };

########################
# crons logs 
########################
destination d_elastic_crons {
  elasticsearch2(
    index("crons-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_cron); destination(d_elastic_crons); };

########################
# kern logs  
########################
destination d_elastic_kern {
  elasticsearch2(
    index("kern-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs ); filter(f_kern); destination(d_elastic_kern); };

########################
# daemon logs  
########################
destination d_elastic_daemon {
  elasticsearch2(
    index("daemon-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_daemon); destination(d_elastic_daemon); };

########################
# user logs  
########################
destination d_elastic_user {
  elasticsearch2(
    index("user-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_user); destination(d_elastic_user); };

########################
# lpr logs  
########################
destination d_elastic_lpr {
  elasticsearch2(
    index("lpr-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_lpr); destination(d_elastic_lpr); };

########################
# syslog logs  
########################
destination d_elastic_syslog {
  elasticsearch2(
    index("syslog-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_syslog3);destination(d_elastic_syslog); };

########################
# uucp logs  
########################
destination d_elastic_uucp {
  elasticsearch2(
    index("uucp-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_uucp); destination(d_elastic_uucp); };

########################
# mail logs  
########################
destination d_elastic_mail {
  elasticsearch2(
    index("mail-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_mail);destination(d_elastic_mail); };

########################
# messages logs  
########################
destination d_elastic_messages {
  elasticsearch2(
    index("messages-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_messages); destination(d_elastic_messages); };

########################
# debug logs  
########################
destination d_elastic_debug {
  elasticsearch2(
    index("debug-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_debug); destination(d_elastic_debug); };

########################
# error logs  
########################
destination d_elastic_error {
  elasticsearch2(
    index("error-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_error);destination(d_elastic_error); };

########################
# info logs  
########################
destination d_elastic_info {
  elasticsearch2(
    index("info-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};
log { source(udp-remote-system-logs); filter(f_info); destination(d_elastic_info); };


Конфиги syslog-ng легко читаемы и понятны с первого раза. Не устану это повторять.


Теперь создадим конфиг для приема других логов — nginx access и error (php errors логи так же будем слать в error.log), nodejs.


nano /usr/local/etc/conf.d/input-web.conf


#формат логов nginx, который будем принимать, здесь я его разместил для наглядности сопоставления с парсером этих логов, в качестве разделителей полей используем символ "|"
#log_format full_format '"$time_iso8601"|"$http_host"|"$remote_addr"|"$http_x_forwarded_for"|"$request_method"|"$request"|"$status"|"$body_bytes_sent"|"$http_referer"|"$request_time"|"$upstream_http_x_cache"|"$uri"|"$upstream_addr"|"$host"|"$upstream_response_length"|"$upstream_status"|"$server_name"|"$http_host"|"$upstream_response_time"|"$upstream_cache_status"|"$http_user_agent"|"$scheme://$host$request_uri"|"$cookie_bar"'; 
#access_log /var/log/nginx/access.log full_format;
#error_log /var/log/nginx/error.log;

#Докер со сборкой nginx + libressl + syslog-ng + nodejs можно найти здесь - https://github.com/galushkoav/nginx-php-nodejs

##Принмаем  nginx access логи на порт 25230 по udp
source udp-nginx-acessfull {
udp(port(25230)
log_iw_size(1000)
log_fetch_limit(1000000)) ;
};

###Парсим принятые логи nginx, здесь мы указываем имена полей, куда будут попадать данные, укажем также разделитель полей символ "|"
parser p-nginx-acessfull-mapped {
    csv-parser(columns("nginx.time", "nginx.http_host", "nginx.remote_addr", "nginx.http_x_forwarded_for", "nginx.request", "nginx.request_method","nginx.status", "nginx.body_bytes_sent", "nginx.http_referer", "nginx.request_time", "nginx.upstream_http_x_cache", "nginx.uri", "nginx.upstream_addr", "nginx.host", "nginx.upstream_response_length", "nginx.upstream_status", "nginx.server_name", "nginx.newurl", "nginx.upstream_response_time", "nginx.upstream_cache_status", "nginx.user_agent","nginx.request_uri","nginx.http_cookie" )
         flags(escape-double-char,strip-whitespace)
         delimiters("|")
         quote-pairs('""[]')
         );
};

###Здесь мы сверяем прилетающий ip из логов nginx -  в поле "nginx.remote_addr" с нашей базой данных maxmidn geoip2
parser p_geoip2 { geoip2( "${nginx.remote_addr}", prefix( "geoip2." ) database( "/usr/local/etc/GEO/GeoLite2-City_20171205/GeoLite2-City.mmdb" ) ); };

##Rewrite необходим для того, чтобы информация о местоположении находилась в форме, ожидаемой Elasticsearch. Он выглядит несколько более сложным, чем для первой версии анализатора GeoIP, поскольку имеется больше информации и информация теперь структурирована.

rewrite r_geoip2 {
    set(
        "${geoip2.location.latitude},${geoip2.location.longitude}",
        value( "geoip2.location2" ),
        condition(not "${geoip2.location.latitude}" == "")
    );
};

###Направляем nginx_access в elasticsearch - затем добавим индекс  в кибана nginx-access-geo-*
destination d_elastic-nginx-acessfull {
  elasticsearch2(
    index("nginx-access-geo-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
    type("netdata")
    persist-name(elasticsearch-netdata)
  );
};

log {source (udp-nginx-acessfull);
parser(p-nginx-acessfull-mapped);
rewrite(r_geoip2);
parser(p_geoip2);
destination(d_elastic-nginx-acessfull);};

##Принимаем  nginx error логи на порт 25231 по udp
source udp-nginx-error {
udp(port(25231)
log_iw_size(1000)
log_fetch_limit(1000000));
};

destination d_elastic-nginxerror {
  elasticsearch2(
    index("nginxerror-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")
  );
};

###########фильтры  - исключим unlink

filter f_tail_nginx_error_unlink {not match ("unlink") ;};
log {source(udp-nginx-error); filter(f_tail_nginx_error_unlink); destination(d_elastic-nginxerror); };


Сохраняемся.


Поясню, какого вида имя index будет создаются в elasticsearch — формат имени будет иметь вид «базовоеимяиндекса-год.месяц», например nginx-access-geo-2018.01. В принципе здесь всё понятно, так как добавляется год и месяц после индекса — nginx-access-geo-${YEAR}.${MONTH}.


Подготовливаем индекс elasticsearch для примема логов nginx access — сделаем mapping для нашего первого индека nginx-access-geo-2018.01:


  • поля nginx.upstream_response_time и nginx.request_time типом float вместо string, для возможности нахождения среднего значения по времени ответа сервера и ответа upstreams;
  • создадим mapping в elasticsearch для geoip, чтобы можно было строить карту с помощью геолокации.


Важно. Всё это делает для индекса nginx-access-geo-2018.01(у нас так настроен формат в syslog-ng), т.е. после окончания месяца необходимо заново выполнить этот запрос, только вместо nginx-access-geo-2018.01 сделать nginx-access-geo-2018.02 и т.д.


Все эти манипуляции необходимо проделать до начала отправки логов в elasticsearch.


curl -X PUT 'http://elasticnode1:9200/nginx-access-geo-2018.01' -d \
'{
   "mappings" : {
      "_default_" : {
        "properties" : {
            "nginx" : {
               "properties" : {
                  "request_time": {
                     "type": "float"
              },
                  "upstream_response_time": {
                     "type": "float"
              }
          }
      },

            "geoip2" : {
               "properties" : {
                  "location2" : {
                     "type" : "geo_point"
             },
                  "geoip2.subdivisions.0.names.en" : {
                     "type": "text",
                     "fielddata": true
             },
                  "geoip2.registered_country.names.en" : {
                     "type": "text",
                     "fielddata": true
            }
           }
        }
      }
    }
  }
}
}
}'


Увидим в выводе что всё ок.


Смотрим наш индекс.


curl -X GET 'http://elasticnode1:9200/nginx-access-geo-2018.01'


Увидели что все что нужно создано.


Проверяем syslog-ng, запускаем с выводом в консоль


syslog-ng -Fvde 


Если ошибок нет — стартуем как демон


/etc/init.d/syslog-ng start


После определенного времени — когда к нам упадут логи заходим в elasticsearch и создаем наш индекс.


image


Сбор и отправка логов pm2 c помощью syslog-ng.


Pm2 должен быть запущен со следующими опциями.


--merge-logs --log-type=json --log-date-format="YYYY-MM-DD HH:mm Z"


Создадим конфиг отправки на клиенте или допишем в существующий. Будем отсылать на отдельный порт.


####Источник с логами nodejs
destination d_server_pm2logs {
 udp("elasticnode1" port(25216));
 };

source s_tail_pm2  { file( "/root/.pm2/logs/server-error.log"
                    follow_freq(1)    
                    flags(no-parse)             
     );
};

###Отправляем все источники на сервер - там их будем парсить и писать в нужные базы.
log {source(s_tail_pm2); destination(d_server_pm2logs);}


На сервере создаем конфиг на принятие данного лога и его отправку в elasticsearch.


##Прием логов nodejs  с удаленных машин  на порт 
source remote_log_host_nodejs {
 udp(port(25216) log_iw_size(1000) log_fetch_limit(1000000) flags(no-parse));
};

###Направляем nodejs логи  в elasticsearch
destination d_elastic_pm2logs {
  elasticsearch2(
    #client-lib-dir("/usr/share/elasticsearch/lib/")
    index("pm2logs-${YEAR}.${MONTH}")
    type("test")
    time-zone("UTC")
    client_mode("http")
    flush-limit("10000")
    cluster_url("http://elasticnode1:9200")
    custom_id("${UNIQID}")
    template("$(format_json --scope nv_pairs --key ISODATE @timestamp=${ISODATE})")

  );
};

log {
    source(remote_log_host_nodejs);
    destination(d_elastic_pm2logs);
};


Перезапускаем syslog-ng на сервере и клиенте и добавляем индекс в kibana.


На этом настройка syslog-ng закончена.


Поиск логов в kibana и построение визуализаций.


Перейдем в наш индекс и сразу для проверки наших настроек попробуем найти все ответы сервера nginx, c временем ответа больше 2 секунд, для этого в поле делаем запрос nginx.request_time: [2 TO *].


image


Сверху выбираем период за который мы хотим получить события и частоту обновления данных. В данном случаем мы выбраои период 24 часа с частотой обновления данных 30 секунд.


image


Как мы видим на выдало 14 событий (hits).


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


image


Так же поля доступны слева на панели


image


Теперь добавим другие наши индексы, которые мы указали в конфиге (если в них уже есть данные). Проверяем индексы командой:


curl 'http://elasticnode1:9200/_cat/indices?v'


У меня получился примерно такой вывод:


health status index                    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   nginxerror-2018.01.03    jQVq1YWrSayxJ-zAeOeNKA   5   1         24            0    165.1kb        165.1kb
yellow open   nginxerror-2018.01.05    dJ0D2ronQWiGcCjj_jVNHg   5   1         96            0    183.9kb        183.9kb
yellow open   kern-2018.01             URAOk3_GRX6MMZfW8hLPbA   5   1       4196            0      1.5mb          1.5mb
yellow open   messages-2018.01         DiU8IEV2RseZ2mQNx2CJxA   5   1       4332            0      1.5mb          1.5mb
yellow open   syslog-2018.01           de2SOs8KRBGNkfd1ja4Mmg   5   1      38783            0     26.1mb         26.1mb
yellow open   .kibana                  jLUuELr-TRGSVr5JzPX52w   1   1          5            0     44.6kb         44.6kb
yellow open   error-2018.01            cnD8VeGkQa2n8HRTnC74SQ   5   1        671            0    438.6kb        438.6kb
yellow open   nginxerror-2018.01.06    z1eT1JC1QLC0AqyIQoj9ng   5   1         47            0    214.6kb        214.6kb
yellow open   nginx-access-geo         41WmT6BARUiQNjuahFhe1g   5   1       8583            0       14mb           14mb
yellow open   syslog-ng                hE37Hu2JRd-lyJaq7nDh-A   5   1         52            0    197.2kb        197.2kb
yellow open   nginx-access-geo-2018.01 MfinD9z7SB-vIMRZcXJevw   5   1       2676            0        6mb            6mb
yellow open   debug-2018.01            SwxEA6sSQjGSMBm6FcyAww   5   1        507            0    362.3kb        362.3kb
yellow open   crons-2018.01            MOJetHGjQs-Gd3Vmg5kxHw   5   1        111            0    149.7kb        149.7kb
yellow open   user-2018.01             zbRxNpGsShWwz43LXjPaAw   5   1        571            0      392kb          392kb
yellow open   auth-2018.01             shHvBE8GSdCi2CIjTxNovg   5   1        468            0    370.8kb        370.8kb
yellow open   daemon-2018.01           p97FQLBHTbyy-sM23oJpWQ   5   1      33754            0     25.1mb         25.1mb
yellow open   nginxerror-2018.01.04    dJ-bnpNIQ328iudAVTg43A   5   1        109            0    170.5kb        170.5kb
yellow open   info-2018.01             bQp1i6YwQoGOvv1aJCjudA   5   1      36267            0     26.7mb         26.7mb


Добавляем индекс auth-*, в нем все события с авторизацией, sudo и др.


image


Перейдем к поиску и увидим события, связанные с авторизацией.


image


Таким же образом добавим другие индексы.


Настройки визуализации в ki

© Habrahabr.ru