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 .