From 5d7e06e9c3fcad0cb19560513509065deecfb273 Mon Sep 17 00:00:00 2001 From: Tommy Ludwig <8924140+shakuzen@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:52:12 +0900 Subject: [PATCH] Avoid Stream API in performance critical tracing code Update composite tracing support to remove Stream API calls from injection and extraction methods which happen on each request. See gh-46838 --- .../tracing/CompositePropagationFactory.java | 56 +++++++++++++------ .../tracing/CompositeTextMapPropagator.java | 13 +++-- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositePropagationFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositePropagationFactory.java index ab14c12f34a..79aed6b1f32 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositePropagationFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositePropagationFactory.java @@ -19,7 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.function.Predicate; import java.util.stream.Stream; import brave.propagation.B3Propagation; @@ -76,11 +75,19 @@ class CompositePropagationFactory extends Propagation.Factory { @Override public TraceContext decorate(TraceContext context) { - return Stream.concat(this.injectors.stream(), this.extractors.stream()) - .map((factory) -> factory.decorate(context)) - .filter((decorated) -> decorated != context) - .findFirst() - .orElse(context); + for (Propagation.Factory factory : this.injectors.factories) { + TraceContext decorated = factory.decorate(context); + if (decorated != context) { + return decorated; + } + } + for (Propagation.Factory factory : this.extractors.factories) { + TraceContext decorated = factory.decorate(context); + if (decorated != context) { + return decorated; + } + } + return context; } /** @@ -179,11 +186,21 @@ class CompositePropagationFactory extends Propagation.Factory { } boolean requires128BitTraceId() { - return stream().anyMatch(Propagation.Factory::requires128BitTraceId); + for (Propagation.Factory factory : this.factories) { + if (factory.requires128BitTraceId()) { + return true; + } + } + return false; } boolean supportsJoin() { - return stream().allMatch(Propagation.Factory::supportsJoin); + for (Propagation.Factory factory : this.factories) { + if (!factory.supportsJoin()) { + return false; + } + } + return true; } List> get() { @@ -224,19 +241,24 @@ class CompositePropagationFactory extends Propagation.Factory { @Override public TraceContext.Injector injector(Setter setter) { - return (traceContext, request) -> this.injectors.stream() - .map((propagation) -> propagation.injector(setter)) - .forEach((injector) -> injector.inject(traceContext, request)); + return (traceContext, request) -> { + for (Propagation propagation : this.injectors) { + propagation.injector(setter).inject(traceContext, request); + } + }; } @Override public TraceContext.Extractor extractor(Getter getter) { - return (request) -> this.extractors.stream() - .map((propagation) -> propagation.extractor(getter)) - .map((extractor) -> extractor.extract(request)) - .filter(Predicate.not(TraceContextOrSamplingFlags.EMPTY::equals)) - .findFirst() - .orElse(TraceContextOrSamplingFlags.EMPTY); + return (request) -> { + for (Propagation propagation : this.extractors) { + TraceContextOrSamplingFlags extracted = propagation.extractor(getter).extract(request); + if (!TraceContextOrSamplingFlags.EMPTY.equals(extracted)) { + return extracted; + } + } + return TraceContextOrSamplingFlags.EMPTY; + }; } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositeTextMapPropagator.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositeTextMapPropagator.java index 1278fef2130..1028c55dabd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositeTextMapPropagator.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositeTextMapPropagator.java @@ -106,11 +106,14 @@ class CompositeTextMapPropagator implements TextMapPropagator { if (getter == null) { return context; } - Context result = this.extractors.stream() - .map((extractor) -> extractor.extract(context, carrier, getter)) - .filter((extracted) -> extracted != context) - .findFirst() - .orElse(context); + Context result = context; + for (TextMapPropagator extractor : this.extractors) { + Context extracted = extractor.extract(context, carrier, getter); + if (extracted != context) { + result = extracted; + break; + } + } if (this.baggagePropagator != null) { result = this.baggagePropagator.extract(result, carrier, getter); }