Структурированный журнал приложений для Azure Spring Apps

Примечание.

Azure Spring Apps — это новое название службы Azure Spring Cloud. Старое название будет еще некоторое время встречаться в наших материалах, пока мы не обновим ресурсы, такие как снимки экрана, видео и схемы.

Эта статья относится к: ✔️ Basic/Standard ✔️ Enterprise

Из этой статьи вы узнаете, как создавать и собирать структурированные данные журнала приложений в Azure Spring Apps. Если правильно настроить Azure Spring Apps, вы сможете запрашивать журнал приложений и выполнять анализ посредством Log Analytics.

Требования к схеме журнала

Для должной работы журнал приложений должен быть в формате JSON и соответствовать заданной схеме. Azure Spring Apps использует эту схему, чтобы анализировать приложение и передавать данные в Log Analytics.

Примечание.

Включение формата журнала JSON затрудняет чтение потоковой передачи журналов из консоли. Чтобы получить результат в понятном для человека формате, добавьте аргумент --format-json в команду CLI az spring app logs. См. статью Форматирование структурированных журналов JSON.

Требования к схеме JSON:

Ключ JSON Тип значения JSON Обязательное поле Столбец в Log Analytics Description
TIMESTAMP строка Да AppTimestamp Метка времени в формате UTC
logger строка Нет Ведение журнала logger
level строка Нет CustomLevel log level
среды строка Нет Дискуссия среды
message строка Нет Message Сообщение журнала
stackTrace строка Нет StackTrace Трассировка стека исключений
exceptionClass строка Нет ExceptionClass Название класса исключений
mdc Вложенный массив JSON No Сопоставленный контекст диагностики
mdc.traceId строка Нет TraceId Идентификатор трассировки для распределенной трассировки
mdc.spanId строка Нет SpanId Идентификатор диапазона для распределенной трассировки
  • Поле timestamp является обязательным и должно быть в формате UTC, все остальные поля необязательны.
  • traceId и spanId в поле mdc используются в целях трассировки.
  • Каждую запись JSON необходимо вносить отдельной строкой.

Пример записи журнала

{"timestamp":"2021-01-08T09:23:51.280Z","logger":"com.example.demo.HelloController","level":"ERROR","thread":"http-nio-1456-exec-4","mdc":{"traceId":"c84f8a897041f634","spanId":"c84f8a897041f634"},"stackTrace":"java.lang.RuntimeException: get an exception\r\n\tat com.example.demo.HelloController.throwEx(HelloController.java:54)\r\n\","message":"Got an exception","exceptionClass":"RuntimeException"}

Ограничения

Каждая строка журналов JSON имеет не более 16 байт. Если выходные данные JSON одной записи журнала превышают это ограничение, он разбивается на несколько строк, и каждая необработанную строку собирается в Log столбец без анализа структурно.

Как правило, эта ситуация возникает при ведении журнала исключений с глубоким стеком, особенно если приложение Аналитика включен агент in-Process. Примените параметры ограничения к результату трассировки стека (см. приведенные ниже примеры конфигурации), чтобы гарантировать его надлежащий анализ.

Создание журнала JSON в соответствии со схемой

Для приложений Spring можно создать ожидаемый формат журнала JSON с помощью общих платформ ведения журнала, таких как Logback и Log4j2.

Ведение журнала с помощью logback

При использовании начальных средств Spring Boot по умолчанию используется logback. Для приложений Logback используйте кодировщик logstash-encoder для создания форматированного журнала JSON. Этот метод поддерживается в Spring Boot версии 2.1 или более поздней.

Процедура:

  1. Добавьте зависимость logstash в файл pom.xml.

    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>6.5</version>
    </dependency>
    
  2. Переведите файл конфигурации logback-spring.xml в формат JSON.

    <configuration>
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
                <providers>
                    <timestamp>
                        <fieldName>timestamp</fieldName>
                        <timeZone>UTC</timeZone>
                    </timestamp>
                    <loggerName>
                        <fieldName>logger</fieldName>
                    </loggerName>
                    <logLevel>
                        <fieldName>level</fieldName>
                    </logLevel>
                    <threadName>
                        <fieldName>thread</fieldName>
                    </threadName>
                    <nestedField>
                        <fieldName>mdc</fieldName>
                        <providers>
                            <mdc />
                        </providers>
                    </nestedField>
                    <stackTrace>
                        <fieldName>stackTrace</fieldName>
                        <!-- maxLength - limit the length of the stack trace -->
                        <throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
                            <maxDepthPerThrowable>200</maxDepthPerThrowable>
                            <maxLength>14000</maxLength>
                            <rootCauseFirst>true</rootCauseFirst>
                        </throwableConverter>
                    </stackTrace>
                    <message />
                    <throwableClassName>
                        <fieldName>exceptionClass</fieldName>
                    </throwableClassName>
                </providers>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="stdout" />
        </root>
    </configuration>
    
  3. При использовании файла конфигурации ведения журнала с суффиксом -spring, например logback-spring.xml, можно задать конфигурацию ведения журнала на основе активного профиля Spring.

    <configuration>
        <springProfile name="dev">
            <!-- JSON appender definitions for local development, in human readable format -->
            <include resource="org/springframework/boot/logging/logback/defaults.xml" />
            <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
            <root level="info">
                <appender-ref ref="CONSOLE" />
            </root>
        </springProfile>
    
        <springProfile name="!dev">
            <!-- JSON appender configuration from previous step, used for staging / production -->
            ...
        </springProfile>
    </configuration>
    

    При локальной разработке запустите приложение Spring с аргументом виртуальной машины Java -Dspring.profiles.active=dev, после чего появятся журналы в понятном для человека формате, а не строки в формате JSON.

Ведение журнала с помощью log4j2

Если речь идет о приложениях log4j2, создать журнал в формате JSON можно с помощью json-template-layout. Этот метод поддерживается в Spring Boot 2.1 и более поздних версиях.

Процедура:

  1. Исключите spring-boot-starter-logging из spring-boot-starter, добавьте зависимости spring-boot-starter-log4j2, log4j-layout-template-json в файл pom.xml.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-layout-template-json</artifactId>
        <version>2.14.0</version>
    </dependency>
    
  2. Подготовьте файл шаблона макета JSON jsonTemplate.json в пути к классу.

    {
        "mdc": {
            "$resolver": "mdc"
        },
        "exceptionClass": {
            "$resolver": "exception",
            "field": "className"
        },
        "stackTrace": {
            "$resolver": "exception",
            "field": "stackTrace",
            "stringified": true
        },
        "message": {
            "$resolver": "message",
            "stringified": true
        },
        "thread": {
            "$resolver": "thread",
            "field": "name"
        },
        "timestamp": {
            "$resolver": "timestamp",
            "pattern": {
                "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                "timeZone": "UTC"
            }
        },
        "level": {
            "$resolver": "level",
            "field": "name"
        },
        "logger": {
            "$resolver": "logger",
            "field": "name"
        }
    }
    
  3. Используйте этот шаблон макета JSON в своем файле конфигурации log4j2-spring.xml.

    <configuration>
        <appenders>
            <console name="Console" target="SYSTEM_OUT">
                <!-- maxStringLength - limit the length of the stack trace -->
                <JsonTemplateLayout eventTemplateUri="classpath:jsonTemplate.json" maxStringLength="14000" />
            </console>
        </appenders>
        <loggers>
            <root level="info">
                <appender-ref ref="Console" />
            </root>
        </loggers>
    </configuration>
    

Анализ журналов в Log Analytics

После правильной настройки приложения журнал консоли приложения передается в Log Analytics. Такая структура обеспечивает эффективную обработку запросов в Log Analytics.

Проверка структуры журнала в Log Analytics

Это можно сделать следующим образом:

  1. Перейдите на страницу обзора своего экземпляра службы.

  2. Щелкните Журналы в разделе Мониторинг.

  3. Выполните этот запрос.

    AppPlatformLogsforSpring
    | where TimeGenerated > ago(1h)
    | project AppTimestamp, Logger, CustomLevel, Thread, Message, ExceptionClass, StackTrace, TraceId, SpanId
    
  4. Вы получите журналы приложений, как на этом изображении:

    Screenshot of the Azure portal showing the log Results pane.

Отобразите записи журнала, содержащие ошибки.

Чтобы проверить записи журнала с ошибкой, выполните следующий запрос:

AppPlatformLogsforSpring
| where TimeGenerated > ago(1h) and CustomLevel == "ERROR"
| project AppTimestamp, Logger, ExceptionClass, StackTrace, Message, AppName
| sort by AppTimestamp

Этот запрос позволяет искать ошибки или менять условия запроса таким образом, чтобы находить конкретные классы исключения или коды ошибки.

Отображение записей журнала по определенному идентификатору трассировки

Чтобы изучить записи журнала по конкретному идентификатору трассировки trace_id, выполните следующий запрос:

AppPlatformLogsforSpring
| where TimeGenerated > ago(1h)
| where TraceId == "trace_id"
| project AppTimestamp, Logger, TraceId, SpanId, StackTrace, Message, AppName
| sort by AppTimestamp

Следующие шаги