Pull to refresh

Учимся готовить Log4j + Logstash + ElasticSearch + Kibana 3 + Auth (Google OAuth2/BasicAuth/CAS Authentication)

Reading time 9 min
Views 66K

Задача


Настройка удобного средства для обработки и получения логов.

Условия


  1. Лицензия MIT или Apache 2.0
  2. Возможность приема и обработки многострочных сообщений
  3. Простота в настройке и использовании
  4. Возможность работы с логами из Log4j


Решение


Logstash + ElasticSearch + Kibana 3.

Реализация


Для начала развернем Logstash + ElasticSearch + Kibana 3 на нашем сервере:


#Проверяем версию джавы, нам нужна 7 или выше
java -version

#Если установлена, то переходим в директорию в которой будет находится Logstash
cd /srv

#Создаем папку для всей системы
mkdir slog

#Переходим в нее
cd slog

#Качаем последнюю версию Logstash, найти последнюю версию можно тут http://logstash.net/
curl -O https://download.elasticsearch.org/logstash/logstash/logstash-1.4.2.tar.gz

#Распаковываем tar.gz
tar zxvf logstash-1.4.2.tar.gz

#Переходим в директорию с распакованным Logstash
cd logstash-1.4.2

#Проверяем работу Logstash командой
bin/logstash -e 'input { stdin { } } output { stdout {} }'

#После этого любой ввод с клавиатуры должен обработаться логсташем. Если все в порядке, останавливаем процесс (Ctrl + C).


Теперь настроим конфигурационный файл для Logstash, подробно тут
Файл можно сохранить где угодно, например я сохраняю в logstash/conf/main.conf.
Мой вариант конфигурационного файла:
input {
 log4j {
  mode => "server"
  host => "logstash_server_ip"
  port => logstash_server_port
  type => "log4j"
 }
}

output {
 elasticsearch {
  embedded => "true"
 }
}

Подробнее:

input
mode — Тип сервиса, сервер/клиент
host — IP адрес сервера, адрес к которому будет передавать логи log4j
port = logstash_server_port — порт для обмена логами
type — тип сообщений, для обозначения логов.
output
embedded — Нужно ли запускать собственный сервис elasticsearch или нужно будет устанавливать подключение к уже существующему

Теперь настроим передачу логов с Log4j:

Для этого будем использовать плагин Logstash для Log4j, и SocketAppender со стороны Log4j.

Добавим настройки в Log4j:

logstash_server_port — порт который мы укажем в настройках Logstash для обмена логами
logstash_server_ip — ip адрес сервера, на котором расположен Logstash
xml
<appender name="LOGSTASH" class="org.apache.log4j.net.SocketAppender">
	<param name="port" value="logstash_server_port" />
	<param name="remoteHost" value="logstash_server_ip" />
</appender>
<root>
	<appender-ref ref="LOGSTASH" />
</root>


properties
log4j.rootLogger=logstash
log4j.appender.logstash=org.apache.log4j.net.SocketAppender
log4j.appender.logstash.port=logstash_server_port
log4j.appender.logstash.remoteHost=logstash_server_ip


Теперь пробуем запустить систему:

#Для начала переходим в папку с Logstash
cd /srv/slog/logstash-1.4.2/

#Запускаем службу при помощи конфигурационного файла:
bin/logstash agent -f conf/main.conf

#В нашем случае мы еще хотим запустить визуальную часть, так что добавим в конце web
bin/logstash agent -f conf/main.conf web

По окончании запуска на экран будет выведено подобное сообщение:
Using milestone 1 input plugin 'log4j'. This plugin should work, but would benefit from use by folks like you. Please let us know if you find bugs or have suggestions on how to improve this plugin.  For more information on plugin milestones, see http://logstash.net/docs/1.4.2/plugin-milestones {:level=>:warn}

Которое говорит что плагин Log4j находится в тестовом состоянии.

Теперь переходим на визуальную часть
http://logstash_server_ip:9292

logstash_server_ip — ip адрес сервера
9292 — порт по умолчанию, его можно изменить в конфигурационном файле.

Стандартное представление Kibana мне показалось не сильно удобным, но его можно настроить под себя. Лично я взял за основу вариант из этой статьи и сделал представление более удобным, на мой взгляд.

Вот мой вариант
{
  "title": "Home dashboard dark",
  "services": {
    "query": {
      "idQueue": [],
      "list": {
        "0": {
          "id": 0,
          "color": "#7EB26D",
          "alias": "",
          "pin": false,
          "type": "lucene",
          "enable": true,
          "query": "priority: \"INFO\""
        },
        "1": {
          "id": 1,
          "color": "#E24D42",
          "query": "priority: \"ERROR\"",
          "alias": "",
          "pin": false,
          "type": "lucene",
          "enable": true
        },
        "2": {
          "id": 2,
          "color": "#6ED0E0",
          "alias": "",
          "pin": false,
          "type": "lucene",
          "enable": true,
          "query": "priority: \"WARN\""
        }
      },
      "ids": [
        0,
        1,
        2
      ]
    },
    "filter": {
      "idQueue": [],
      "list": {
        "0": {
          "type": "time",
          "field": "@timestamp",
          "from": "now-6h",
          "to": "now",
          "mandate": "must",
          "active": true,
          "alias": "",
          "id": 0
        }
      },
      "ids": [
        0
      ]
    }
  },
  "rows": [
    {
      "title": "Filtering",
      "height": "150px",
      "editable": true,
      "collapse": false,
      "collapsable": true,
      "panels": [
        {
          "error": false,
          "type": "filtering",
          "span": 12
        },
        {
          "loading": false,
          "error": false,
          "sizeable": false,
          "span": 12,
          "height": "150px",
          "editable": true,
          "type": "query",
          "query": "*",
          "pinned": true,
          "history": [
            "priority: \"WARN\"",
            "priority: \"ERROR\"",
            "priority: \"INFO\"",
            "@&~(HHH.+)",
            "@&~(foo.+)",
            "*",
            "level:\"WARN\"",
            "level:\"ERROR\"",
            "level:\"INFO\""
          ],
          "remember": 10
        }
      ],
      "notice": true
    },
    {
      "title": "Graph",
      "height": "200px",
      "editable": true,
      "collapse": false,
      "collapsable": true,
      "panels": [
        {
          "span": 12,
          "editable": true,
          "group": [
            "default"
          ],
          "type": "histogram",
          "mode": "count",
          "time_field": "@timestamp",
          "value_field": null,
          "auto_int": true,
          "resolution": 99,
          "interval": "5m",
          "fill": 2,
          "linewidth": 3,
          "timezone": "browser",
          "spyable": true,
          "zoomlinks": true,
          "bars": false,
          "stack": false,
          "points": false,
          "lines": true,
          "legend": true,
          "x-axis": true,
          "y-axis": true,
          "percentage": false,
          "interactive": true,
          "queries": {
            "mode": "all",
            "ids": [
              0,
              1,
              2
            ]
          },
          "title": "Events over time",
          "intervals": [
            "auto",
            "1s",
            "1m",
            "5m",
            "10m",
            "30m",
            "1h",
            "3h",
            "12h",
            "1d",
            "1w",
            "1M",
            "1y"
          ],
          "options": true,
          "tooltip": {
            "value_type": "cumulative",
            "query_as_alias": true
          },
          "scale": 1,
          "y_format": "none",
          "grid": {
            "max": null,
            "min": 0
          },
          "annotate": {
            "enable": false,
            "query": "*",
            "size": 20,
            "field": "_type",
            "sort": [
              "_score",
              "desc"
            ]
          },
          "pointradius": 5,
          "show_query": true,
          "legend_counts": true,
          "zerofill": true,
          "derivative": false
        }
      ],
      "notice": false
    },
    {
      "title": "Events",
      "height": "150px",
      "editable": true,
      "collapse": false,
      "collapsable": true,
      "panels": [
        {
          "title": "All events",
          "error": false,
          "span": 12,
          "editable": true,
          "group": [
            "default"
          ],
          "type": "table",
          "size": 100,
          "pages": 5,
          "offset": 0,
          "sort": [
            "@timestamp",
            "desc"
          ],
          "style": {
            "font-size": "9pt"
          },
          "overflow": "min-height",
          "fields": [
            "@timestamp",
            "priority",
            "message",
            "class",
            "host"
          ],
          "highlight": [
            "level"
          ],
          "sortable": true,
          "header": true,
          "paging": true,
          "spyable": true,
          "queries": {
            "mode": "all",
            "ids": [
              0,
              1,
              2
            ]
          },
          "field_list": false,
          "status": "Stable",
          "trimFactor": 300,
          "normTimes": true,
          "all_fields": false,
          "localTime": false,
          "timeField": "@timestamp"
        }
      ],
      "notice": false
    }
  ],
  "editable": true,
  "failover": false,
  "index": {
    "interval": "day",
    "pattern": "[logstash-]YYYY.MM.DD",
    "default": "NO_TIME_FILTER_OR_INDEX_PATTERN_NOT_MATCHED",
    "warm_fields": true
  },
  "style": "dark",
  "panel_hints": true,
  "pulldowns": [
    {
      "type": "query",
      "collapse": false,
      "notice": false,
      "query": "*",
      "pinned": true,
      "history": [],
      "remember": 10,
      "enable": false
    },
    {
      "type": "filtering",
      "collapse": true,
      "notice": true,
      "enable": false
    }
  ],
  "nav": [
    {
      "type": "timepicker",
      "collapse": false,
      "notice": false,
      "status": "Stable",
      "time_options": [
        "5m",
        "15m",
        "1h",
        "6h",
        "12h",
        "24h",
        "2d",
        "7d",
        "30d"
      ],
      "refresh_intervals": [
        "5s",
        "10s",
        "30s",
        "1m",
        "5m",
        "15m",
        "30m",
        "1h",
        "2h",
        "1d"
      ],
      "timefield": "@timestamp",
      "now": true,
      "filter_id": 0,
      "enable": true
    }
  ],
  "loader": {
    "save_gist": false,
    "save_elasticsearch": true,
    "save_local": true,
    "save_default": true,
    "save_temp": true,
    "save_temp_ttl_enable": true,
    "save_temp_ttl": "30d",
    "load_gist": true,
    "load_elasticsearch": true,
    "load_elasticsearch_size": 20,
    "load_local": true,
    "hide": false
  },
  "refresh": false
}


Аутентификация:

Недостатком данной системы является отсутствие любой аутентификации, из за того, что она была рассчитана на внутренние сети. Но это достаточно быстро решается вот этим форком из github.

Для того что бы им воспользоваться для начала мы должны установить node.js на наш сервер. Лично я использовал данный туториал.

#Переходим в директорию
cd /usr/src

#Заходим на http://nodejs.org/download/. и получаем линк на последнюю версию
#Например http://nodejs.org/dist/v0.10.31/node-v0.10.31.tar.gz
#Теперь вводим
wget http://nodejs.org/dist/v0.10.31/node-v0.10.31.tar.gz

#Распаковываем архив
tar zxf node-v0.10.4.tar.gz

#Переходим в директорию с node.js
cd node-v0.10.4

#Выполняем конфигурацию
./configure

#Далее выполняем непосредственную инсталяцию командами последовательно
make
make install

#Теперь у нас есть установленный node.js
#Приступим к установке и настройки форка с аутентификацией.
#Для начала перейдем в директорию которую создали ранее
cd /srv/slog

#Далее выполняем последовательно:
git clone https://github.com/fangli/kibana-authentication-proxy
cd kibana-authentication-proxy/
git submodule init
git submodule update
npm install

#Далее проверяем и обновляем Kibana до последней версии
cd kibana && git checkout master && git pull

#Следующим шагом является настройка config.js файла.
#Я люблю пользоваться nano редактором, так что в моем случае
nano /srv/slog/kibana-authentication-proxy/config.js


Для первоначального запуска нужно отредактировать следующие настройки: es_host/es_port
В них мы задаем настройки подключения к ElasticSearch. Если в предыдущем случае мы использовали встроенный ElasticSearch для встроенной Kibana, то теперь нам нужно настроить его на отдельную кастомную Kibana. Для этого редактируем наш main.conf файл, добавляя настройки порта ElasticSearch:

elasticsearch_server_port — порт по которому будет доступен elasticsearch
Финальная версия:
input {
 log4j {
  mode => "server"
  host => "logstash_server_ip"
  port => logstash_server_port
  type => "log4j"
 }
}

output {
 elasticsearch {
  embedded => "true"
  embedded_http_port => elasticsearch_server_port
 }
}


Теперь меняем настройки в config.js

«es_host»: logstash_server_ip
«es_port»: elasticsearch_server_port

Теперь аутентификация. Данный форк позволяет настроить одну из 3х аутентификаций: Google OAuth2/Basic Authentication/CAS Authentication.

Для примера настроим Basic Authentication:
    "enable_basic_auth": true,
        "basic_auth_users": [
            {"user": "admin", "password": "admin"},
        ],


Запуск:

#Для начала запустим Logstash + ElasticSearch
#Без приставки web так как теперь мы будем запускать на собственной вьюхе
cd /srv/slog/logstash-1.4.2/
bin/logstash agent -f conf/main.conf

#После того как Logstash стартует мы можем запустить вьюху.
cd /srv/slog/kibana-authentication-proxy/
node app.js

По умолчанию порт для данного форка Kibana — 9201
Так что теперь она доступна по адресу:
http://logstash_server_ip:9201. 


Результат






UPD: После обновления Logstash до версии 1.5.* рецепт не работает, будет время — выложу обновленную версию.
Tags:
Hubs:
+16
Comments 47
Comments Comments 47

Articles