Обработка трассировок пользовательских заголовков в Spring Boot 3.4
Представьте, что у вас есть веб-сервис Spring Boot 3.4, который без проблем работает с двумя клиентами. Первый клиент использует Spring Boot 3+, что упрощает распространение трассировки. Без каких-либо дополнительных усилий вы получите прекрасную сквозную непрерывность трассировки 🪄. Журналы выглядят чистыми и связанными, как по волшебству.
Однако ситуация меняется, когда в игру вступает клиент номер два. Вместо стандартных заголовков трассировки они отправляют собственные заголовки, такие как ot-custom-traceid и ot-custom-spanid. Хотя эти пользовательские заголовки содержат действительную информацию трассировки, Spring Boot не может распространять эти трассировки. Результат? Вы теряете возможность связывать клиентские трассировки с журналами на стороне сервера.
Это создает разрыв в наблюдаемости. Для первого клиента вы видите полный путь запроса между службами. Для второго клиента вы видите только журналы на стороне сервера, но отсутствует критическая трассировка клиента. Это как увидеть половину пазла: ты знаешь, что чего-то не хватает, но не можешь собрать кусочки воедино. 😓
В этой статье мы рассмотрим, как решить эту проблему не полагаясь на Spring Cloud Sleuth, оставаясь верными экосистеме Spring Boot 3.4. К концу вы будете знать, как распространять и продолжать трассировку из пользовательских заголовков, обеспечивая беспрепятственное наблюдение во всей вашей системе.
Команда | Пример использования |
---|---|
MDC.put | Эта команда добавляет пары ключ-значение в Сопоставленный диагностический контекст (MDC), позволяя включать в журналы пользовательские идентификаторы трассировки. Например, MDC.put("traceId", "12345"). |
MDC.clear | Удаляет все записи из MDC после обработки запроса, чтобы избежать загрязнения трассировки между запросами. Например, MDC.clear(). |
OncePerRequestFilter | Фильтр Spring Boot, который гарантирует, что логика фильтра выполняется только один раз для каждого HTTP-запроса, что идеально подходит для отслеживания заголовков. Пример: общедоступный класс CustomTraceFilter расширяет OncePerRequestFilter. |
filterChain.doFilter | Переходит к следующему фильтру в цепочке, обеспечивая продолжение запроса через другие фильтры. Например, filterChain.doFilter(запрос, ответ). |
RestTemplate.getInterceptors() | Извлекает список перехватчиков для экземпляра RestTemplate, позволяя добавлять собственные перехватчики. Пример: restTemplate.getInterceptors().add(new CustomInterceptor()). |
ClientHttpRequestInterceptor | Интерфейс для перехвата исходящих HTTP-запросов и добавления пользовательских заголовков. Например, реализация ClientHttpRequestInterceptor для вставки идентификаторов трассировки. |
HttpServletRequest.getHeader | Извлекает значение определенного HTTP-заголовка из входящего запроса. Пример: request.getHeader("ot-custom-traceid"). |
FilterRegistrationBean | Регистрирует пользовательские фильтры в приложении Spring Boot. Например: RegistrationBean.setFilter(new CustomTraceFilter()). |
MockMvc.perform | Имитирует HTTP-запросы в модульных тестах для приложений Spring Boot. Пример:ockMvc.perform(get("/test-endpoint").header("ot-custom-traceid", "12345")). |
ClientHttpRequestExecution.execute | Выполняет перехваченный HTTP-запрос с предоставленным телом и заголовками запроса. Пример: выполнение.execute(запрос, тело). |
Распространение пользовательской трассировки заголовка в Spring Boot
Одним из ключевых компонентов решения этой проблемы является CustomTraceFilter. Этот фильтр расширяет OncePerRequestFilter class, гарантируя, что логика заголовка трассировки запускается только один раз для каждого HTTP-запроса. Фильтры в Spring Boot невероятно полезны при глобальном изменении запросов или ответов. Например, если клиент отправляет информацию отслеживания, например ot-custom-traceid или ot-custom-spanid в пользовательских заголовках этот фильтр перехватывает запрос, извлекает эти заголовки и распространяет их в Сопоставленный диагностический контекст (MDC). Добавляя идентификаторы трассировки в MDC, мы гарантируем, что эти идентификаторы будут видны в журналах, создаваемых во время обработки запроса.
MDC является важной частью таких платформ ведения журналов, как SLF4J и Logback. Это позволяет нам хранить контекстную информацию для текущего потока, например пользовательские идентификаторы трассировки. Используя такие команды, как MDC.put и MDC.очистить, мы гарантируем, что система журналирования включает детали трассировки и позволяет избежать загрязнения между одновременными запросами. Например, если второй клиент отправляет ot-custom-traceid как 8f7ebd8a73f9a8f50e6a00a87a20952a, этот идентификатор сохраняется в MDC и включается во все последующие журналы, создавая согласованный путь трассировки.
С другой стороны, для исходящих HTTP-запросов важную роль играет перехватчик RestTemplate. Реализуя КлиентHttpRequestInterceptorмы можем прикреплять одни и те же заголовки трассировки (ot-custom-traceid и ot-custom-spanid) к исходящим запросам. Это гарантирует сохранение непрерывности трассировки, когда приложение вызывает другие микрослужбы. Например, когда сервер обрабатывает запрос с идентификатором трассировки `8f7ebd8a73f9a8f50e6a00a87a20952a`, он присоединяет этот идентификатор к исходящим заголовкам, поэтому нижестоящие службы могут беспрепятственно распознавать и распространять трассировку.
Наконец, модульные тесты, написанные с помощью MockMvc, проверяют всю настройку, моделируя HTTP-запросы и проверяя распространение заголовков. В реальных приложениях тестирование имеет решающее значение для обеспечения правильной обработки заголовков трассировки. Например, отправив запрос GET с настраиваемыми заголовками и проверив ответ или журналы, мы можем убедиться, что фильтр и перехватчик работают должным образом. Этот комплексный подход решает проблему, не полагаясь на устаревшие зависимости, такие как Spring Cloud Sleuth. В конечном итоге сочетание фильтров, перехватчиков и MDC обеспечивает непрерывность трассировки, даже когда клиенты используют собственные заголовки, что делает систему надежной и полностью наблюдаемой. 🌟
Распространение пользовательских заголовков трассировки в Spring Boot 3.4
Использование Java с Spring Boot 3.4 и Micrometer для внутренней обработки
// Solution 1: Extract and Propagate Custom Trace Headers Manually
// Import necessary Spring Boot and Micrometer libraries
import org.slf4j.MDC;
import org.springframework.http.HttpHeaders;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomTraceFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException {
String traceId = request.getHeader("ot-custom-traceid");
String spanId = request.getHeader("ot-custom-spanid");
try {
if (traceId != null) {
MDC.put("traceId", traceId); // Add traceId to Mapped Diagnostic Context
}
if (spanId != null) {
MDC.put("spanId", spanId);
}
filterChain.doFilter(request, response); // Continue request processing
} finally {
MDC.clear(); // Ensure MDC is cleared after processing
}
}
}
// Register the filter in your configuration class
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<CustomTraceFilter> traceFilter() {
FilterRegistrationBean<CustomTraceFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomTraceFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}
Модульный тест для распространения пользовательского заголовка трассировки
Тестирование с помощью JUnit и MockMvc для проверки распространения заголовка трассировки
// Import necessary libraries
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest
public class CustomTraceFilterTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testCustomTraceHeaders() throws Exception {
mockMvc.perform(get("/test-endpoint")
.header("ot-custom-traceid", "12345")
.header("ot-custom-spanid", "67890"))
.andExpect(status().isOk());
}
}
Распространение пользовательских заголовков в HTTP-запросах с использованием RestTemplate
Использование перехватчиков RestTemplate для добавления пользовательских заголовков в исходящие запросы
// Import necessary libraries
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
public class CustomHeaderInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("ot-custom-traceid", "12345");
headers.add("ot-custom-spanid", "67890");
return execution.execute(request, body);
}
}
// Register the interceptor with RestTemplate
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new CustomHeaderInterceptor());
return restTemplate;
}
}
Обработка пользовательских трассировок заголовков с помощью OpenTelemetry в Spring Boot 3.4
При работе с Spring Boot 3.4 еще одним мощным подходом к распространению трассировок из пользовательских заголовков является интеграция OpenTelemetry. OpenTelemetry, платформа наблюдения с открытым исходным кодом, помогает беспрепятственно анализировать, собирать и экспортировать трассировки. Он предоставляет механизмы для извлечения и внедрения контекста трассировки, включая пользовательские заголовки, такие как ot-custom-traceid и ot-custom-spanid, в ваше приложение. Используя TextMapPropagator OpenTelemetry, вы можете устранить разрыв между нестандартными клиентами и вашей системой наблюдения.
Чтобы использовать OpenTelemetry в Spring Boot 3.4, можно реализовать пользовательский распространитель для извлечения информации трассировки из пользовательских заголовков и присоединения ее к текущему контексту трассировки. Например, когда ваш сервер получает входящий запрос от второго клиента, OpenTelemetry может анализировать пользовательские заголовки и восстанавливать исходный контекст трассировки. Это гарантирует, что нижестоящие службы будут видеть одни и те же идентификаторы трассировки, обеспечивая сквозную видимость. В отличие от старых решений, таких как Spring Cloud Sleuth, OpenTelemetry является легковесным и соответствует современным стандартам наблюдения.
Объединив распространитель OpenTelemetry с Micrometer, вы можете обогатить свои метрики и журналы информацией трассировки. Представьте себе, что в вашем инструменте наблюдения вы можете легко отслеживать запросы, поступающие как от первого, так и от второго клиента. OpenTelemetry автоматически поддерживает интеграцию с Prometheus, Zipkin или Jaeger, что позволяет централизовать визуализацию трассировки. Такой подход гарантирует, что даже при использовании пользовательских заголовков данные трассировки не будут потеряны, а отладка станет значительно проще. 🚀
Часто задаваемые вопросы о распространении пользовательских трассировок в Spring Boot
- Как вручную извлечь пользовательские заголовки трассировки в Spring Boot?
- Вы можете использовать request.getHeader("custom-header"), чтобы вручную получить определенный заголовок и добавить его в MDC с помощью MDC.put("traceId", value).
- В чем преимущество использования OpenTelemetry для распространения пользовательской трассировки?
- OpenTelemetry обеспечивает современный, независимый от поставщика подход к распространению трассировок, включая настраиваемые заголовки, между микросервисами.
- Могу ли я распространять пользовательские заголовки с помощью RestTemplate в Spring Boot?
- Да, реализовав ClientHttpRequestInterceptor, вы можете прикреплять к исходящим запросам собственные заголовки, такие как traceid и spanid.
- Как зарегистрировать фильтр для глобального захвата заголовков?
- Вы можете создать фильтр, расширяющий OncePerRequestFilter, и зарегистрировать его с помощью FilterRegistrationBean для захвата заголовков для всех конечных точек.
- Какие инструменты я могу использовать для визуализации трассировок Spring Boot?
- Такие инструменты, как Zipkin, Jaeger и Prometheus, можно интегрировать со Spring Boot и OpenTelemetry для визуализации сквозных трассировок.
Обеспечение непрерывности трассировки
В современных системах обработка пользовательских заголовков трассировки имеет решающее значение для надежного наблюдения. Используя фильтры и перехватчики, вы можете собирать информацию трассировки, предоставляемую клиентом, и правильно распространять ее по своим службам. Это позволяет избежать фрагментации журналов и отсутствия следов. 🔍
Spring Boot 3.4 в сочетании с Micrometer или OpenTelemetry позволяет создавать надежные решения, не полагаясь на старые инструменты, такие как Spring Cloud Sleuth. Независимо от того, имеете ли вы дело со стандартными заголовками Client One или пользовательскими заголовками Client Two, реализация этих методов эффективно устраняет пробелы в трассировке. 🚀
Источники и ссылки
- Официальная документация Spring Boot: распространение контекстов трассировки. Документация Spring Boot
- OpenTelemetry для разработчиков Java: руководство по распространению трассировки. OpenTelemetry Java
- Документация по наблюдаемости микрометра: интеграция пользовательских заголовков трасс. Микрометрическая наблюдаемость
- API ведения журнала SLF4J: варианты использования сопоставленного диагностического контекста (MDC). SLF4J Руководство