Сегодня мы чуть больше углубимся в логирование. Прежде чем врываться в код, задумайтесь: как бы вы поняли, что приложение "сломалось"? Конечно, пользователи могут пожаловаться, что "сайт не работает", но этого недостаточно для диагностики. Тут в дело вступает логирование. Spring предоставляет мощный и гибкий механизм для логирования, который легко интегрируется с популярными библиотеками, такими как SLF4J, Logback и Log4j. А теперь представьте свою жизнь без логов. Ваш единственный способ отладки — расставлять System.out.println() в коде? Это не только неэффективно, но и напоминает попытки найти север с помощью кактуса.
Настройка логирования в Spring Boot
По умолчанию Spring Boot поставляется с поддержкой SLF4J (Simple Logging Facade for Java) и Logback. Это стандартное сочетание, которое покрывает большинство задач.
Добавление зависимости (если вдруг её нет)
Если вы ещё не используете Spring Boot Starter Logging, добавьте это в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
Spring Boot автоматически подключит Logback, так что дополнительных манипуляций с библиотеками не потребуется.
Логирование в обработчиках ошибок
Логирование ошибок в обработчиках — это ключевая часть обработки исключений. Давайте начнем с простого примера использования @ExceptionHandler с добавлением логирования.
Пример
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
LOGGER.error("Произошла ошибка: {}", ex.getMessage(), ex);
return new ResponseEntity<>("Некорректный запрос: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
Здесь мы используем Logger, чтобы записать сообщение об ошибке, дополненное стек-трейсом (ex в конце). Это позволяет получить полное представление об ошибке.
Разбираемся в уровнях логирования
Перед тем как написать мегакрутой логгер, важно понять, что такое уровни логирования:
- TRACE: детальная информация о работе приложения (редко используется).
- DEBUG: информация для отладки приложения. Например, какие значения были переданы в метод.
- INFO: общая информация о нормальной работе приложения.
- WARN: предупреждения, которые не критичны, но требуют проверки (например, истекает срок действия сессии).
- ERROR: ошибки, которые требуют вмешательства.
Пример использования разных уровней:
LOGGER.trace("Детальная информация для отладки.");
LOGGER.debug("Данные для анализа работы: значение X = {}", x);
LOGGER.info("Пользователь успешно авторизовался.");
LOGGER.warn("Пароль пользователя скоро истечёт.");
LOGGER.error("Ошибка при обработке запроса.", exception);
На практике, логи с уровнями ниже INFO выключены в большинстве production-систем.
Настройка Logback через конфигурационный файл
Хотите больше контроля над логами? Spring Boot позволяет настроить Logback в файле logback-spring.xml.
Пример конфигурации
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/app.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.example" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
Этот файл создаёт два логгера: один выводит логи в консоль, другой — в файл app.log. Обратите внимание на pattern: он определяет формат вывода логов (включая timestamp, уровень, имя логгера и сообщение).
Логирование с помощью SLF4J в контроллерах и сервисах
Пример
Давайте добавим логи в контроллер:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);
@GetMapping("/example")
public ResponseEntity<String> exampleMethod(@RequestParam String input) {
LOGGER.info("Получен запрос с параметром: {}", input);
if (input.isEmpty()) {
LOGGER.warn("Пустой параметр запроса!");
return new ResponseEntity<>("Параметр не должен быть пустым", HttpStatus.BAD_REQUEST);
}
LOGGER.debug("Выполняется обработка запроса...");
return new ResponseEntity<>("Успешный ответ", HttpStatus.OK);
}
}
Практическая задача: логируем кастомные исключения
Создадим кастомное исключение и глобальный обработчик с логированием.
Шаг 1. Создание кастомного исключения
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
Шаг 2. Добавление обработки
@RestControllerAdvice
public class GlobalErrorHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalErrorHandler.class);
@ExceptionHandler(CustomException.class)
public ResponseEntity<String> handleCustomException(CustomException ex) {
LOGGER.error("Кастомное исключение: {}", ex.getMessage(), ex);
return new ResponseEntity<>("Произошла ошибка: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Шаг 3. Использование исключения в коде
@RestController
public class CustomExceptionController {
@GetMapping("/trigger-error")
public ResponseEntity<String> triggerError() {
throw new CustomException("Что-то пошло не так!");
}
}
Результат: если пользователь откроет /trigger-error, он увидит понятное сообщение об ошибке, а в логах будет стек-трейс с деталями.
Логирование и мониторинг
Интеграция логов с системами мониторинга (например, ELK: Elasticsearch, Logstash, Kibana) позволяет вам следить за логами в реальном времени. Spring Actuator также может логировать системные события. Иными словами, ваши логи будут не просто текстом, а инструментом предсказания проблем.
Типичные ошибки при логировании
- Стараться логировать абсолютно всё (миллион
DEBUG-логов = конец производительности). - Использование
System.out.println()вместо нормального логгера. - Забвение про уровни логирования: всё либо
WARN, либоINFO. - Логирование чувствительных данных (например, паролей).
Используйте правильные уровни и избегайте перегрузки логов ненужной информацией.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ