Шаблон конвейера Logstash для Spring Boot развернут на Cloud Foundry - PullRequest
0 голосов
/ 03 октября 2019

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

Я использую Spring Boot (2.1.x) из коробки, развертываю его в Cloud Foundry и регистрируюсь через stdout / logdrain в Logstash и, в конечном итоге, в Elasticsearch.

Я уже искал в Интернете инашел только один шаблон для приложений Cloud Foundry:

input {
  http {
    port => "5044"
    user => "inputuser"
    password => "inputpassword"
  }
}

filter {
 grok {
    #patterns_dir => "{{ .Env.HOME }}/grok-patterns"
    match => { "message" => "%{SYSLOG5424PRI}%{NONNEGINT:syslog5424_ver} +(?:%{TIMESTAMP_ISO8601:syslog5424_ts}|-) +(?:%{HOSTNAME:syslog5424_host}|-) +(?:%{NOTSPACE:syslog5424_app}|-) +(?:%{NOTSPACE:syslog5424_proc}|-) +(?:%{WORD:syslog5424_msgid}|-) +(?:%{SYSLOG5424SD:syslog5424_sd}|-|)%{SPACE}%{GREEDYDATA:message}" }
    add_tag => [ "CF","CF-%{syslog5424_proc}","_grokked"]
    add_field => { "format" => "cf" }
    tag_on_failure => [ ]
    overwrite => [ "message" ]
  }
  if [syslog5424_proc] =~ /(A[pP]{2}.+)/ {
    mutate { add_tag => ["CF-APP"] }
    mutate { remove_tag => ["_grokked"] }
  }
  if  ("CF-APP" in [tags]) or !("CF" in [tags])  {
    if [message] =~ /^{.*}/ {
      json {
        source => "message"
        add_tag => [ "json", "_grokked"]
      }
    }
  }
  if !("_grokked" in [tags]) {
    mutate{
      add_tag => [ "_ungrokked" ]
    }
  }
}

output {
    #stdout { codec => rubydebug }
    if ("_grokked" in [tags]) {
      elasticsearch {
        hosts => ["https://ac9537fc444c489bb63ac44064c54519.elasticsearch.lyra-836.appcloud.swisscom.com"]
        user => "myuser"
        password => "mypassword"
        ssl => true
        ssl_certificate_verification => true
        codec => "plain"
        workers => 1
        index => "parsed-%{+YYYY.MM.dd}"
        manage_template => true
        template_name => "logstash"
        template_overwrite => true
      }
    } else {
      elasticsearch {
        hosts => ["https://ac9537fc848c489bb63ac44064c54519.elasticsearch.lyra-836.appcloud.swisscom.com"]
        user => "myuser"
        password => "mypassword"
        ssl => true
        ssl_certificate_verification => true
        codec => "plain"
        workers => 1
        index => "unparsed-%{+YYYY.MM.dd}"
        manage_template => true
        template_name => "logstash"
        template_overwrite => true
      }
   }
}

Это уже выглядит довольно многословно и охватывает только поля Cloud Foundry, но игнорирует все специфические поля приложения, например уровень журнала (который не следует за ключом /запись значения, а не фиксированная позиция в сообщении журнала).

Один пример сообщения журнала:

2019-10-03T09:20:09.37+0200 [APP/PROC/WEB/0] OUT 2019-10-03 09:20:09.378  INFO 19 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'

Любая помощь приветствуется, большое спасибо!


Обновление : На основании первого комментария я настроил свое приложение Spring Boot для регистрации сообщений как json. В Cloud Foundry я отправляю эти журналы с помощью предоставленной пользователем службы, настроенной как logdrain, в Logstash. Logstash получает сообщение, подобное этому:

<14>1 2019-10-03T17:29:17.547195+00:00 cf-organization.cf-space.cf-app abc9dac6-1234-4b62-9eb4-98d1234d9ace [APP/PROC/WEB/1] - - {"app":"cf-app","ts":"2019-10-03T17:29:17.546+00:00","logger":"org.springframework.boot.web.embedded.netty.NettyWebServer","level":"INFO","class":"org.springframework.boot.web.embedded.netty.NettyWebServer","method":"start","file":"NettyWebServer.java","line":76,"thread":"main","msg":"Netty started on port(s): 8080"}

Используя вышеупомянутый фильтр, Logstash анализирует его для этого json:

{
  "syslog5424_ts": "2019-10-03T17:29:17.547195+00:00",
  "syslog5424_pri": "14",
  "syslog5424_ver": "1",
  "message": "{\"app\":\"cf-app\",\"ts\":\"2019-10-03T17:29:17.546+00:00\",\"logger\":\"org.springframework.boot.web.embedded.netty.NettyWebServer\",\"level\":\"INFO\",\"class\":\"org.springframework.boot.web.embedded.netty.NettyWebServer\",\"method\":\"start\",\"file\":\"NettyWebServer.java\",\"line\":76,\"thread\":\"main\",\"msg\":\"Netty started on port(s): 8080\"}",
  "syslog5424_app": "abc9dac6-1234-4b62-9eb4-98d1234d9ace",
  "syslog5424_proc": "[APP/PROC/WEB/1]",
  "syslog5424_host": "cf-organization.cf-space.cf-app"
}

Как бы мне пришлось настроить grok / output, чтобы просто отправитьзначение ключа message как json для Elasticsearch?

1 Ответ

0 голосов
/ 06 октября 2019

Хорошо, мне удалось сделать это с помощью следующих шагов, и благодаря этой замечательной статье :

Spring Boot app

Добавить эту зависимость

implementation 'net.logstash.logback:logstash-logback-encoder:5.2'

Добавьте этот src / main / resources / logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property resource="application.properties"/>
    <contextName>${spring.application.name}</contextName>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <contextName>
                    <fieldName>app</fieldName>
                </contextName>
                <timestamp>
                    <fieldName>ts</fieldName>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <loggerName>
                    <fieldName>logger</fieldName>
                </loggerName>
                <logLevel>
                    <fieldName>level</fieldName>
                </logLevel>
                <callerData>
                    <classFieldName>class</classFieldName>
                    <methodFieldName>method</methodFieldName>
                    <lineFieldName>line</lineFieldName>
                    <fileFieldName>file</fileFieldName>
                </callerData>
                <threadName>
                    <fieldName>thread</fieldName>
                </threadName>
                <mdc/>
                <arguments>
                    <includeNonStructuredArguments>false</includeNonStructuredArguments>
                </arguments>
                <stackTrace>
                    <fieldName>stack</fieldName>
                </stackTrace>
                <message>
                    <fieldName>msg</fieldName>
                </message>
            </providers>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

Добавьте эти свойства

spring.application.name=<app-name>
spring.main.banner-mode=OFF

Это приведет к созданию журналов, которые выглядят следующим образом:

<14>1 2019-10-03T17:29:17.547195+00:00 cf-organization.cf-space.cf-app abc9dac6-1234-4b62-9eb4-98d1234d9ace [APP/PROC/WEB/1] - - {"app":"cf-app","ts":"2019-10-03T17:29:17.546+00:00","logger":"org.springframework.boot.web.embedded.netty.NettyWebServer","level":"INFO","class":"org.springframework.boot.web.embedded.netty.NettyWebServer","method":"start","file":"NettyWebServer.java","line":76,"thread":"main","msg":"Netty started on port(s): 8080"}

Теперь нам нужно проанализировать предварительно добавленный текст и добавить его значения в зарегистрированное сообщение.

Logstash-Pipeline

input {
  http {
    port => "5044"
    user => "exampleUser"
    password => "examplePassword"
  }
}

filter{
 grok {
    #patterns_dir => "{{ .Env.HOME }}/grok-patterns"
    match => { "message" => "%{SYSLOG5424PRI}%{NONNEGINT:syslog5424_ver} +(?:%{TIMESTAMP_ISO8601:syslog5424_ts}|-) +(?:%{HOSTNAME:syslog5424_host}|-) +(?:%{NOTSPACE:syslog5424_app}|-) +(?:%{NOTSPACE:syslog5424_proc}|-) +(?:%{WORD:syslog5424_msgid}|-) +(?:%{SYSLOG5424SD:syslog5424_sd}|-|)%{SPACE}%{GREEDYDATA:message}" }
    add_tag => [ "CF", "CF-%{syslog5424_proc}", "parsed"]
    add_field => { "format" => "cf" }
    tag_on_failure => [ ]
    overwrite => [ "message" ]
  }
  mutate {
        split => ["syslog5424_host", "."]
        add_field => { "cf-org" => "%{[syslog5424_host][0]}" }
        add_field => { "cf-space" => "%{[syslog5424_host][1]}" }
        add_field => { "cf-app" => "%{[syslog5424_host][2]}" }
    }
  if [syslog5424_proc] =~ /\[(A[pP]{2}.+)/ {
    mutate { add_tag => ["CF-APP"] }
    mutate { remove_tag => ["parsed"] }
  }
  if  ("CF-APP" in [tags]) or !("CF" in [tags])  {
    if [message] =~ /^{.*}/ {
      json {
        source => "message"
        add_tag => [ "json", "parsed"]
      }
    }
  }
  if !("CF-APP" in [tags]) {
   mutate {
        add_field => { "msg" => "%{[message]}" }
        add_tag => [ "CF-PAAS"]
    }
  }
  if !("parsed" in [tags]) {
    mutate{
      add_tag => [ "unparsed" ]
    }
  }
}

output {
    if ("parsed" in [tags]) {
      elasticsearch {
        hosts => ["https://7875eb592bb94554ad35421dccc6847f.elasticsearch.lyra-836.appcloud.swisscom.com"]
        user => "logstash-system-ExjpCND01GbF7knG"
        password => "5v9nUztOkz0WUdKK"
        ssl => true
        ssl_certificate_verification => true
        codec => "plain"
        workers => 1
        index => "parsed-%{+YYYY.MM.dd}"
        manage_template => true
        template_name => "logstash"
        template_overwrite => true
      }
    } else {
      elasticsearch {
        hosts => ["https://7875eb592bb94554ad35421dccc6847f.elasticsearch.lyra-836.appcloud.swisscom.com"]
        user => "logstash-system-ExjpCND01GbF7knG"
        password => "5v9nUztOkz0WUdKK"
        ssl => true
        ssl_certificate_verification => true
        codec => "plain"
        workers => 1
        index => "unparsed-%{+YYYY.MM.dd}"
        manage_template => true
        template_name => "logstash"
        template_overwrite => true
      }
    }
}

Спасибо @Стрелок, указывающий мне в правильном направлении.

...