|
19 | 19 | import java.util.Collection;
|
20 | 20 | import java.util.Collections;
|
21 | 21 | import java.util.List;
|
| 22 | +import java.util.function.Predicate; |
22 | 23 | import java.util.stream.Stream;
|
23 | 24 |
|
24 | 25 | import brave.internal.propagation.StringPropagationAdapter;
|
25 | 26 | import brave.propagation.B3Propagation;
|
26 | 27 | import brave.propagation.Propagation;
|
| 28 | +import brave.propagation.Propagation.Factory; |
27 | 29 | import brave.propagation.TraceContext;
|
28 | 30 | import brave.propagation.TraceContextOrSamplingFlags;
|
| 31 | +import graphql.com.google.common.collect.Streams; |
29 | 32 | import io.micrometer.tracing.BaggageManager;
|
30 | 33 | import io.micrometer.tracing.brave.bridge.W3CPropagation;
|
31 | 34 |
|
| 35 | +import org.springframework.boot.actuate.autoconfigure.tracing.TracingProperties.Propagation.PropagationType; |
| 36 | + |
32 | 37 | /**
|
33 |
| - * {@link Factory} which supports multiple tracing formats. It is able to configure |
34 |
| - * different formats for injecting and for extracting. |
| 38 | + * {@link brave.propagation.Propagation.Factory Propagation factory} which supports |
| 39 | + * multiple tracing formats. It is able to configure different formats for injecting and |
| 40 | + * for extracting. |
35 | 41 | *
|
36 | 42 | * @author Marcin Grzejszczak
|
37 | 43 | * @author Moritz Halbritter
|
| 44 | + * @author Phillip Webb |
38 | 45 | */
|
39 |
| -class CompositePropagationFactory extends Propagation.Factory implements Propagation<String> { |
40 |
| - |
41 |
| - private final Collection<Propagation.Factory> injectorFactories; |
42 |
| - |
43 |
| - private final Collection<Propagation.Factory> extractorFactories; |
44 |
| - |
45 |
| - private final List<Propagation<String>> injectors; |
| 46 | +class CompositePropagationFactory extends Propagation.Factory { |
46 | 47 |
|
47 |
| - private final List<Propagation<String>> extractors; |
| 48 | + private final PropagationFactories injectors; |
48 | 49 |
|
49 |
| - private final boolean supportsJoin; |
| 50 | + private final PropagationFactories extractors; |
50 | 51 |
|
51 |
| - private final boolean requires128BitTraceId; |
52 |
| - |
53 |
| - private final List<String> keys; |
| 52 | + private final CompositePropagation propagation; |
54 | 53 |
|
55 | 54 | CompositePropagationFactory(Collection<Factory> injectorFactories, Collection<Factory> extractorFactories) {
|
56 |
| - this.injectorFactories = injectorFactories; |
57 |
| - this.extractorFactories = extractorFactories; |
58 |
| - this.injectors = this.injectorFactories.stream().map(Factory::get).toList(); |
59 |
| - this.extractors = this.extractorFactories.stream().map(Factory::get).toList(); |
60 |
| - this.supportsJoin = Stream.concat(this.injectorFactories.stream(), this.extractorFactories.stream()) |
61 |
| - .allMatch(Factory::supportsJoin); |
62 |
| - this.requires128BitTraceId = Stream.concat(this.injectorFactories.stream(), this.extractorFactories.stream()) |
63 |
| - .anyMatch(Factory::requires128BitTraceId); |
64 |
| - this.keys = Stream.concat(this.injectors.stream(), this.extractors.stream()) |
65 |
| - .flatMap((entry) -> entry.keys().stream()) |
66 |
| - .distinct() |
67 |
| - .toList(); |
68 |
| - } |
69 |
| - |
70 |
| - Collection<Factory> getInjectorFactories() { |
71 |
| - return this.injectorFactories; |
| 55 | + this.injectors = new PropagationFactories(injectorFactories); |
| 56 | + this.extractors = new PropagationFactories(extractorFactories); |
| 57 | + this.propagation = new CompositePropagation(this.injectors, this.extractors); |
72 | 58 | }
|
73 | 59 |
|
74 |
| - @Override |
75 |
| - public List<String> keys() { |
76 |
| - return this.keys; |
| 60 | + Stream<Factory> getInjectors() { |
| 61 | + return this.injectors.stream(); |
77 | 62 | }
|
78 | 63 |
|
79 | 64 | @Override
|
80 |
| - public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) { |
81 |
| - return (traceContext, request) -> { |
82 |
| - for (Propagation<String> injector : this.injectors) { |
83 |
| - injector.injector(setter).inject(traceContext, request); |
84 |
| - } |
85 |
| - }; |
| 65 | + public boolean supportsJoin() { |
| 66 | + return this.injectors.supportsJoin() && this.extractors.supportsJoin(); |
86 | 67 | }
|
87 | 68 |
|
88 | 69 | @Override
|
89 |
| - public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) { |
90 |
| - return (request) -> { |
91 |
| - for (Propagation<String> extractor : this.extractors) { |
92 |
| - TraceContextOrSamplingFlags extract = extractor.extractor(getter).extract(request); |
93 |
| - if (extract != TraceContextOrSamplingFlags.EMPTY) { |
94 |
| - return extract; |
95 |
| - } |
96 |
| - } |
97 |
| - return TraceContextOrSamplingFlags.EMPTY; |
98 |
| - }; |
| 70 | + public boolean requires128BitTraceId() { |
| 71 | + return this.injectors.requires128BitTraceId() || this.extractors.requires128BitTraceId(); |
99 | 72 | }
|
100 | 73 |
|
101 | 74 | @Override
|
102 | 75 | @SuppressWarnings("deprecation")
|
103 |
| - public <K> Propagation<K> create(KeyFactory<K> keyFactory) { |
104 |
| - return StringPropagationAdapter.create(this, keyFactory); |
105 |
| - } |
106 |
| - |
107 |
| - @Override |
108 |
| - public boolean supportsJoin() { |
109 |
| - return this.supportsJoin; |
110 |
| - } |
111 |
| - |
112 |
| - @Override |
113 |
| - public boolean requires128BitTraceId() { |
114 |
| - return this.requires128BitTraceId; |
| 76 | + public <K> Propagation<K> create(Propagation.KeyFactory<K> keyFactory) { |
| 77 | + return StringPropagationAdapter.create(this.propagation, keyFactory); |
115 | 78 | }
|
116 | 79 |
|
117 | 80 | @Override
|
118 | 81 | public TraceContext decorate(TraceContext context) {
|
119 |
| - for (Factory injectorFactory : this.injectorFactories) { |
120 |
| - TraceContext decorated = injectorFactory.decorate(context); |
121 |
| - if (decorated != context) { |
122 |
| - return decorated; |
123 |
| - } |
124 |
| - } |
125 |
| - for (Factory extractorFactory : this.extractorFactories) { |
126 |
| - TraceContext decorated = extractorFactory.decorate(context); |
127 |
| - if (decorated != context) { |
128 |
| - return decorated; |
129 |
| - } |
130 |
| - } |
131 |
| - return super.decorate(context); |
| 82 | + return Streams.concat(this.injectors.stream(), this.extractors.stream()) |
| 83 | + .map((factory) -> factory.decorate(context)) |
| 84 | + .filter((decorated) -> decorated != context) |
| 85 | + .findFirst() |
| 86 | + .orElse(context); |
132 | 87 | }
|
133 | 88 |
|
134 | 89 | /**
|
135 | 90 | * Creates a new {@link CompositePropagationFactory}, which uses the given
|
136 | 91 | * {@code injectionTypes} for injection and {@code extractionTypes} for extraction.
|
| 92 | + * @param properties the propagation properties |
137 | 93 | * @param baggageManager the baggage manager to use, or {@code null}
|
138 |
| - * @param injectionTypes the propagation types for injection |
139 |
| - * @param extractionTypes the propagation types for extraction |
140 | 94 | * @return the {@link CompositePropagationFactory}
|
141 | 95 | */
|
142 |
| - static CompositePropagationFactory create(BaggageManager baggageManager, |
143 |
| - Collection<TracingProperties.Propagation.PropagationType> injectionTypes, |
144 |
| - Collection<TracingProperties.Propagation.PropagationType> extractionTypes) { |
145 |
| - List<Factory> injectors = injectionTypes.stream() |
146 |
| - .map((injection) -> factoryForType(baggageManager, injection)) |
147 |
| - .toList(); |
148 |
| - List<Factory> extractors = extractionTypes.stream() |
149 |
| - .map((extraction) -> factoryForType(baggageManager, extraction)) |
150 |
| - .toList(); |
| 96 | + static CompositePropagationFactory create(TracingProperties.Propagation properties, BaggageManager baggageManager) { |
| 97 | + PropagationFactoryMapper mapper = new PropagationFactoryMapper(baggageManager); |
| 98 | + List<Factory> injectors = properties.getEffectiveProducedTypes().stream().map(mapper::map).toList(); |
| 99 | + List<Factory> extractors = properties.getEffectiveConsumedTypes().stream().map(mapper::map).toList(); |
151 | 100 | return new CompositePropagationFactory(injectors, extractors);
|
152 | 101 | }
|
153 | 102 |
|
154 | 103 | /**
|
155 |
| - * Creates a new {@link CompositePropagationFactory}, which uses the given |
156 |
| - * {@code injectionTypes} for injection and {@code extractionTypes} for extraction. |
157 |
| - * @param injectionTypes the propagation types for injection |
158 |
| - * @param extractionTypes the propagation types for extraction |
159 |
| - * @return the {@link CompositePropagationFactory} |
| 104 | + * Mapper used to create a {@link brave.propagation.Propagation.Factory Propagation |
| 105 | + * factory} from a {@link PropagationType}. |
160 | 106 | */
|
161 |
| - static CompositePropagationFactory create(Collection<TracingProperties.Propagation.PropagationType> injectionTypes, |
162 |
| - Collection<TracingProperties.Propagation.PropagationType> extractionTypes) { |
163 |
| - return create(null, injectionTypes, extractionTypes); |
164 |
| - } |
| 107 | + private static class PropagationFactoryMapper { |
165 | 108 |
|
166 |
| - private static Factory factoryForType(BaggageManager baggageManager, |
167 |
| - TracingProperties.Propagation.PropagationType type) { |
168 |
| - return switch (type) { |
169 |
| - case B3 -> b3Single(); |
170 |
| - case B3_MULTI -> b3Multi(); |
171 |
| - case W3C -> w3c(baggageManager); |
172 |
| - }; |
173 |
| - } |
| 109 | + private final BaggageManager baggageManager; |
| 110 | + |
| 111 | + PropagationFactoryMapper(BaggageManager baggageManager) { |
| 112 | + this.baggageManager = baggageManager; |
| 113 | + } |
| 114 | + |
| 115 | + Propagation.Factory map(PropagationType type) { |
| 116 | + return switch (type) { |
| 117 | + case B3 -> b3Single(); |
| 118 | + case B3_MULTI -> b3Multi(); |
| 119 | + case W3C -> w3c(); |
| 120 | + }; |
| 121 | + } |
| 122 | + |
| 123 | + /** |
| 124 | + * Creates a new B3 propagation factory using a single B3 header. |
| 125 | + * @return the B3 propagation factory |
| 126 | + */ |
| 127 | + private Propagation.Factory b3Single() { |
| 128 | + return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build(); |
| 129 | + } |
| 130 | + |
| 131 | + /** |
| 132 | + * Creates a new B3 propagation factory using multiple B3 headers. |
| 133 | + * @return the B3 propagation factory |
| 134 | + */ |
| 135 | + private Propagation.Factory b3Multi() { |
| 136 | + return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.MULTI).build(); |
| 137 | + } |
| 138 | + |
| 139 | + /** |
| 140 | + * Creates a new W3C propagation factory. |
| 141 | + * @return the W3C propagation factory |
| 142 | + */ |
| 143 | + private Propagation.Factory w3c() { |
| 144 | + return (this.baggageManager != null) ? new W3CPropagation(this.baggageManager, Collections.emptyList()) |
| 145 | + : new W3CPropagation(); |
| 146 | + } |
174 | 147 |
|
175 |
| - /** |
176 |
| - * Creates a new B3 propagation factory using a single B3 header. |
177 |
| - * @return the B3 propagation factory |
178 |
| - */ |
179 |
| - private static Factory b3Single() { |
180 |
| - return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build(); |
181 | 148 | }
|
182 | 149 |
|
183 | 150 | /**
|
184 |
| - * Creates a new B3 propagation factory using multiple B3 headers. |
185 |
| - * @return the B3 propagation factory |
| 151 | + * A collection of propagation factories. |
186 | 152 | */
|
187 |
| - private static Factory b3Multi() { |
188 |
| - return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.MULTI).build(); |
| 153 | + private static class PropagationFactories { |
| 154 | + |
| 155 | + private final List<Propagation.Factory> factories; |
| 156 | + |
| 157 | + PropagationFactories(Collection<Factory> factories) { |
| 158 | + this.factories = List.copyOf(factories); |
| 159 | + } |
| 160 | + |
| 161 | + boolean requires128BitTraceId() { |
| 162 | + return stream().anyMatch(Propagation.Factory::requires128BitTraceId); |
| 163 | + } |
| 164 | + |
| 165 | + boolean supportsJoin() { |
| 166 | + return stream().allMatch(Propagation.Factory::supportsJoin); |
| 167 | + } |
| 168 | + |
| 169 | + List<Propagation<String>> get() { |
| 170 | + return stream().map(Factory::get).toList(); |
| 171 | + } |
| 172 | + |
| 173 | + Stream<Factory> stream() { |
| 174 | + return this.factories.stream(); |
| 175 | + } |
| 176 | + |
189 | 177 | }
|
190 | 178 |
|
191 | 179 | /**
|
192 |
| - * Creates a new W3C propagation factory. |
193 |
| - * @param baggageManager baggage manager to use, or {@code null} |
194 |
| - * @return the W3C propagation factory |
| 180 | + * A composite {@link Propagation}. |
195 | 181 | */
|
196 |
| - private static W3CPropagation w3c(BaggageManager baggageManager) { |
197 |
| - return (baggageManager != null) ? new W3CPropagation(baggageManager, Collections.emptyList()) |
198 |
| - : new W3CPropagation(); |
| 182 | + private static class CompositePropagation implements Propagation<String> { |
| 183 | + |
| 184 | + private final List<Propagation<String>> injectors; |
| 185 | + |
| 186 | + private final List<Propagation<String>> extractors; |
| 187 | + |
| 188 | + private final List<String> keys; |
| 189 | + |
| 190 | + CompositePropagation(PropagationFactories injectorFactories, PropagationFactories extractorFactories) { |
| 191 | + this.injectors = injectorFactories.get(); |
| 192 | + this.extractors = extractorFactories.get(); |
| 193 | + this.keys = Stream.concat(keys(this.injectors), keys(this.extractors)).distinct().toList(); |
| 194 | + } |
| 195 | + |
| 196 | + private Stream<String> keys(List<Propagation<String>> propagations) { |
| 197 | + return propagations.stream().flatMap((propagation) -> propagation.keys().stream()); |
| 198 | + } |
| 199 | + |
| 200 | + @Override |
| 201 | + public List<String> keys() { |
| 202 | + return this.keys; |
| 203 | + } |
| 204 | + |
| 205 | + @Override |
| 206 | + public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) { |
| 207 | + return (traceContext, request) -> this.injectors.stream() |
| 208 | + .map((propagation) -> propagation.injector(setter)) |
| 209 | + .forEach((injector) -> injector.inject(traceContext, request)); |
| 210 | + } |
| 211 | + |
| 212 | + @Override |
| 213 | + public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) { |
| 214 | + return (request) -> this.extractors.stream() |
| 215 | + .map((propagation) -> propagation.extractor(getter)) |
| 216 | + .map((extractor) -> extractor.extract(request)) |
| 217 | + .filter(Predicate.not(TraceContextOrSamplingFlags.EMPTY::equals)) |
| 218 | + .findFirst() |
| 219 | + .orElse(TraceContextOrSamplingFlags.EMPTY); |
| 220 | + } |
| 221 | + |
199 | 222 | }
|
200 | 223 |
|
201 | 224 | }
|
0 commit comments