Skip to content

Commit 5bcc577

Browse files
committed
Avoid Stream API in performance critical tracing code
Injection and extraction of the tracing context happens on each request. For example, on each call to a Controller or HTTP client. The Stream API used here was showing up on CPU profiling under heavy load. With these changes, the CPU profiling looks better.
1 parent 8861304 commit 5bcc577

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositePropagationFactory.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,19 @@ public Propagation<String> get() {
7676

7777
@Override
7878
public TraceContext decorate(TraceContext context) {
79-
return Stream.concat(this.injectors.stream(), this.extractors.stream())
80-
.map((factory) -> factory.decorate(context))
81-
.filter((decorated) -> decorated != context)
82-
.findFirst()
83-
.orElse(context);
79+
for (Propagation.Factory factory : this.injectors.factories) {
80+
TraceContext decorated = factory.decorate(context);
81+
if (decorated != context) {
82+
return decorated;
83+
}
84+
}
85+
for (Propagation.Factory factory : this.extractors.factories) {
86+
TraceContext decorated = factory.decorate(context);
87+
if (decorated != context) {
88+
return decorated;
89+
}
90+
}
91+
return context;
8492
}
8593

8694
/**
@@ -179,11 +187,21 @@ private static class PropagationFactories {
179187
}
180188

181189
boolean requires128BitTraceId() {
182-
return stream().anyMatch(Propagation.Factory::requires128BitTraceId);
190+
for (Propagation.Factory factory : this.factories) {
191+
if (factory.requires128BitTraceId()) {
192+
return true;
193+
}
194+
}
195+
return false;
183196
}
184197

185198
boolean supportsJoin() {
186-
return stream().allMatch(Propagation.Factory::supportsJoin);
199+
for (Propagation.Factory factory : this.factories) {
200+
if (!factory.supportsJoin()) {
201+
return false;
202+
}
203+
}
204+
return true;
187205
}
188206

189207
List<Propagation<String>> get() {
@@ -224,19 +242,24 @@ public List<String> keys() {
224242

225243
@Override
226244
public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {
227-
return (traceContext, request) -> this.injectors.stream()
228-
.map((propagation) -> propagation.injector(setter))
229-
.forEach((injector) -> injector.inject(traceContext, request));
245+
return (traceContext, request) -> {
246+
for (Propagation<String> propagation : this.injectors) {
247+
propagation.injector(setter).inject(traceContext, request);
248+
}
249+
};
230250
}
231251

232252
@Override
233253
public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {
234-
return (request) -> this.extractors.stream()
235-
.map((propagation) -> propagation.extractor(getter))
236-
.map((extractor) -> extractor.extract(request))
237-
.filter(Predicate.not(TraceContextOrSamplingFlags.EMPTY::equals))
238-
.findFirst()
239-
.orElse(TraceContextOrSamplingFlags.EMPTY);
254+
return (request) -> {
255+
for (Propagation<String> propagation : this.extractors) {
256+
TraceContextOrSamplingFlags extracted = propagation.extractor(getter).extract(request);
257+
if (!TraceContextOrSamplingFlags.EMPTY.equals(extracted)) {
258+
return extracted;
259+
}
260+
}
261+
return TraceContextOrSamplingFlags.EMPTY;
262+
};
240263
}
241264

242265
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/CompositeTextMapPropagator.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,14 @@ public <C> Context extract(Context context, C carrier, TextMapGetter<C> getter)
106106
if (getter == null) {
107107
return context;
108108
}
109-
Context result = this.extractors.stream()
110-
.map((extractor) -> extractor.extract(context, carrier, getter))
111-
.filter((extracted) -> extracted != context)
112-
.findFirst()
113-
.orElse(context);
109+
Context result = context;
110+
for (TextMapPropagator extractor : this.extractors) {
111+
Context extracted = extractor.extract(context, carrier, getter);
112+
if (extracted != context) {
113+
result = extracted;
114+
break;
115+
}
116+
}
114117
if (this.baggagePropagator != null) {
115118
result = this.baggagePropagator.extract(result, carrier, getter);
116119
}

0 commit comments

Comments
 (0)