Jak používat Spring Boot 3.4 k šíření trasování z vlastních záhlaví

Tracing

Zpracování vlastních trasování záhlaví v aplikaci Spring Boot 3.4

Představte si, že máte webovou službu Spring Boot 3.4, která bezproblémově spolupracuje se dvěma klienty. První klient používá Spring Boot 3+, díky čemuž je šíření trasování hračkou. Bez dalšího úsilí získáte nádhernou kontinuitu trasování od začátku do konce 🪄. Protokoly vypadají čistě a propojené, jakoby kouzlem.

Věci se však obrátí, když do hry vstoupí klient dva. Namísto standardních trasovacích hlaviček odesílají vlastní hlavičky jako `ot-custom-traceid` a `ot-custom-spanid`. Zatímco tato vlastní záhlaví obsahují platné informace o trasování, Spring Boot selhává při šíření těchto trasování. Výsledek? Ztratíte možnost propojit trasování klienta s protokoly na straně serveru.

To vytváří mezeru v pozorovatelnosti. U klienta jedna vidíte úplnou cestu požadavku napříč službami. U klienta 2 vidíte pouze protokoly na straně serveru, chybí kritické trasování klienta. Je to jako vidět polovinu skládačky – víte, že něco chybí, ale nedokážete poskládat kousky dohromady. 😓

V tomto článku prozkoumáme, jak tento problém vyřešit aniž bychom se spoléhali na Spring Cloud Sleuth, a přitom zůstaneme věrní ekosystému Spring Boot 3.4. Na konci budete vědět, jak šířit a pokračovat ve trasování z vlastních záhlaví, což zajistí bezproblémovou pozorovatelnost v celém systému.

Příkaz Příklad použití
MDC.put Tento příkaz přidá páry klíč–hodnota do Mapped Diagnostic Context (MDC), což umožňuje zahrnutí vlastních ID trasování do protokolů. Například MDC.put("traceId", "12345").
MDC.clear Po zpracování požadavku vymaže všechny položky z MDC, aby se zabránilo kontaminaci trasování mezi požadavky. Například MDC.clear().
OncePerRequestFilter Filtr Spring Boot, který zajišťuje, že logika filtru je spuštěna pouze jednou na požadavek HTTP, ideální pro trasování záhlaví. Příklad: veřejná třída CustomTraceFilter rozšiřuje OncePerRequestFilter.
filterChain.doFilter Přejde k dalšímu filtru v řetězci a zajistí, že požadavek bude pokračovat přes další filtry. Například filterChain.doFilter(požadavek, odpověď).
RestTemplate.getInterceptors() Načte seznam interceptorů pro instanci RestTemplate, což umožňuje přidání vlastních interceptorů. Příklad: restTemplate.getInterceptors().add(new CustomInterceptor()).
ClientHttpRequestInterceptor Rozhraní pro zachycování odchozích požadavků HTTP a přidávání vlastních hlaviček. Například implementace ClientHttpRequestInterceptor pro vložení ID trasování.
HttpServletRequest.getHeader Extrahuje hodnotu konkrétní hlavičky HTTP z příchozího požadavku. Příklad: request.getHeader("ot-custom-traceid").
FilterRegistrationBean Registruje vlastní filtry v aplikaci Spring Boot. Například: registrationBean.setFilter(new CustomTraceFilter()).
MockMvc.perform Simuluje požadavky HTTP v testech jednotek pro aplikace Spring Boot. Příklad: mockMvc.perform(get("/test-endpoint").header("ot-custom-traceid", "12345")).
ClientHttpRequestExecution.execute Provede zachycený HTTP požadavek s poskytnutým tělem požadavku a hlavičkami. Příklad: exekuce.execute(požadavek, tělo).

Vlastní šíření trasování záhlaví v Spring Boot

Jednou z klíčových součástí při řešení tohoto problému je CustomTraceFilter. Tento filtr rozšiřuje třídy, což zajišťuje, že logika trasovací hlavičky běží pouze jednou pro každý požadavek HTTP. Filtry v aplikaci Spring Boot jsou neuvěřitelně užitečné při globální úpravě požadavků nebo odpovědí. Například pokud klient odešle informace o sledování jako nebo ve vlastních záhlavích tento filtr zachytí požadavek, extrahuje tato záhlaví a rozšíří je do Mapped Diagnostic Context (MDC). Přidáním ID trasování do MDC zajistíme, že tyto identifikátory budou viditelné v protokolech generovaných během zpracování požadavku.

MDC je kritickou součástí protokolovacích rámců, jako jsou SLF4J a Logback. Umožňuje nám ukládat kontextové informace pro aktuální vlákno, jako jsou vlastní ID trasování. Pomocí příkazů jako a , zajistíme, aby systém protokolování obsahoval podrobnosti o sledování a zabránil kontaminaci mezi souběžnými požadavky. Pokud například klient dva odešle `ot-custom-traceid` jako `8f7ebd8a73f9a8f50e6a00a87a20952a`, toto ID je uloženo v MDC a zahrnuto do všech následných protokolů, čímž se vytvoří konzistentní cesta trasování.

Na druhou stranu u odchozích HTTP požadavků hraje RestTemplate interceptor zásadní roli. Zavedením , můžeme k odchozím požadavkům připojit stejné trasovací hlavičky (`ot-custom-traceid` a `ot-custom-spanid`). Tím je zajištěno, že je zachována kontinuita trasování, když aplikace volá jiné mikroslužby. Když například server zpracuje požadavek s ID trasování `8f7ebd8a73f9a8f50e6a00a87a20952a`, připojí toto ID k odchozím hlavičkám, takže následné služby mohou trasování bez problémů rozpoznat a šířit.

Nakonec testy jednotek napsané pomocí MockMvc ověří celé nastavení simulací požadavků HTTP a ověřením šíření hlaviček. V aplikacích v reálném světě je testování zásadní, aby se zajistilo správné zpracování hlaviček trasování. Například odesláním požadavku GET s vlastními hlavičkami a kontrolou odpovědi nebo protokolů můžeme potvrdit, že filtr a interceptor fungují podle očekávání. Tento komplexní přístup řeší problém, aniž by se spoléhal na starší závislosti, jako je Spring Cloud Sleuth. V konečném důsledku kombinace filtrů, zachycovačů a MDC zajišťuje kontinuitu sledování, i když klienti používají vlastní hlavičky, díky čemuž je systém robustní a plně pozorovatelný. 🌟

Šíření vlastních hlaviček trasování v aplikaci Spring Boot 3.4

Použití Javy s Spring Boot 3.4 a Micrometer pro Backend Processing

// 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;
    }
}

Test jednotky pro vlastní šíření záhlaví trasování

Testování pomocí JUnit a MockMvc pro ověření šíření trasovacích záhlaví

// 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());
    }
}

Šíření vlastních záhlaví v požadavcích HTTP pomocí RestTemplate

Použití zachycovačů RestTemplate k přidání vlastních záhlaví do odchozích požadavků

// 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;
    }
}

Zpracování vlastních trasování záhlaví pomocí OpenTelemetry v aplikaci Spring Boot 3.4

Při práci s Spring Boot 3.4 je dalším účinným přístupem k šíření trasování z vlastních hlaviček integrace . OpenTelemetry, open-source rámec pro pozorovatelnost, pomáhá bezproblémově instrumentovat, shromažďovat a exportovat stopy. Poskytuje mechanismy pro extrahování a vkládání kontextu trasování, včetně vlastních hlaviček jako a , do vaší aplikace. Využitím TextMapPropagator od OpenTelemetry můžete překlenout propast mezi nestandardními klienty a vaším systémem pozorovatelnosti.

Chcete-li použít OpenTelemetry v Spring Boot 3.4, lze implementovat vlastní propagátor, který extrahuje informace o sledování z vlastních záhlaví a připojí je k aktuálnímu kontextu trasování. Když například váš server obdrží příchozí požadavek od klienta 2, OpenTelemetry může analyzovat vlastní záhlaví a rekonstruovat původní kontext trasování. To zajišťuje, že navazující služby uvidí stejná ID trasování, což umožňuje viditelnost od začátku do konce. Na rozdíl od starších řešení, jako je Spring Cloud Sleuth, je OpenTelemetry lehká a odpovídá moderním standardům pozorovatelnosti.

Kombinací propagátoru OpenTelemetry s Mikrometrem můžete obohatit své metriky a protokolování o informace o sledování. Představte si, že ve svém nástroji pro sledování můžete bezproblémově vidět stopy požadavků přicházejících od klienta 1 i klienta 2. OpenTelemetry automaticky podporuje integrace s Prometheus, Zipkin nebo Jaeger, což vám umožňuje centralizovat vizualizaci trasování. Tento přístup zajišťuje, že i když jsou použity vlastní hlavičky, nedojde ke ztrátě dat trasování a ladění se výrazně zjednoduší. 🚀

  1. Jak mohu ručně extrahovat vlastní záhlaví trasování v aplikaci Spring Boot?
  2. Pomocí request.getHeader("custom-header") můžete ručně načíst konkrétní záhlaví a přidat je do MDC pomocí MDC.put("traceId", hodnota).
  3. Jaká je výhoda použití OpenTelemetry pro vlastní šíření trasování?
  4. OpenTelemetry poskytuje moderní, na dodavatele neutrální přístup k šíření trasování, včetně vlastních hlaviček, napříč mikroslužbami.
  5. Mohu propagovat vlastní záhlaví pomocí RestTemplate v aplikaci Spring Boot?
  6. Ano, implementací ClientHttpRequestInterceptor můžete k odchozím požadavkům připojit vlastní záhlaví jako traceid a spanid.
  7. Jak zaregistruji filtr pro globální zachycení záhlaví?
  8. Můžete vytvořit filtr, který rozšiřuje OncePerRequestFilter a zaregistrovat jej pomocí FilterRegistrationBean k zachycení záhlaví pro všechny koncové body.
  9. Jaké nástroje mohu použít k vizualizaci tras z Spring Boot?
  10. Nástroje jako Zipkin, Jaeger a Prometheus lze integrovat se Spring Boot a OpenTelemetry pro vizualizaci tras od začátku do konce.

V moderních systémech je pro spolehlivou pozorovatelnost kritická manipulace s vlastními hlavičkami trasování. Pomocí filtrů a zachycovačů můžete zachytit informace o sledování poskytnuté klientem a správně je šířit ve vašich službách. Vyhnete se tak fragmentovaným protokolům a chybějícím stopám. 🔍

Spring Boot 3.4 v kombinaci s Micrometer nebo OpenTelemetry umožňuje robustní řešení bez spoléhání se na starší nástroje, jako je Spring Cloud Sleuth. Ať už máte co do činění se standardními hlavičkami klienta 1 nebo vlastními hlavičkami klienta 2, implementace těchto technik efektivně překlene mezery ve trasování. 🚀

  1. Oficiální dokumentace Spring Boot: Propagation of Tracing Contexts. Spring Boot dokumentace
  2. OpenTelemetry for Java Developers: Guide to Trace Propagation. OpenTelemetry Java
  3. Dokumentace pozorovatelnosti mikrometru: Integrace vlastních trasovacích hlaviček. Pozorovatelnost mikrometru
  4. SLF4J protokolování API: Případy použití mapovaného diagnostického kontextu (MDC). Manuál SLF4J