Log4j Войдите в STDOUT, затем отформатируйте его в формат JSON для Logstash.

У меня есть приложение Spring Boot, работающее в кластере Kubernetes, и стек EFK (например, ELK, но вместо Logstash Fluentd используется как легкая альтернатива для сбора журналов из все контейнеры kubernetes и отправляет их в elasticsearch).

Чтобы адаптировать журналы к выходу JSON, я использовал logstash-logback-encoder библиотека:

<dependency>
  <groupId>net.logstash.logback</groupId>
  <artifactId>logstash-logback-encoder</artifactId>
  <version>4.11</version>
</dependency>

И из коробки мои журналы были преобразованы в JSON (что отлично).

Я вхожу в STDOUT, все забирается и отправляется в Elasticsearch. Никакой специальной настройки для ведения журнала внутри приложения Spring Boot не требуется.

Но проблема, с которой я столкнулся прямо сейчас, заключается в том, что при чтении моих журналов в реальном времени из STDOUT модуля Kubernetes их очень трудно читать со всем форматированием JSON.

Пример:

{"@timestamp":"2018-02-08T12:49:06.080+01:00","@version":1,"message":"Mapped \"{[/error],produces=[text/html]}\" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)","logger_name":"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.080+01:00","@version":1,"message":"Mapped \"{[/error]}\" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)","logger_name":"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.098+01:00","@version":1,"message":"Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]","logger_name":"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.098+01:00","@version":1,"message":"Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]","logger_name":"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.137+01:00","@version":1,"message":"Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]","logger_name":"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.268+01:00","@version":1,"message":"Registering beans for JMX exposure on startup","logger_name":"org.springframework.jmx.export.annotation.AnnotationMBeanExporter","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.333+01:00","@version":1,"message":"Initializing ProtocolHandler [\"http-nio-8080\"]","logger_name":"org.apache.coyote.http11.Http11NioProtocol","thread_name":"main","level":"INFO","level_value":20000}
{"@timestamp":"2018-02-08T12:49:06.355+01:00","@version":1,"message":"Starting ProtocolHandler [\"http-nio-8080\"]","logger_name":"org.apache.coyote.http11.Http11NioProtocol","thread_name":"main","level":"INFO","level_value":20000}

Я хочу войти в STDOUT в «обычном формате, отличном от JSON», а затем отправить журналы в Fluentd в формате JSON.

Я пытаюсь настроить два приложения журнала (один для STDOUT, а другой в формате JSON для Fluentd), но я почти уверен, что это дублирует данные (Fluentd получит формат JSON И STDOUT).

Мой план Б - создать один образ для развертывания (без формата JSON), а другой - для производства, но это больше похоже на план Z, tbh, потому что я хочу также отслеживать эти поды в производственной среде.

У меня вопрос: Как я могу сделать это, возможно, с одним приложением журнала ИЛИ без дублирования данных во Fluentd. Может быть, есть другой подход, о котором я не думал?


person Urosh T.    schedule 08.02.2018    source источник


Ответы (2)


Я предполагаю, что вы используете Logback, а не Log4j, который вы отметили, поскольку библиотека logstash, с которой вы связались, похоже, написана для Logback.

Самым простым решением, вероятно, было бы настроить fluentd для чтения журналов из файла и перенаправления приложения JSON в этот файл.

Есть статья о плагине ввода хвоста, но по сути вы настраиваете его так :

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

  <!-- JSON appender for log collection -->
  <appender name="json" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>/some/path/to/your/file.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>/some/path/to/your/file.log.%d{yyyy-MM-dd}</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
  </appender>

  <!-- Console appender for humans -->
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <!-- Set threshold for the console log here if you want the
      log collection to get all log messages regardless of level -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>INFO</level>
    </filter>
    <!-- encoders are assigned the type
      ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

  <!-- Tie it all together -->
  <root level="all">
    <appender-ref ref="json" />
    <appender-ref ref="console" />
  </root>
</configuration>

свободно

<source>
  @type tail
  path /some/path/to/your/file.log
  pos_file /some/path/to/your/file.log
  format json
</source>

Согласно документации, fluentd будет следовать за ролловерами и начинать с начала нового файла после завершения старого файла.

Если вы хотите, чтобы вывод консоли был таким же, как у обычного приложения Spring Boot, вы можете скопировать шаблон из их конфигурация

person Raniz    schedule 08.02.2018

Несмотря на то, что меня искушало найти решение, которое было предложено, в конце я просто использовал jq, парсер json для просмотра моих журналов на cli. Я сделал это, чтобы избежать дублирования данных журнала и не создавать файлы, а также специально настраивать fluentd для чтения журналов из файлов.

person Urosh T.    schedule 22.02.2019