From fb1e318acd625c35d899954a521ddb553663d022 Mon Sep 17 00:00:00 2001 From: tdanylchuk Date: Wed, 12 Dec 2018 16:44:12 +0200 Subject: [PATCH] sleuth extra propagation fields to tags feature. --- .../log/SleuthLogAutoConfiguration.java | 4 +- ...SleuthTagPropagationAutoConfiguration.java | 52 +++++++++ .../SleuthTagPropagationProperties.java | 60 +++++++++++ .../TagPropagationFinishedSpanHandler.java | 62 +++++++++++ .../main/resources/META-INF/spring.factories | 1 + ...thTagPropagationAutoConfigurationTest.java | 60 +++++++++++ ...TagPropagationFinishedSpanHandlerTest.java | 102 ++++++++++++++++++ 7 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfiguration.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationProperties.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandler.java create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfigurationTest.java create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandlerTest.java diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java index 258c39a8a..f27e44991 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/SleuthLogAutoConfiguration.java @@ -29,8 +29,8 @@ import org.springframework.context.annotation.Configuration; /** * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration - * Auto-configuration} enables a {@link Slf4jCurrentTraceContext} that prints tracing - * information in the logs. + * Auto-configuration} adds a {@link Slf4jScopeDecorator} that prints tracing information + * in the logs. *

* * @author Spencer Gibb diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfiguration.java new file mode 100644 index 000000000..d2fa079d9 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.propagation; + +import brave.handler.FinishedSpanHandler; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.sleuth.autoconfig.SleuthProperties; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Taras Danylchuk + * @since 2.1.0 + */ +@Configuration +@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true) +@AutoConfigureBefore(TraceAutoConfiguration.class) +public class SleuthTagPropagationAutoConfiguration { + + @Configuration + @ConditionalOnProperty(value = "spring.sleuth.propagation.tag.enabled", matchIfMissing = true) + @EnableConfigurationProperties(SleuthTagPropagationProperties.class) + protected static class TagPropagationConfiguration { + + @Bean + @ConditionalOnProperty(value = "spring.sleuth.propagation.tag.whitelisted-keys") + public FinishedSpanHandler finishedSpanHandler(SleuthProperties sleuthProperties, + SleuthTagPropagationProperties tagPropagationProperties) { + return new TagPropagationFinishedSpanHandler(sleuthProperties, + tagPropagationProperties); + } + + } + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationProperties.java new file mode 100644 index 000000000..46fec947b --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.propagation; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.ArrayList; +import java.util.List; + +/** + * Configuration properties of tag propagation. + * + * @author Taras Danylchuk + * @since 2.1.0 + */ +@ConfigurationProperties("spring.sleuth.propagation.tag") +public class SleuthTagPropagationProperties { + + /** + * Enables a {@link TagPropagationFinishedSpanHandler} that adds extra propagated + * fields to span tags. + */ + private boolean enabled = true; + + /** + * A list of keys to be put from extra propagation fields to span tags. + */ + private List whitelistedKeys = new ArrayList<>(); + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public List getWhitelistedKeys() { + return whitelistedKeys; + } + + public void setWhitelistedKeys(List whitelistedKeys) { + this.whitelistedKeys = whitelistedKeys; + } + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandler.java new file mode 100644 index 000000000..b550c4068 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.propagation; + +import brave.handler.FinishedSpanHandler; +import brave.handler.MutableSpan; +import brave.propagation.ExtraFieldPropagation; +import brave.propagation.TraceContext; +import org.springframework.cloud.sleuth.autoconfig.SleuthProperties; + +import java.util.AbstractMap; +import java.util.Collection; +import java.util.stream.Stream; + +import static java.util.Objects.nonNull; + +/** + * Finish span handler which adds extra propagation fields to span tags, so spans could be + * looked up by its baggage. + * + * @author Taras Danylchuk + * @since 2.1.0 + */ +public class TagPropagationFinishedSpanHandler extends FinishedSpanHandler { + + private final SleuthProperties sleuthProperties; + + private final SleuthTagPropagationProperties tagPropagationProperties; + + public TagPropagationFinishedSpanHandler(SleuthProperties sleuthProperties, + SleuthTagPropagationProperties tagPropagationProperties) { + this.sleuthProperties = sleuthProperties; + this.tagPropagationProperties = tagPropagationProperties; + } + + @Override + public boolean handle(TraceContext context, MutableSpan span) { + Stream.of(sleuthProperties.getBaggageKeys(), sleuthProperties.getPropagationKeys()) + .flatMap(Collection::stream) + .filter(key -> this.tagPropagationProperties.getWhitelistedKeys().contains(key)) + .map(baggageItemKey -> new AbstractMap.SimpleEntry<>(baggageItemKey, + ExtraFieldPropagation.get(context, baggageItemKey))) + .filter(entry -> nonNull(entry.getValue())) + .forEach(entry -> span.tag(entry.getKey(), entry.getValue())); + return true; + } + +} diff --git a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories index 2043bd2c5..c7061d641 100644 --- a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories @@ -3,6 +3,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.sleuth.annotation.SleuthAnnotationAutoConfiguration,\ org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration,\ org.springframework.cloud.sleuth.log.SleuthLogAutoConfiguration,\ +org.springframework.cloud.sleuth.propagation.SleuthTagPropagationAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.web.TraceHttpAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration,\ diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfigurationTest.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfigurationTest.java new file mode 100644 index 000000000..48f074b2c --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/SleuthTagPropagationAutoConfigurationTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.sleuth.propagation; + +import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class SleuthTagPropagationAutoConfigurationTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SleuthTagPropagationAutoConfiguration.class)); + + @Test + public void shouldNotCreateHandler() { + this.contextRunner + .run((context) -> { + assertThat(context).doesNotHaveBean(TagPropagationFinishedSpanHandler.class); + }); + } + + @Test + public void shouldNotCreateHandlerByDisablingIt() { + this.contextRunner + .withPropertyValues("spring.sleuth.propagation.tag.whitelisted-keys=some-key") + .withPropertyValues("spring.sleuth.propagation.tag.enabled=false") + .withUserConfiguration(TraceAutoConfiguration.class) + .run((context) -> { + assertThat(context).doesNotHaveBean(TagPropagationFinishedSpanHandler.class); + }); + } + + @Test + public void shouldCreateHandler() { + this.contextRunner + .withPropertyValues("spring.sleuth.propagation.tag.whitelisted-keys=some-key") + .withUserConfiguration(TraceAutoConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(TagPropagationFinishedSpanHandler.class); + }); + } + +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandlerTest.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandlerTest.java new file mode 100644 index 000000000..01428020b --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/propagation/TagPropagationFinishedSpanHandlerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.sleuth.propagation; + +import brave.ScopedSpan; +import brave.Tracer; +import brave.propagation.ExtraFieldPropagation; +import brave.propagation.TraceContext; +import brave.sampler.Sampler; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.sleuth.util.ArrayListSpanReporter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Taras Danylchuk + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { + "spring.sleuth.baggage-keys=my-baggage", + "spring.sleuth.propagation-keys=my-propagation,others-propagation", + "spring.sleuth.propagation.tag.whitelisted-keys=my-baggage,my-propagation"}, + classes = TagPropagationFinishedSpanHandlerTest.TestConfiguration.class) +public class TagPropagationFinishedSpanHandlerTest { + + private static final String BAGGAGE_KEY = "my-baggage"; + private static final String BAGGAGE_VALUE = "332323"; + + private static final String PROPAGATION_KEY = "my-propagation"; + private static final String PROPAGATION_VALUE = "332323"; + + @Autowired + private Tracer tracer; + + @Autowired + private ArrayListSpanReporter arrayListSpanReporter; + + private ScopedSpan span; + + @Before + public void setUp() { + arrayListSpanReporter.clear(); + span = tracer.startScopedSpan("my-scoped-span"); + TraceContext context = span.context(); + ExtraFieldPropagation.set(context, BAGGAGE_KEY, BAGGAGE_VALUE); + ExtraFieldPropagation.set(context, PROPAGATION_KEY, PROPAGATION_VALUE); + ExtraFieldPropagation.set(context, "others-propagation", "some value"); + } + + @Test + public void shouldReportWithBaggageInTags() { + span.finish(); + + List spans = arrayListSpanReporter.getSpans(); + assertThat(spans).hasSize(1); + Map tags = spans.get(0).tags(); + assertThat(tags).hasSize(2); + assertThat(tags).containsEntry(BAGGAGE_KEY, BAGGAGE_VALUE); + assertThat(tags).containsEntry(PROPAGATION_KEY, PROPAGATION_VALUE); + } + + @Configuration + @EnableAutoConfiguration + public static class TestConfiguration { + + @Bean + public ArrayListSpanReporter arrayListSpanReporter() { + return new ArrayListSpanReporter(); + } + + @Bean + public Sampler alwaysSampler() { + return Sampler.ALWAYS_SAMPLE; + } + + } + +} \ No newline at end of file