diff --git a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilter.java b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilter.java index bd3e5a21..b2413620 100644 --- a/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilter.java +++ b/custom/shared/src/main/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilter.java @@ -16,29 +16,36 @@ package com.solarwinds.opentelemetry.extensions; -import static io.opentelemetry.api.common.AttributeKey.stringKey; - import com.solarwinds.joboe.config.ConfigManager; import com.solarwinds.joboe.config.ConfigProperty; +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.trace.ReadableSpan; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; public class SpanStacktraceFilter implements Predicate { - private static final Set filterAttributes = new HashSet<>(); + private Set filterAttributes = new HashSet<>(); @Override public boolean test(ReadableSpan readableSpan) { if (filterAttributes.isEmpty()) { - filterAttributes.add("db.system"); Set configuredFilterAttributes = ConfigManager.getConfigOptional( - ConfigProperty.AGENT_SPAN_STACKTRACE_FILTERS, filterAttributes); - filterAttributes.addAll(configuredFilterAttributes); + ConfigProperty.AGENT_SPAN_STACKTRACE_FILTERS, Collections.singleton("db.system")); + + Set effectiveFilterAttributes = new HashSet<>(configuredFilterAttributes); + effectiveFilterAttributes.add("db.system"); + filterAttributes = effectiveFilterAttributes; } - return filterAttributes.stream() - .anyMatch(attr -> readableSpan.getAttribute(stringKey(attr)) != null); + Set attributes = + readableSpan.getAttributes().asMap().keySet().stream() + .map(AttributeKey::getKey) + .collect(Collectors.toSet()); + + return filterAttributes.stream().anyMatch(attributes::contains); } } diff --git a/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilterTest.java b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilterTest.java index 80628c95..b51760b6 100644 --- a/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilterTest.java +++ b/custom/shared/src/test/java/com/solarwinds/opentelemetry/extensions/SpanStacktraceFilterTest.java @@ -16,32 +16,102 @@ package com.solarwinds.opentelemetry.extensions; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.solarwinds.joboe.config.ConfigManager; +import com.solarwinds.joboe.config.ConfigProperty; +import com.solarwinds.joboe.config.InvalidConfigException; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.trace.ReadableSpan; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -@ExtendWith(MockitoExtension.class) class SpanStacktraceFilterTest { - @InjectMocks private SpanStacktraceFilter tested; + private SpanStacktraceFilter tested; - @Mock private ReadableSpan readableSpanMock; + @BeforeEach + void setUp() { + tested = new SpanStacktraceFilter(); + } + + @AfterEach + void tearDown() { + ConfigManager.reset(); + } + + @Test + void returnTrueWhenSpanHasMultipleMatchingAttributes() { + ReadableSpan span = + createSpanWithAttributes( + Attributes.builder().put("db.system", "postgresql").put("http.method", "GET").build()); + assertTrue(tested.test(span)); + } + + @Test + void returnFalseWhenSpanHasNoAttributes() { + ReadableSpan span = createSpanWithAttributes(Attributes.empty()); + assertFalse(tested.test(span)); + } + + @Test + void returnTrueWhenSpanHasCustomConfiguredLongAttribute() throws InvalidConfigException { + Set customFilters = new HashSet<>(); + customFilters.add("process.id"); + ConfigManager.setConfig(ConfigProperty.AGENT_SPAN_STACKTRACE_FILTERS, customFilters); + + SpanStacktraceFilter filter = new SpanStacktraceFilter(); + ReadableSpan span = + createSpanWithAttributes(Attributes.builder().put("process.id", 450).build()); + + assertTrue(filter.test(span)); + } @Test - void returnTrueWhenAttributeHasValue() { - when(readableSpanMock.getAttribute(any())).thenReturn("test-value"); - assertTrue(tested.test(readableSpanMock)); + void returnTrueWhenSpanHasCustomConfiguredStringArrayAttribute() throws InvalidConfigException { + Set customFilters = new HashSet<>(); + customFilters.add("messaging.systems"); + ConfigManager.setConfig(ConfigProperty.AGENT_SPAN_STACKTRACE_FILTERS, customFilters); + + SpanStacktraceFilter filter = new SpanStacktraceFilter(); + ReadableSpan spanWithMessaging = + createSpanWithAttributes( + Attributes.builder() + .put( + AttributeKey.stringArrayKey("messaging.systems"), + Arrays.asList("postgresql", "rabbitmq")) + .build()); + + assertTrue(filter.test(spanWithMessaging)); } @Test - void returnFalseWhenAttributeHasNoValue() { - assertFalse(tested.test(readableSpanMock)); + void returnTrueWhenSpanHasCustomConfiguredLongArrayAttribute() throws InvalidConfigException { + Set customFilters = new HashSet<>(); + customFilters.add("process.ids"); + ConfigManager.setConfig(ConfigProperty.AGENT_SPAN_STACKTRACE_FILTERS, customFilters); + + SpanStacktraceFilter filter = new SpanStacktraceFilter(); + ReadableSpan span = + createSpanWithAttributes( + Attributes.builder() + .put(AttributeKey.longArrayKey("process.ids"), Arrays.asList(200L, 300L)) + .build()); + + assertTrue(filter.test(span)); + } + + private ReadableSpan createSpanWithAttributes(Attributes attributes) { + ReadableSpan span = mock(ReadableSpan.class); + when(span.getAttributes()).thenReturn(attributes); + return span; } }