Васильев Андрей Михайлович, 2024
Версии презентации
Серверное приложение обычно запускается на выделенном компьютере и функционирует постоянно (или согласно графику обслуживания пользователей)
Во время работы приложения могут возникнуть разные ситуации:
Обычно при продуктовом запуске у разработчиков нет возможности физически подключиться к серверу, чтобы изучить все детали некорректного поведения приложения
Выполним классификацию возможных причин критических ситуаций:
Задача отслеживания состояния серверов в целом решена: создан ряд продуктов, которые позволяют собрать информацию о состоянии вычислительной системы:
Данные собираются в единую систему, которая:
На каждом компьютере, за которым необходимо следить, запускается агент системы мониторинга, который собирает информацию и отправляет на центральный узел
Некоторые системы мониторинга позволяют отправлять метрики не только от собственных агентов, но также и от внешних приложений, например веб-приложений
Каждое приложение обладает важными характеристиками относительно задачи, которую оно решает, именно их стоит закладывать в метрики, а не обобщённые данные
Общие метрики веб-сервера, запущенного на JVM:
При отсутствии системы монитроринга можно воспользоваться локальной альтернативой — журналированием работы приложения в файлы-журналы
Журналы в данном случае являются файлами, расположенными на файловой системе
Необходимо выполнять ротацию журналов — удаление излишних записей из журнала, когда всё хранилище заполнено или старые данные уже не актуальны
Ввиду длинной жизни платформы JVM было предложено много решений для выполнения журналирования внутри приложения:
Каждый разработчик библиотеки может выбирать любое решение для записи своих журналов
Данная библиотека является достаточно гибкой и она используется при разработке Android-приложений, для неё существуют обёртки на языке Kotlin
В файле build.gradle.kts
или build.properties.json
необходимо добавить
зависимость от API
"org.slf4j:slf4j-api"
class SomeHandler() : HttpHandler {
private val logger = LoggerFactory.getLogger(SomeHandler::class.java)
override fun invoke(request: Request): Response {
logger.atInfo().log("Обрабатываем очень важный запрос")
}
}
Журналирование общей информации по запросам можно доверить фильтру на уровне всего приложения, т.к. он имеет всю необходимую информацию
val logger = LoggerFactory.getLogger("ru.yarsu.WebApplication")
val loggingFilter = Filter { next: HttpHandler ->
{ request: Request ->
// Собрать данные о запросе
// Вычислить время обработки запроса
val result = next(request)
// Собрать данные об ответе
// Выполнить журналирование информации
logger.atInfo().setMessage("Request")
.addKeyValue("URI", request.uri).log()
result
}
}
Библиотеки журналирования предоставляют несколько уровней важности сообщений: trace, debug, info, warn, error
При записи данных в журнал можно указать желаемый уровень сообщений
Сообщение\Журналирование | TRACE | DEBUG | INFO | WARN | ERROR | OFF |
---|---|---|---|---|---|---|
TRACE | + | - | - | - | - | - |
DEBUG | + | + | - | - | - | - |
INFO | + | + | + | - | - | - |
WARN | + | + | + | + | - | - |
ERROR | + | + | + | + | + | - |
INFO
Необходимо добавить зависимость от logback-classic в build.gradle.kts
или
build.properties.json
:
"ch.qos.logback:logback-classic"
В момент запуска приложения Logback пытается выполнить конфигурацию автоматически:
logback-test.scmo
из ресурсов приложенияlogback.xml
из ресурсов приложенияSCMO-файлы являются бинарным представлением конфигурации, оптимизированы для ускорения запуска
logs
, в файл app.log
debug
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${HOME_LOG}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- Максимальный размер архива журнала 10 МБ -->
<maxFileSize>10MB</maxFileSize>
<!-- Максимальный общий объём архива 100 МБ -->
<totalSizeCap>100MB</totalSizeCap>
<!-- Хранить не более 60 дней -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.JsonEncoder"/>
</appender>
<root level="debug">
<appender-ref ref="FILE-ROLLING"/>
</root>
</configuration>