Added spanHandler that skips span name via patterns; fixes gh-1720
This commit is contained in:
@@ -381,12 +381,12 @@ anything not already done by Sleuth with auto-configuration or properties.
|
||||
If you define one of the following as a `Bean`, Sleuth will invoke it to
|
||||
customize behaviour:
|
||||
|
||||
* RpcTracingCustomizer - for RPC tagging and sampling policy
|
||||
* HttpTracingCustomizer - for HTTP tagging and sampling policy
|
||||
* MessagingTracingCustomizer - for messaging tagging and sampling policy
|
||||
* CurrentTraceContextCustomizer - to integrate decorators such as correlation.
|
||||
* BaggagePropagationCustomizer - for propagating baggage fields in process and over headers
|
||||
* CorrelationScopeDecoratorCustomizer - for scope decorations such as MDC (logging) field correlation
|
||||
* `RpcTracingCustomizer` - for RPC tagging and sampling policy
|
||||
* `HttpTracingCustomizer` - for HTTP tagging and sampling policy
|
||||
* `MessagingTracingCustomizer` - for messaging tagging and sampling policy
|
||||
* `CurrentTraceContextCustomizer` - to integrate decorators such as correlation.
|
||||
* `BaggagePropagationCustomize`r - for propagating baggage fields in process and over headers
|
||||
* `CorrelationScopeDecoratorCustomizer` - for scope decorations such as MDC (logging) field correlation
|
||||
|
||||
=== HTTP
|
||||
|
||||
@@ -540,6 +540,8 @@ include::{project-root}//spring-cloud-sleuth-core/src/test/java/org/springframew
|
||||
|
||||
The preceding example results in changing the name of the reported span to `foo bar`, just before it gets reported (for example, to Zipkin).
|
||||
|
||||
Sleuth registers a `SpanHandler` bean that can automatically skip reporting spans of given name patterns. The property `spring.sleuth.span-handler.span-name-patterns-to-skip` contains the default skip patterns for span names. The property `spring.sleuth.span-handler.additional-span-name-patterns-to-skip` will append the provided span name patterns to the existing ones. In order to disable this functionality just set `spring.sleuth.span-handler.enabled` to `false`.
|
||||
|
||||
=== Host Locator
|
||||
|
||||
IMPORTANT: This section is about defining *host* from service discovery.
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.autoconfig;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
@@ -38,6 +42,11 @@ class SleuthProperties {
|
||||
*/
|
||||
private boolean supportsJoin = true;
|
||||
|
||||
/**
|
||||
* Properties related to handling of spans.
|
||||
*/
|
||||
private SpanHandler spanHandler = new SpanHandler();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
@@ -62,4 +71,62 @@ class SleuthProperties {
|
||||
this.supportsJoin = supportsJoin;
|
||||
}
|
||||
|
||||
public SpanHandler getSpanHandler() {
|
||||
return this.spanHandler;
|
||||
}
|
||||
|
||||
public void setSpanHandler(SpanHandler spanHandler) {
|
||||
this.spanHandler = spanHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties related to handling of spans.
|
||||
*/
|
||||
public static class SpanHandler {
|
||||
|
||||
/**
|
||||
* Will turn on the default Sleuth handler mechanism. Might ignore exporting of
|
||||
* certain spans;
|
||||
*/
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* List of span names to ignore. They will not be sent to external systems.
|
||||
*/
|
||||
private List<String> spanNamePatternsToSkip = Arrays
|
||||
.asList("^catalogWatchTaskScheduler$");
|
||||
|
||||
/**
|
||||
* Additional list of span names to ignore. Will be appended to
|
||||
* {@link #spanNamePatternsToSkip}.
|
||||
*/
|
||||
private List<String> additionalSpanNamePatternsToIgnore = Collections.emptyList();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getSpanNamePatternsToSkip() {
|
||||
return this.spanNamePatternsToSkip;
|
||||
}
|
||||
|
||||
public void setSpanNamePatternsToSkip(List<String> spanNamePatternsToSkip) {
|
||||
this.spanNamePatternsToSkip = spanNamePatternsToSkip;
|
||||
}
|
||||
|
||||
public List<String> getAdditionalSpanNamePatternsToIgnore() {
|
||||
return this.additionalSpanNamePatternsToIgnore;
|
||||
}
|
||||
|
||||
public void setAdditionalSpanNamePatternsToIgnore(
|
||||
List<String> additionalSpanNamePatternsToIgnore) {
|
||||
this.additionalSpanNamePatternsToIgnore = additionalSpanNamePatternsToIgnore;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.autoconfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.handler.SpanHandler;
|
||||
import brave.propagation.TraceContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link SpanHandler} that ignores spans via names.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class SpanIgnoringSpanHandler extends SpanHandler {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SpanIgnoringSpanHandler.class);
|
||||
|
||||
private final SleuthProperties sleuthProperties;
|
||||
|
||||
static final Map<String, Pattern> cache = new ConcurrentHashMap<>();
|
||||
|
||||
SpanIgnoringSpanHandler(SleuthProperties sleuthProperties) {
|
||||
this.sleuthProperties = sleuthProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean end(TraceContext context, MutableSpan span, Cause cause) {
|
||||
if (cause != Cause.FINISHED) {
|
||||
return true;
|
||||
}
|
||||
List<Pattern> spanNamesToIgnore = spanNamesToIgnore();
|
||||
String name = span.name();
|
||||
if (StringUtils.hasText(name)
|
||||
&& spanNamesToIgnore.stream().anyMatch(p -> p.matcher(name).matches())) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will ignore a span with name [" + name + "]");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.end(context, span, cause);
|
||||
}
|
||||
|
||||
private List<Pattern> spanNamesToIgnore() {
|
||||
return spanNames().stream()
|
||||
.map(regex -> cache.computeIfAbsent(regex, Pattern::compile))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> spanNames() {
|
||||
List<String> spanNamesToIgnore = new ArrayList<>(
|
||||
this.sleuthProperties.getSpanHandler().getSpanNamePatternsToSkip());
|
||||
spanNamesToIgnore.addAll(this.sleuthProperties.getSpanHandler()
|
||||
.getAdditionalSpanNamePatternsToIgnore());
|
||||
return spanNamesToIgnore;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -142,4 +142,10 @@ public class TraceAutoConfiguration {
|
||||
return CurrentSpanCustomizer.create(tracing);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.sleuth.span-handler.enabled", matchIfMissing = true)
|
||||
SpanHandler spanIgnoringSpanHandler(SleuthProperties sleuthProperties) {
|
||||
return new SpanIgnoringSpanHandler(sleuthProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.autoconfig;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import brave.handler.MutableSpan;
|
||||
import brave.handler.SpanHandler;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
class SpanIgnoringSpanHandlerTests {
|
||||
|
||||
@Test
|
||||
void should_handle_span_when_not_yet_finished() {
|
||||
SpanIgnoringSpanHandler handler = new SpanIgnoringSpanHandler(new SleuthProperties());
|
||||
|
||||
then(handler.end(null, null, SpanHandler.Cause.ABANDONED)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_handle_span_when_name_null() {
|
||||
SpanIgnoringSpanHandler handler = new SpanIgnoringSpanHandler(new SleuthProperties());
|
||||
|
||||
then(handler.end(null, new MutableSpan(), SpanHandler.Cause.FINISHED)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_handle_span_when_not_present_in_main_list_of_spans_to_skip() {
|
||||
SpanIgnoringSpanHandler handler = new SpanIgnoringSpanHandler(new SleuthProperties());
|
||||
|
||||
then(handler.end(null, namedSpan(), SpanHandler.Cause.FINISHED)).isTrue();
|
||||
}
|
||||
|
||||
private MutableSpan namedSpan() {
|
||||
MutableSpan span = new MutableSpan();
|
||||
span.name("someName");
|
||||
return span;
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_not_handle_span_when_present_in_main_list_of_spans_to_skip() {
|
||||
SleuthProperties sleuthProperties = new SleuthProperties();
|
||||
sleuthProperties.getSpanHandler().setSpanNamePatternsToSkip(Collections.singletonList("someName"));
|
||||
SpanIgnoringSpanHandler handler = new SpanIgnoringSpanHandler(sleuthProperties);
|
||||
|
||||
then(handler.end(null, namedSpan(), SpanHandler.Cause.FINISHED)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_not_handle_span_when_present_in_additional_list_of_spans_to_skip() {
|
||||
SleuthProperties sleuthProperties = sleuthPropertiesWithAdditionalEntries();
|
||||
SpanIgnoringSpanHandler handler = new SpanIgnoringSpanHandler(sleuthProperties);
|
||||
|
||||
then(handler.end(null, namedSpan(), SpanHandler.Cause.FINISHED)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_use_cached_entry_for_same_patterns() {
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("someOtherName")));
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("someOtherName")));
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("someOtherName")));
|
||||
|
||||
then(SpanIgnoringSpanHandler.cache).containsKey("someOtherName");
|
||||
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("a")));
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("b")));
|
||||
end(handler(sleuthPropertiesWithAdditionalEntries("c")));
|
||||
|
||||
then(SpanIgnoringSpanHandler.cache).containsKey("someOtherName").containsKey("a").containsKey("b")
|
||||
.containsKey("c");
|
||||
}
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void should_not_register_span_handler_when_property_passed() {
|
||||
this.contextRunner.withPropertyValues("spring.sleuth.span-handler.enabled=false")
|
||||
.run((context) -> BDDAssertions.thenThrownBy(() -> context.getBean(SpanIgnoringSpanHandler.class))
|
||||
.isInstanceOf(NoSuchBeanDefinitionException.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_register_span_handler_by_default() {
|
||||
this.contextRunner.run((context) -> context.getBean(SpanIgnoringSpanHandler.class));
|
||||
}
|
||||
|
||||
private SleuthProperties sleuthPropertiesWithAdditionalEntries() {
|
||||
return sleuthPropertiesWithAdditionalEntries("someName");
|
||||
}
|
||||
|
||||
private SleuthProperties sleuthPropertiesWithAdditionalEntries(String name) {
|
||||
SleuthProperties sleuthProperties = new SleuthProperties();
|
||||
sleuthProperties.getSpanHandler().setAdditionalSpanNamePatternsToIgnore(Collections.singletonList(name));
|
||||
return sleuthProperties;
|
||||
}
|
||||
|
||||
private void end(SpanIgnoringSpanHandler handler) {
|
||||
handler.end(null, namedSpan(), SpanHandler.Cause.FINISHED);
|
||||
}
|
||||
|
||||
private SpanIgnoringSpanHandler handler(SleuthProperties sleuthProperties) {
|
||||
return new SpanIgnoringSpanHandler(sleuthProperties);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user