Приветствую, дорогие друзья!


Сегодня я хочу продемонстрировать потрясающий пример того, как Бобина может помочь в очень распространённой ситуации — логирование HTTP запросов и ответов в Spring Boot.


Даже больше! Мы будем логировать только сообщения HTTP в отдельные файлы.


Итак, поехали!


Чтобы активировать логирование HTTP в Spring Boot просто добавьте строку в application.properties:


logging.level.org.springframework.web=TRACE

Такая конфигурация всё ещё не позволит логировать тело HTTP запроса.


Чтобы активировать логирование тела HTTP запроса, создайте конфигурационный класс:


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CommonsRequestLoggingFilter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Bean
    public CommonsRequestLoggingFilter logFilter() {
        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(100000);
        filter.setIncludeHeaders(false);
        filter.setAfterMessagePrefix("REQUEST DATA : ");
        return filter;
    }

}

Теперь, давайте настроим Бобину.


Добавьте зависимость в build.gradle:


compile "io.infinite:bobbin:2.0.4"

Или в pom.xml:


<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.5.6</version>
    <type>pom</type>
</dependency>
<dependency>
    <groupId>io.infinite</groupId>
    <artifactId>bobbin</artifactId>
    <version>2.0.4</version>
</dependency>

Создайте файл Bobbin.json в директории с ресурсами или в рабочей директории приложения:


{
  "levels": "['debug', 'info', 'warn', 'error'].contains(level)",
  "destinations": [
    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/THREADS/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\""
      },
      "classes": "className.contains('io.infinite.')"
    },
    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/ALL/WARNINGS_AND_ERRORS_${date}.log\""
      },
      "levels": "['warn', 'error'].contains(level)"
    },
    {
      "name": "io.infinite.bobbin.destinations.ConsoleDestination",
      "levels": "['warn', 'error'].contains(level)"
    }
  ]
}

Одной из основных особенностей "Бобины" является то, что она с лёгкостью разделяет вывод логирования в отдельные файлы на основании таких критериев как:


  • Уровень сообщения (debug, warn, и т.д.)
  • Название потока
  • Имя класса и пакета
  • и т.д.

Так зачем нам утруждать себя, ища наши HTTP логи в файлах, содержащих прочие логи?


Давайте направим HTTP логи Spring Boot в отдельные файлы для нашего удобства!


Добавьте новый destination в Bobbin.json:


    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/SPRING_WEB/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\""
      },
      "classes": "className.contains('org.springframework.web')"
    }

Как видно, мы записываем логи от классов, содержащих org.springframework.web в имени их пакета в директорию "SPRING_WEB"!


Легко, не правда ли?


Вот так выглядит полная конфигурация Bobbin.json:


{
  "levels": "['debug', 'info', 'warn', 'error'].contains(level)",
  "destinations": [
    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/THREADS/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\""
      },
      "classes": "className.contains('io.infinite.')"
    },
    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/ALL/WARNINGS_AND_ERRORS_${date}.log\""
      },
      "levels": "['warn', 'error'].contains(level)"
    },
    {
      "name": "io.infinite.bobbin.destinations.FileDestination",
      "properties": {
        "fileName": "\"./LOGS/SPRING_WEB/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\""
      },
      "classes": "className.contains('org.springframework.web')"
    },
    {
      "name": "io.infinite.bobbin.destinations.ConsoleDestination",
      "levels": "['warn', 'error'].contains(level)"
    }
  ]
}

А вот и содержимое самого лог файла .\LOGS\SPRING_WEB\main\http-nio-8089-exec-1\debug\http-nio-8089-exec-1_debug_2019-03-22.log: Ссылка на github.com, т.к. файл имеет длинные строки


Ещё никогда настройка логирования не была такой простой!


Спасибо за внимание!

Комментарии (2)


  1. Borz
    24.04.2019 09:44

    Одной из основных особенностей "Бобины" является то, что она с лёгкостью разделяет вывод логирования в отдельные файлы на основании таких критериев как

    Но зачем, если Logback или Log4J, идущие "из коробки" со Spring Boot уже умеют это?


    1. antonpryamostanov Автор
      24.04.2019 11:22

      Не умеют. Точнее, например, Logback может разделять по максимум одному MDC дискриминатору (такому как имя потока), но не более одного на файл.

      И используемый SiftingAppender имеет меньше настроект и функционал, чем RollingFileAppender. Например, нельзя настроить архивацию по оригинальному имени файла в SiftingAppender.

      В общем, архитектурно и с точки зрения настроек там всё очень печально. Поэтому и была создана Бобина.