Системный журнал EVPC#

Настройка системного журнала#

Настройки отправляемых сообщений указываются в файле /conf/logback.xml. Отправляемые сообщения имеют формат JSON или XML согласно шаблону, описываемому в файле logback.xml.

Для логирования информации о работе EVPC необходимо в файле logback.xml заполнить блок:

<root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="file"/>
    </root>

В нем необходимо указать наименования appenders, в которых описан вывод логов в конкретные места. В данном примере описан вывод логов EVPC в консоль управления EVPC и в файл.

Для логирования сообщений необходимо:

  1. Настроить шаг обработки сообщения log в параметре processors конфигурационного файла epf.conf.

  2. Заполнить файл logback.xml необходимыми настройками логирования и поместить его в директорию conf перед запуском установки EVPC. Примеры заполненных файлов logback.xml приведены ниже в данном разделе.

  3. Определить в файле logback.xml, куда будет производиться отправка сообщений. Для этого необходимо заполнить блок настроек:

<logger name="ru.sbt.ss.reactive.stream.transformers.logging.MessageLogger" level="info" additivity="false" >
        <appender-ref ref="GateLogger"/>
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="file"/>
    </logger>

В данном примере логирование сообщений, проходящих через EVPC, настроено на три приемника:

  • в централизованную систему журналирования: настройки задаются в appender GateLogger;

  • в консоль управления EVPC: настройки задаются в appender STDOUT;

  • в файл: настройки задаются в appender file.

  1. Прописать настройки в конфигурационном файле vars.yml.

Перед установкой (переустановкой) новой версии EVPC необходимо в конфигурационном файле vars.yml заполнить блок:

  logback:
    level: info
#    loggers:
#      - name: "ru.sbt.cep"
#        level: info
#      - name: "org.apache.kafka"
#        level: warn
#      - name: "com.typesafe.akka"
#        level: info
#    kafka: # Отправка логов в Apache Kafka
#      systemLogsTopic: sys-topic # Топик для отправки системных логов
#      systemLogsTopic_never_block: true # Блокировка работы приложения при недоступности Kafka (по умолчанию - блокируется, при true недоставленные сообщения в kafka отбрасываются)
#      systemLogsTopic_discarding_threshold: 20 # Процент свободного места в очереди отправки сообщений при достижении которого будут удаляться сообщения уровня TRACE, DEBUG, INFO
#      systemLogsTopic_queue_size: 512 # Размер очереди для отправки в Кафку
#      businessLogsTopic: business-topic # Топик для отправки бизнес логов
#      businessLogsTopic_never_block: true # Блокировка работы приложения при недоступности Kafka (по умолчанию - блокируется, при true недоставленные сообщения в kafka отбрасываются)
#      businessLogsTopic_discarding_threshold: 20 # Процент свободного места в очереди отправки сообщений при достижении которого будут удаляться сообщения уровня TRACE, DEBUG, INFO
#      businessLogsTopic_queue_size: 512 # Размер очереди для отправки в Кафку
#      businessLogsTopic_log_level: "info" # Уровень логирования TRACE, DEBUG, INFO
#      retries: 3 # Количество переиницилизации продьюсера, если параметр не задан, по умолчанию значение 3
#      interval: 1000 # Интервал между переиницилизациями, по умолчанию 1000 мс. Задается в мс.
#      multiplier: 1 # Множитель интервала переинициализации, по умолчанию значение 1.
#      never_block: false # блокировка работы приложения при недоступности Kafka центральной системы журналирования Platform V Monitor (по умолчанию - блокируется, при true недоставленные сообщения отбрасываются)
#      properties:
#        "bootstrap.servers": "host:port,host2:port2"
#        "client.id": "epf-cluster-test"
#        "config.providers": decode
#        "config.providers.decode.class": ru.sbt.ss.kafka.DecryptionConfigProvider
#        "config.providers.decode.param.security.encoding.key": ssl/secret.pass
#        "config.providers.decode.param.security.encoding.class": ru.sbt.ss.password.BaseEncryptor
#
#        "security.protocol": SSL
#        "ssl.endpoint.identification.algorithm": ""
#        "ssl.keystore.location": "ssl/epf.jks"
#        "ssl.truststore.location": "ssl/epf.jks"
#
#        "ssl.keystore.password": <password>
#        "ssl.truststore.password": <password>
#        "ssl.key.password": <password>

Для настройки отправки сообщений в централизованную систему журналирования Platform V Monitor необходимо заполнить блок appender GateLogger файла logback.xml (пример описан ниже).

При заполнении файла logback.xml стоит обратить внимание на заполнение следующих параметров:

Параметр

Описание

Значение по умолчанию

bodyType

Тип сообщения. Доступные значения: XML или JSON

JSON

rqUIDPath

Путь до RqUID (case sensitive) в логируемых сообщениях xpath (//rqUID) или jsonpath ($…rqUID)

$…rqUID

topic

Имя topic записи сообщений логов

client.id

Идентификатор продюсера Kafka, по которому можно однозначно идентифицировать продюсер Apache Kafka

пусто

config.providers

Объявление провайдера шифрования паролей. Значение не изменять

decode

config.providers.decode.class

Класс провайдера шифрования паролей. Значение не изменять

config.providers.decode.param.security.encoding.key

Путь до файла, содержащего ключ шифрования паролей

config.providers.decode.param.security.encoding.class

Класс шифрования паролей. Значение не изменять

security.protocol

Тип протокола подключения к системе журналирования

SSL

ssl.endpoint.identification.algorithm

Проверка сертификата на соответствия hostname

ssl.keystore.location

Расположение файла keystore

ssl.truststore.location

Расположение файла truststore

ssl.keystore.password

Пароль keystore в зашифрованном виде

ssl.truststore.password

Пароль truststore в зашифрованном виде

ssl.key.password

Ключ шифрования паролей в зашифрованном виде

bootstrap.servers

Hosts подключения к системе журналирования

host:port,host:port

Пример конфигурации логирования в системный вывод#

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

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{60} %X{sourceThread} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

Логирование в централизованную систему журналирования Platform V Monitor#

Для EVPC может быть настроена отправка системных журналов в централизованную систему журналирования Platform V Monitor.

Предварительно необходимо выполнить следующие действия:

  • узнать адреса брокеров Apache Kafka централизованной системы журналирования Platform V Monitor;

  • узнать названия топиков централизованной системы журналирования Platform V Monitor, куда будут отправляться журналы EVPC;

  • выпустить сертификат подключения к Apache Kafka централизованной системы журналирования Platform V Monitor.

Пример файла logback.xml с заполненными настройками представлен в файле example_logback.

Доступные уровни логирования системного журнала#

Имя логирования

Описание

Примечание

TRACE

Отражает менее приоритетные события для отладки

Уровень TRACE не рекомендуется включать в Промышленной среде

DEBUG

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

Уровень DEBUG не рекомендуется включать в Промышленной среде

INFO

Уровень логирования по умолчанию. События отражают информационные события системного журнала

WARN

Уровень отражает предупреждения и некритические ошибки обработки запросов/состояния сервиса

ERROR

Уровень отражает критические ошибки обработки запросов/состояния сервиса

Конфигурация логирования с возможностью отправки логов в топик Kafka#

Пример файла logback.xml с заполненными настройками логирования с возможностью отправки логов в топик Kafka представлен в файле example_logback.

Схема логов#

Логи разделены на системные и бизнес логи. К бизнес логам относятся логи трансформации событий.

Системные логи (name=SystemLogAppender)#

В системных логах указаны следующие поля JSON-сообщения:

  1. timestamp — время сообщения лога;

  2. level — уровень лога;

  3. projectName — название проекта(namespace) в k8s(DropApp);

  4. pod — название pod в проекте;

  5. deployment — имя манифеста с kind: Deployment;

  6. message — описание действий.

Бизнес логи (name=BusinessLogAppender)#

В бизнес логах трансформации событий указаны следующие поля JSON-сообщения:

  1. timestamp — время сообщения лога;

  2. level — уровень лога;

  3. projectName — название проекта(namespace) в k8s(DropApp);

  4. pod — название pod в проекте;

  5. deployment — имя манифеста с kind: Deployment;

  6. operationName — имя интеграционного потока, получаем из поля name блока flow конфигурации обработчика;

  7. eventId — идентификатор события;

  8. source — источник данных;

  9. destination — назчение данных (topic/очередь);

  10. message — описание действий.

Для бизнес логов в параметрах appender необходимо указывать настройку transformationLog со значением true (по умолчанию false), для включения в логи полей eventId, source, destination.

Настройка appender бизнес логов при запуске Jenkins с использованием параметра logLevel#

Параметр logLevel определяет уровень логирования DSL-логов универсального обработчика для определенного задания Jenkins. Для отправки логов в соответствии с настройками appender, необходимо в conf/logback.xml добавить logger с именем, совпадающим с именем задания Jenkins. Имя задания Jenkins определяется в настройках конфигурации потока обработки, в параметре name.

При запуске нескольких заданий Jenkins, необходимо для каждого задания Jenkins добавить соответствующий logger.

В случае, если задание Jenkins запускается без параметра logLevel, то используется logger класса ru.sbt.cep.flow.event.process.flow.function.EventHolderTransformer с настройками уровня логирования и используемым appender из conf/logback.xml. Подробнее указано в примере example_logback.

Изменение уровня логирования#

Возможно изменение уровня логирования при обращении к endpoint, на котором запущен healthCheck.

Схема:

openapi: 3.0.1
info:
  description: "Logger runtime update"
  version: "1.0.0"
  title: "Logging swagger"
servers:
  - url: "http://localhost:8080"
    description: "Logger runtime update"
paths:
  /loggers:
    get:
      summary: "Текущее состояние логеров"
      description: |
        **Текущее состояние логеров** \
        curl http://localhost:8080/loggers
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    name:
                      type: string
                      example: "ru.sbt.ss"
                    level:
                      type: string
                      example: "INFO"
        "405":
          description: "Incorrect method"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Incorrect method"
    put:
      summary: "Изменение уровня логирования логера с указанным именем"
      description: |
        **Изменение уровня логирования логера с указанным именем** \
        curl -X PUT http://localhost:8080/loggers -d '{"name":"ru.sbt.ss","level":"info"}'
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: object
              required:
                - name
                - level
              properties:
                name:
                  type: string
                  example: "ru.sbt.ss"
                level:
                  type: string
                  example: "INFO"
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Change logger ru.sbt.ss to level info"
        "400":
          description: "Incorrect data"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Incorrect data"
        "403":
          description: "Изменение незаданных в logback логеров"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Changing level of org.apache.kafka logger is prohibited"
        "404":
          description: "Not found"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Logger with name ru.sbt.ss not found"
        "405":
          description: "Incorrect method"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Incorrect method"
  /loggers/{loggerName}:
    get:
      summary: "Текущий уровень логирования логера с указанным именем"
      description: |
        **Текущий уровень логирования логера с указанным именем** \
        curl -v http://localhost:8080/loggers/ru.sbt.ss
      parameters:
        - in: path
          name: loggerName
          schema:
            type: string
          required: true
          description: "Имя логгера, информация о котором требуется"
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                    example: "ru.sbt.ss"
                  level:
                    type: string
                    example: "INFO"
        "400":
          description: "Incorrect data"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Incorrect data"
        "404":
          description: "Not found"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Logger with name ru.sbt.ss not found"
        "405":
          description: "Incorrect method"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "Incorrect method"

Часто встречающиеся события в файлах логов#

Часто встречающиеся события в файлах логов типа ERROR#

  1. Отсутствует egress EVTA:

15:48:19.823 [grpc-default-executor-0] ERROR r.s.s.r.s.g.c.GrpcClientStatusStreamObserver - Error on connect grpc stream: UNAVAILABLE: Unable to resolve host reactivestreamadapter-evta-os
io.grpc.StatusRuntimeException: UNAVAILABLE: Unable to resolve host reactivestreamadapter-evta-os
at io.grpc.Status.asRuntimeException(Status.java:535)
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:487)
at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:470)
at io.grpc.internal.DelayedClientCall$DelayedListener.drainPendingCallbacks(DelayedClientCall.java:509)
at io.grpc.internal.DelayedClientCall$1DrainListenerRunnable.runInContext(DelayedClientCall.java:298)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.RuntimeException: java.net.UnknownHostException: reactivestreamadapter-evta-os: Name or service not known
at io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:223)
at io.grpc.internal.DnsNameResolver.doResolve(DnsNameResolver.java:282)
at io.grpc.grpclb.GrpclbNameResolver.doResolve(GrpclbNameResolver.java:63)
at io.grpc.internal.DnsNameResolver$Resolve.run(DnsNameResolver.java:318)
... 3 common frames omitted
Caused by: java.net.UnknownHostException: reactivestreamadapter-evta-os: Name or service not known
at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(InetAddress.java:929)
at java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1515)
at java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:848)
at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1505)
at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1364)
at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1298)
at io.grpc.internal.DnsNameResolver$JdkAddressResolver.resolveAddress(DnsNameResolver.java:631)
at io.grpc.internal.DnsNameResolver.resolveAddresses(DnsNameResolver.java:219)
... 6 common frames omitted
  1. Не удалось расшифровать зашифрованный пароль:

16:24:04.916 [main] ERROR ru.sbt.ss.password.BaseEncryptor - Can't decrypt by the set parameters
  1. Не удалось подключиться к Apache Kafka (подробную причину ищем в логах egress EVTA):

16:33:32.878 [grpc-default-executor-0] ERROR r.s.s.r.s.g.c.GrpcClientStatusStreamObserver - Error on connect grpc stream: INTERNAL: Failure create subscriber from configuration, Error message: org.apache.kafka.common.KafkaException: Failed to construct kafka producer
io.grpc.StatusRuntimeException: INTERNAL: Failure create subscriber from configuration, Error message: org.apache.kafka.common.KafkaException: Failed to construct kafka producer
at io.grpc.Status.asRuntimeException(Status.java:535)
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:487)
at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:470)
at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:434)
at io.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:467)
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:563)
at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:744)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:723)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
  1. Отсутствует/требуется блок в conf/defaults.json:

Exception in thread "main" com.typesafe.config.ConfigException$UnresolvedSubstitution: mapping/flow-example.conf: 7: Could not resolve substitution to a value: ${defaults.grpc-example}
at com.typesafe.config.impl.ConfigReference.resolveSubstitutions(ConfigReference.java:111)
at com.typesafe.config.impl.ResolveContext.realResolve(ResolveContext.java:179)
at com.typesafe.config.impl.ResolveContext.resolve(ResolveContext.java:142)
at com.typesafe.config.impl.SimpleConfigObject$ResolveModifier.modifyChildMayThrow(SimpleConfigObject.java:380)
at com.typesafe.config.impl.SimpleConfigObject.modifyMayThrow(SimpleConfigObject.java:313)
at com.typesafe.config.impl.SimpleConfigObject.resolveSubstitutions(SimpleConfigObject.java:399)
at com.typesafe.config.impl.ResolveContext.realResolve(ResolveContext.java:179)
at com.typesafe.config.impl.ResolveContext.resolve(ResolveContext.java:142)
at com.typesafe.config.impl.SimpleConfigObject$ResolveModifier.modifyChildMayThrow(SimpleConfigObject.java:380)
at com.typesafe.config.impl.SimpleConfigObject.modifyMayThrow(SimpleConfigObject.java:313)
at com.typesafe.config.impl.SimpleConfigObject.resolveSubstitutions(SimpleConfigObject.java:399)
at com.typesafe.config.impl.ResolveContext.realResolve(ResolveContext.java:179)
at com.typesafe.config.impl.ResolveContext.resolve(ResolveContext.java:142)
at com.typesafe.config.impl.ResolveContext.resolve(ResolveContext.java:231)
at com.typesafe.config.impl.SimpleConfig.resolveWith(SimpleConfig.java:78)
at com.typesafe.config.impl.SimpleConfig.resolve(SimpleConfig.java:68)
at com.typesafe.config.impl.SimpleConfig.resolve(SimpleConfig.java:63)
at com.typesafe.config.impl.SimpleConfig.resolve(SimpleConfig.java:41)
at ru.sbt.cep.flow.event.process.akka.Main$.delayedEndpoint$ru$sbt$cep$flow$event$process$akka$Main$1(Main.scala:123)
at ru.sbt.cep.flow.event.process.akka.Main$delayedInit$body.apply(Main.scala:28)
at scala.Function0.apply$mcV$sp(Function0.scala:42)
at scala.Function0.apply$mcV$sp$(Function0.scala:42)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
at scala.App.$anonfun$main$1(App.scala:98)
at scala.App.$anonfun$main$1$adapted(App.scala:98)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:575)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:573)
at scala.collection.AbstractIterable.foreach(Iterable.scala:933)
at scala.App.main(App.scala:98)
at scala.App.main$(App.scala:96)
at ru.sbt.cep.flow.event.process.akka.Main$.main(Main.scala:28)
at ru.sbt.cep.flow.event.process.akka.Main.main(Main.scala)