ELK: Elasticsearch+Logstash+Kibana — логи Tomcat и подключение двух удалённых хостов

Автор: | 13/09/2015

elk-logosИмеется два QA сервера – один в дата-центре Ирландии, другой – в США.

Требуется собирать с них логи catalina.out и передавать на центральный сервер Logstash.

Повторяем установку Logstash Forwarder, как это описано в посте ELK: Elasticsearch+Logstash+Kibana — добавление удалённого хоста и настройка Logstash Forwarder – и приступаем к настройке, например – файл конфигурации с QA-сервера из США:

{
  "network": {
      "servers": [ "ec2-54-***-***-47.compute-1.amazonaws.com:5001" ],
      "ssl ca": "/etc/pki/tls/certs/logstash-forwarder.crt",
      "timeout": 15
  },

  "files": [
    {
      "paths": [  "/var/log/tomcat7/catalina.out" ],
      "fields": { "type": "n-qa-vir-catalina" }
    }
  ]
}

Тут:

  • servers – куда отправлять логи;
  • ssl ca – публичная часть сертификата сервера;
  • timeout – время ожидания ответа от Logstash сервера;
  • paths – файл лога;
  • fields – указываем в поле type имя, по которому в дальнейшем будем сортировать логи.

Переходим к серверу.

В файл шаблонов (в данном примере это /opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-0.3.0/patterns/grok-patterns) добавляем:

...
EVERYTHING (.*)
MYTIME %{YEAR}-%{MONTHNUM}-%{MONTHDAY} %{HOUR}:%{MINUTE}:%{SECOND},%{SSS}
...

Создаём два файла файла конфигурации, например:

# ls -l /etc/logstash/conf.d | grep qa
-rw-r--r-- 1 root root 812 Sep 11 15:46 n-qa-ire.domain.com.conf
-rw-r--r-- 1 root root 812 Sep 11 15:46 n-qa-vir.domain.com.conf

Содержимое одного из них:

input {
  lumberjack {

    ssl_certificate => "/etc/pki/tls/certs/logstash-forwarder.crt"
    ssl_key => "/etc/pki/tls/private/logstash-forwarder.key"

    port => 5001
    type => "n-qa-vir-catalina"
    add_field => { "server" => "N-QA-VIR" }

  }
}

filter {
  if [type] == "n-qa-vir-catalina" {

    multiline {
       pattern => "^s"
       what => "previous"
    }

    grok {
      match => [ "message", "[%{MYTIME:logTime}] %{LOGLEVEL:logLevel} %{EVERYTHING:logMsg}" ]
    }

     fingerprint {
       source => ["message"]
       target => "fingerprint"
       key => "rds-n-qa-vir"
       method => "SHA1"
       concatenate_sources => true
     }
   }
}

output {
  elasticsearch {
    host => localhost
    document_id => "%{fingerprint}"
    index => "logstash-%{type}-%{+YYYY.MM.dd}"
  }
}

Теперь рассмотрим некоторые моменты тут.

  • add_field => { "server" => "N-QA-VIR" } – добавляем поле, что бы в Kibana было проще выбирать сервера;
  • if [type] == "n-qa-vir-catalina" – обычная проверка if/else, что бы обрабатывать логи только с хоста с type == n-qa-vir-catalina;
  • multiline – для решения проблемы с переносом строк при отображении Java-ексепшенов;
  • fingerprint – создание “отпечатка” каждой записи, что бы избежать дублирования строк в Kibana;
  • index в блоке output – создать отдельный индекс для данных каждого хоста.

Многострочные записи в Kibana

Для примера – отключим обработку переноса строк при отображении трассировки  Java-ошибок:

kibana_1

Каждая новая строка отображается как новая запись.

Что бы избежать этого – используется кодек multiline:

...
    multiline {
       pattern => "^s"
       what => "previous"
    }
...

В данном случае указывается, что каждая строка, которая начинается с символа пробела – должна быть “прекреплена” к предыдущей строке.

Это помогает корректно отображать многострочные записи:

kibana_2

Дублирование строк в Kibana

Кроме этой проблемы – возникла ещё одна: при работе с несколькими форвадерами – Elasticsearch добавляет записи от каждого из них, в редзультате чего получается дублирование данных при отображении в веб-интерфейсе:

kibana_3

Что бы избежать этого – используется модуль fingerprint:

...
    fingerprint {
       source => ["message"]
       target => "fingerprint"
       key => "rds-n-qa-vir"
       method => "SHA1"
       concatenate_sources => true
     }
...
    output {
      elasticsearch {
        ...
        document_id => "%{fingerprint}"
        ...
      }
    }
...

Индексы в Elasticsearch

Что бы просмотреть все созаднные индексы и их размер – можно выполнить:

$ curl 'http://127.0.0.1:9200/_cat/indices?v'
health status index                                 pri rep docs.count docs.deleted store.size pri.store.size
yellow open   logstash-n-qa-vir-catalina-2015.09.13   5   1        827            0    617.4kb        617.4kb
yellow open   .kibana                                 1   1          2            1     13.5kb         13.5kb
yellow open   logstash-2015.09.11                     5   1     616153            0    862.8mb        862.8mb
yellow open   logstash-2015.09.09                     5   1       2616            0      1.2mb          1.2mb
yellow open   logstash-dev-catalina-2015.09.11        5   1        384           85    396.5kb        396.5kb
yellow open   logstash-n-qa-ire-catalina-2015.09.12   5   1          1            2      7.4kb          7.4kb
yellow open   logstash-n-qa-vir-catalina-2015.09.11   5   1        817           74      576kb          576kb
yellow open   logstash-n-qa-ire-catalina-2015.09.13   5   1        190          695    531.8kb        531.8kb
yellow open   logstash-2015.09.08                     5   1         55            0    283.9kb        283.9kb
yellow open   logstash-n-qa-vir-catalina-2015.09.12   5   1        379          638      991kb          991kb
yellow open   logstash-n-qa-ire-catalina-2015.09.11   5   1        191          709    584.1kb        584.1kb

Просмотреть данные:

$ curl -XGET 'http://127.0.0.1:9200/logstash-dev-catalina-2015.09.11/_search?pretty=1' | less
...
     "_index" : "logstash-dev-catalina-2015.09.11",
      "_type" : "dev-catalina",
      "_id" : "2e5dbf120deba6dad8cd643fe54864bc6adb9353",
      "_score" : 1.0,
      "_source":{"message":"INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/access/write-on-collection],methods=[GET]}" onto public java.lang.Boolean com.domain.cloudlibrary.controllers.AccessController.checkUserHasWritePermissionOnCollection(java.lang.String) throws com.netflix.astyanax.connectionpool.exceptions.ConnectionException","@version":"1","@timestamp":"2015-09-11T13:41:36.697Z","type":"dev-catalina","server":"DEV","file":"/var/log/tomcat7/catalina.out","host":"ip-10-122-0-100","offset":"14541646","tags":["_grokparsefailure"],"fingerprint":"2e5dbf120deba6dad8cd643fe54864bc6adb9353"}
    }, {
...

Удалить индекс:

$ curl -XDELETE 'http://127.0.0.1:9200/logstash-2015.09.08/'
{"acknowledged":true}