Перейти к основному содержимому

Регистрация HTTP-запросов с помощью HTTP-трассировки Spring Boot Actuator

· 5 мин. чтения

1. Введение

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

Доступны некоторые системы, которые могут помочь нам в этом и могут быть легко интегрированы со Spring, например Zipkin . Однако Spring Boot Actuator имеет эту встроенную функцию и может использоваться через конечную точку httpTrace , которая отслеживает все HTTP-запросы. В этом уроке мы покажем, как его использовать и как настроить, чтобы он лучше соответствовал нашим требованиям.

2. Настройка конечной точки HttpTrace

Для этого руководства мы будем использовать проект Maven Spring Boot .

Первое, что нам нужно сделать, это добавить в наш проект зависимость Spring Boot Actuator :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

После этого нам нужно включить конечную точку httpTrace в нашем приложении.

Для этого нам просто нужно изменить наш файл application.properties , включив в него конечную точку httpTrace :

management.endpoints.web.exposure.include=httptrace

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

Теперь наша конечная точка httpTrace должна появиться в списке конечных точек привода нашего приложения:

{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"httptrace": {
"href": "http://localhost:8080/actuator/httptrace",
"templated": false
}
}
}

Обратите внимание, что мы можем перечислить все включенные конечные точки привода, перейдя в конечную точку /actuator нашего веб-сервиса.

3. Анализ следов

Теперь давайте проанализируем трассировки, которые возвращает конечная точка привода httpTrace .

Давайте сделаем несколько запросов к нашему сервису, вызовем конечную точку /actuator/httptrace и возьмем одну из возвращенных трассировок:

{
"traces": [
{
"timestamp": "2019-08-05T19:28:36.353Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {
"accept-language": [
"en-GB,en-US;q=0.9,en;q=0.8"
],
"upgrade-insecure-requests": [
"1"
],
"host": [
"localhost:8080"
],
"connection": [
"keep-alive"
],
"accept-encoding": [
"gzip, deflate, br"
],
"accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
],
"user-agent": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 OPR/62.0.3331.66"
]
},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 19:28:36 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": 82
}
]
}

Как мы видим, ответ разбит на несколько узлов:

  • timestamp : время получения запроса
  • Principal : аутентифицированный пользователь, выполнивший запрос, если применимо.
  • session : любой сеанс, связанный с запросом
  • request : информация о запросе, такая как метод, полный URI или заголовки.
  • response : информация об ответе, такая как статус или заголовки
  • timeTaken : время, затраченное на обработку запроса

Мы можем адаптировать этот ответ к нашим потребностям, если считаем, что он слишком многословен. Мы можем указать Spring, какие поля мы хотим вернуть, указав их в свойстве management.trace.http.include нашего application.properties :

management.trace.http.include=RESPONSE_HEADERS

В этом случае мы указали, что нам нужны только заголовки ответов. Следовательно, мы видим, что поля, которые были включены ранее, такие как заголовки запроса или затраченное время, теперь отсутствуют в ответе:

{
"traces": [
{
"timestamp": "2019-08-05T20:23:01.397Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 20:23:01 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": null
}
]
}

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

4. Настройка HttpTraceRepository

По умолчанию конечная точка httpTrace возвращает только последние 100 запросов и сохраняет их в памяти . Хорошая новость заключается в том, что мы также можем настроить это, создав собственный HttpTraceRepository .

Давайте теперь создадим наш репозиторий. Интерфейс HttpTraceRepository очень прост, и нам нужно реализовать только два метода: findAll() для извлечения всех трассировок; и add() , чтобы добавить трассировку в репозиторий.

Для простоты наш репозиторий также будет хранить трассировки в памяти, и мы будем хранить только последний запрос GET, который попадает в нашу службу:

@Repository
public class CustomTraceRepository implements HttpTraceRepository {

AtomicReference<HttpTrace> lastTrace = new AtomicReference<>();

@Override
public List<HttpTrace> findAll() {
return Collections.singletonList(lastTrace.get());
}

@Override
public void add(HttpTrace trace) {
if ("GET".equals(trace.getRequest().getMethod())) {
lastTrace.set(trace);
}
}

}

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

5. Фильтрация путей для трассировки

Последнее, что мы собираемся рассмотреть, — это то, как фильтровать пути, которые мы хотим отслеживать, чтобы мы могли игнорировать некоторые запросы, которые нас не интересуют.

Если мы немного поиграем с конечной точкой httpTrace после выполнения некоторых запросов к нашему сервису, мы увидим, что мы также получаем трассировки для запросов привода:

{
"traces": [
{
"timestamp": "2019-07-28T13:56:36.998Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/actuator/",
// ...
}

Мы можем не найти эти следы полезными для нас, и мы бы предпочли их исключить. В этом случае нам просто нужно создать собственный HttpTraceFilter и указать, какие пути мы хотим игнорировать в методе shouldNotFilter :

@Component
public class TraceRequestFilter extends HttpTraceFilter {

public TraceRequestFilter(HttpTraceRepository repository, HttpExchangeTracer tracer) {
super(repository, tracer);
}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return request.getServletPath().contains("actuator");
}
}

Обратите внимание, что HttpTraceFilter — это обычный фильтр Spring, но с некоторыми специфическими для трассировки функциями.

6. Заключение

В этом руководстве мы представили конечную точку httpTrace Spring Boot Actuator и показали ее основные функции. Мы также копнули немного глубже и объяснили, как изменить некоторые поведения по умолчанию, чтобы они лучше соответствовали нашим конкретным потребностям.

Как всегда, полный исходный код примеров доступен на GitHub .