JavaRush /Курсы /Модуль 5. Spring /Логирование ошибок и исключений

Логирование ошибок и исключений

Модуль 5. Spring
9 уровень , 9 лекция
Открыта

Сегодня мы чуть больше углубимся в логирование. Прежде чем врываться в код, задумайтесь: как бы вы поняли, что приложение "сломалось"? Конечно, пользователи могут пожаловаться, что "сайт не работает", но этого недостаточно для диагностики. Тут в дело вступает логирование. 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 в конце). Это позволяет получить полное представление об ошибке.


Разбираемся в уровнях логирования

Перед тем как написать мегакрутой логгер, важно понять, что такое уровни логирования:

  1. TRACE: детальная информация о работе приложения (редко используется).
  2. DEBUG: информация для отладки приложения. Например, какие значения были переданы в метод.
  3. INFO: общая информация о нормальной работе приложения.
  4. WARN: предупреждения, которые не критичны, но требуют проверки (например, истекает срок действия сессии).
  5. 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.
  • Логирование чувствительных данных (например, паролей).

Используйте правильные уровни и избегайте перегрузки логов ненужной информацией.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ