From 655f7a50a910103fdfadbff76b67b503eb9c4bb2 Mon Sep 17 00:00:00 2001 From: Simon Gurcke Date: Thu, 29 Jan 2026 22:50:32 +1000 Subject: [PATCH 1/2] Remove span collector --- README.md | 3 +- pom.xml | 5 - .../io/apitally/common/ApitallyClient.java | 3 - .../io/apitally/common/RequestLogger.java | 17 +- .../io/apitally/common/SpanCollector.java | 178 ------------------ .../apitally/common/dto/RequestLogItem.java | 18 +- .../spring/ApitallyAutoConfiguration.java | 4 - .../io/apitally/spring/ApitallyFilter.java | 21 +-- .../spring/ApitallySpanCollector.java | 79 -------- .../apitally/common/ApitallyClientTest.java | 2 +- .../io/apitally/common/RequestLoggerTest.java | 32 +--- .../io/apitally/common/SpanCollectorTest.java | 164 ---------------- .../apitally/spring/ApitallyFilterTest.java | 8 - .../apitally/spring/app/TestController.java | 7 - 14 files changed, 15 insertions(+), 526 deletions(-) delete mode 100644 src/main/java/io/apitally/common/SpanCollector.java delete mode 100644 src/main/java/io/apitally/spring/ApitallySpanCollector.java delete mode 100644 src/test/java/io/apitally/common/SpanCollectorTest.java diff --git a/README.md b/README.md index 5f7a769..3609f7d 100644 --- a/README.md +++ b/README.md @@ -91,14 +91,13 @@ apitally: client-id: "your-client-id" env: "dev" # or "prod" etc. - # Optional: configure request logging and tracing + # Optional: configure request logging request-logging: enabled: true request-headers-included: true request-body-included: true response-body-included: true log-capture-enabled: true - tracing-enabled: true ``` For further instructions, see our diff --git a/pom.xml b/pom.xml index 86cd6a8..ddeeb04 100644 --- a/pom.xml +++ b/pom.xml @@ -54,11 +54,6 @@ oshi-core 6.9.2 - - io.opentelemetry - opentelemetry-sdk - 1.58.0 - com.github.spotbugs spotbugs-annotations diff --git a/src/main/java/io/apitally/common/ApitallyClient.java b/src/main/java/io/apitally/common/ApitallyClient.java index 7d1acdd..6ca0fdd 100644 --- a/src/main/java/io/apitally/common/ApitallyClient.java +++ b/src/main/java/io/apitally/common/ApitallyClient.java @@ -67,7 +67,6 @@ public enum HubRequestStatus { public final RequestCounter requestCounter; public final RequestLogger requestLogger; - public final SpanCollector spanCollector; public final ValidationErrorCounter validationErrorCounter; public final ServerErrorCounter serverErrorCounter; public final ConsumerRegistry consumerRegistry; @@ -84,8 +83,6 @@ public ApitallyClient(String clientId, String env, RequestLoggingConfig requestL this.requestCounter = new RequestCounter(); this.requestLogger = new RequestLogger(requestLoggingConfig); - this.spanCollector = - new SpanCollector(requestLoggingConfig.isEnabled() && requestLoggingConfig.isTracingEnabled()); this.validationErrorCounter = new ValidationErrorCounter(); this.serverErrorCounter = new ServerErrorCounter(); this.consumerRegistry = new ConsumerRegistry(); diff --git a/src/main/java/io/apitally/common/RequestLogger.java b/src/main/java/io/apitally/common/RequestLogger.java index c415ec3..34ac4ea 100644 --- a/src/main/java/io/apitally/common/RequestLogger.java +++ b/src/main/java/io/apitally/common/RequestLogger.java @@ -131,9 +131,7 @@ public void logRequest( Request request, Response response, Exception exception, - List logs, - List spans, - String traceId) { + List logs) { if (!enabled || suspendUntil != null && suspendUntil > System.currentTimeMillis()) { return; } @@ -171,12 +169,7 @@ public void logRequest( logs = null; } - if (!config.isTracingEnabled()) { - spans = null; - traceId = null; - } - - RequestLogItem item = new RequestLogItem(request, response, exceptionDto, logs, spans, traceId); + RequestLogItem item = new RequestLogItem(request, response, exceptionDto, logs); pendingWrites.add(item); if (pendingWrites.size() > MAX_PENDING_WRITES) { @@ -284,12 +277,6 @@ public void writeToFile() throws IOException { if (item.getLogs() != null && !item.getLogs().isEmpty()) { itemNode.set("logs", objectMapper.valueToTree(item.getLogs())); } - if (item.getSpans() != null && !item.getSpans().isEmpty()) { - itemNode.set("spans", objectMapper.valueToTree(item.getSpans())); - } - if (item.getTraceId() != null && !item.getTraceId().isEmpty()) { - itemNode.put("trace_id", item.getTraceId()); - } String serializedItem = objectMapper.writeValueAsString(itemNode); currentFile.writeLine(serializedItem.getBytes(StandardCharsets.UTF_8)); diff --git a/src/main/java/io/apitally/common/SpanCollector.java b/src/main/java/io/apitally/common/SpanCollector.java deleted file mode 100644 index af0dd21..0000000 --- a/src/main/java/io/apitally/common/SpanCollector.java +++ /dev/null @@ -1,178 +0,0 @@ -package io.apitally.common; - -import io.apitally.common.dto.SpanData; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import io.opentelemetry.sdk.trace.ReadableSpan; -import io.opentelemetry.sdk.trace.SpanProcessor; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class SpanCollector implements SpanProcessor { - private final boolean enabled; - private volatile Tracer tracer; - private final Map> includedSpanIds = new ConcurrentHashMap<>(); - private final Map> collectedSpans = new ConcurrentHashMap<>(); - - public SpanCollector(boolean enabled) { - this.enabled = enabled; - } - - public void setTracer(Tracer tracer) { - this.tracer = tracer; - } - - public SpanHandle startCollection() { - if (!enabled || tracer == null) { - return null; - } - - Span span = tracer.spanBuilder("root").setSpanKind(SpanKind.INTERNAL).startSpan(); - Scope scope = Context.current().with(span).makeCurrent(); - SpanContext spanContext = span.getSpanContext(); - String traceId = spanContext.getTraceId(); - - Set spanIds = ConcurrentHashMap.newKeySet(); - spanIds.add(spanContext.getSpanId()); - includedSpanIds.put(traceId, spanIds); - collectedSpans.put(traceId, new ConcurrentLinkedQueue<>()); - - return new SpanHandle(traceId, span, scope, this); - } - - List getAndClearSpans(String traceId) { - if (traceId == null) { - return null; - } - - includedSpanIds.remove(traceId); - ConcurrentLinkedQueue spans = collectedSpans.remove(traceId); - return spans != null ? new ArrayList<>(spans) : null; - } - - @Override - public void onStart(Context parentContext, ReadWriteSpan span) { - if (!enabled) { - return; - } - - SpanContext spanContext = span.getSpanContext(); - String traceId = spanContext.getTraceId(); - String spanId = spanContext.getSpanId(); - - Set included = includedSpanIds.get(traceId); - if (included == null) { - return; - } - - SpanContext parentSpanContext = span.getParentSpanContext(); - if (parentSpanContext.isValid() && included.contains(parentSpanContext.getSpanId())) { - included.add(spanId); - } - } - - @Override - public boolean isStartRequired() { - return enabled; - } - - @Override - public void onEnd(ReadableSpan span) { - if (!enabled) { - return; - } - - SpanContext spanContext = span.getSpanContext(); - String traceId = spanContext.getTraceId(); - String spanId = spanContext.getSpanId(); - - Set included = includedSpanIds.get(traceId); - if (included == null || !included.contains(spanId)) { - return; - } - - SpanData data = serializeSpan(span); - ConcurrentLinkedQueue spans = collectedSpans.get(traceId); - if (spans != null) { - spans.add(data); - } - } - - @Override - public boolean isEndRequired() { - return enabled; - } - - private SpanData serializeSpan(ReadableSpan span) { - io.opentelemetry.sdk.trace.data.SpanData spanData = span.toSpanData(); - SpanContext spanContext = spanData.getSpanContext(); - SpanContext parentSpanContext = spanData.getParentSpanContext(); - - String parentSpanId = parentSpanContext.isValid() ? parentSpanContext.getSpanId() : null; - String status = spanData.getStatus().getStatusCode() != StatusCode.UNSET - ? spanData.getStatus().getStatusCode().name() - : null; - - Map attributes = null; - if (!spanData.getAttributes().isEmpty()) { - Map attrMap = new HashMap<>(); - spanData.getAttributes().forEach((key, value) -> attrMap.put(key.getKey(), value)); - attributes = attrMap; - } - - return new SpanData( - spanContext.getSpanId(), - parentSpanId, - spanData.getName(), - spanData.getKind().name(), - spanData.getStartEpochNanos(), - spanData.getEndEpochNanos(), - status, - attributes); - } - - public static class SpanHandle { - private final String traceId; - private final Span span; - private final Scope scope; - private final SpanCollector collector; - - SpanHandle(String traceId, Span span, Scope scope, SpanCollector collector) { - this.traceId = traceId; - this.span = span; - this.scope = scope; - this.collector = collector; - } - - public String getTraceId() { - return traceId; - } - - public void setName(String name) { - span.updateName(name); - } - - public List end() { - scope.close(); - span.end(); - return collector.getAndClearSpans(traceId); - } - } - - void resetForTest() { - this.tracer = null; - this.includedSpanIds.clear(); - this.collectedSpans.clear(); - } -} diff --git a/src/main/java/io/apitally/common/dto/RequestLogItem.java b/src/main/java/io/apitally/common/dto/RequestLogItem.java index 5c4dec7..4f54f10 100644 --- a/src/main/java/io/apitally/common/dto/RequestLogItem.java +++ b/src/main/java/io/apitally/common/dto/RequestLogItem.java @@ -10,23 +10,17 @@ public class RequestLogItem extends BaseDto { private final Response response; private final ExceptionDto exception; private final List logs; - private final List spans; - private final String traceId; public RequestLogItem( Request request, Response response, ExceptionDto exception, - List logs, - List spans, - String traceId) { + List logs) { this.uuid = UUID.randomUUID().toString(); this.request = request; this.response = response; this.exception = exception; this.logs = logs; - this.spans = spans; - this.traceId = traceId; } @JsonProperty("uuid") @@ -53,14 +47,4 @@ public ExceptionDto getException() { public List getLogs() { return logs; } - - @JsonProperty("spans") - public List getSpans() { - return spans; - } - - @JsonProperty("trace_id") - public String getTraceId() { - return traceId; - } } diff --git a/src/main/java/io/apitally/spring/ApitallyAutoConfiguration.java b/src/main/java/io/apitally/spring/ApitallyAutoConfiguration.java index b9eff9a..d688109 100644 --- a/src/main/java/io/apitally/spring/ApitallyAutoConfiguration.java +++ b/src/main/java/io/apitally/spring/ApitallyAutoConfiguration.java @@ -29,10 +29,6 @@ public ApitallyClient apitallyClient( && properties.getRequestLogging().isLogCaptureEnabled()) { LogAppender.register(); } - if (properties.getRequestLogging().isEnabled() - && properties.getRequestLogging().isTracingEnabled()) { - ApitallySpanCollector.getInstance().setDelegate(client.spanCollector); - } return client; } diff --git a/src/main/java/io/apitally/spring/ApitallyFilter.java b/src/main/java/io/apitally/spring/ApitallyFilter.java index 5c1b860..267d217 100644 --- a/src/main/java/io/apitally/spring/ApitallyFilter.java +++ b/src/main/java/io/apitally/spring/ApitallyFilter.java @@ -5,7 +5,6 @@ import io.apitally.common.LogAppender; import io.apitally.common.RequestLogger; import io.apitally.common.RequestLoggingConfig; -import io.apitally.common.SpanCollector; import io.apitally.common.dto.Consumer; import io.apitally.common.dto.Header; import io.apitally.common.dto.LogRecord; @@ -82,8 +81,6 @@ protected void doFilterInternal( LogAppender.startCapture(); } - final SpanCollector.SpanHandle spanHandle = shouldCaptureSpans ? client.spanCollector.startCollection() : null; - try { filterChain.doFilter( cachingRequest != null ? cachingRequest : request, @@ -96,20 +93,6 @@ protected void doFilterInternal( final long responseTimeInMillis = System.currentTimeMillis() - startTime; final String path = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); - // End span collection and get spans - List spans = null; - String traceId = null; - if (spanHandle != null) { - Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE); - if (handler instanceof HandlerMethod handlerMethod) { - String controllerName = handlerMethod.getBeanType().getSimpleName(); - String methodName = handlerMethod.getMethod().getName(); - spanHandle.setName(controllerName + "." + methodName); - } - spans = spanHandle.end(); - traceId = spanHandle.getTraceId(); - } - // End log capture and get logs final List capturedLogs = shouldCaptureLogs ? LogAppender.endCapture() : null; @@ -180,9 +163,7 @@ protected void doFilterInternal( responseSize, responseBody), exception, - capturedLogs, - spans, - traceId); + capturedLogs); } // Add validation error to counter diff --git a/src/main/java/io/apitally/spring/ApitallySpanCollector.java b/src/main/java/io/apitally/spring/ApitallySpanCollector.java deleted file mode 100644 index 7cf948e..0000000 --- a/src/main/java/io/apitally/spring/ApitallySpanCollector.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.apitally.spring; - -import io.apitally.common.SpanCollector; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import io.opentelemetry.sdk.trace.ReadableSpan; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.SpanProcessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ApitallySpanCollector implements SpanProcessor { - private static final Logger logger = LoggerFactory.getLogger(ApitallySpanCollector.class); - private static final ApitallySpanCollector INSTANCE = new ApitallySpanCollector(); - private volatile SpanCollector delegate; - - public static ApitallySpanCollector getInstance() { - return INSTANCE; - } - - private ApitallySpanCollector() {} - - public void setDelegate(SpanCollector spanCollector) { - this.delegate = spanCollector; - if (spanCollector != null) { - initializeTracer(spanCollector); - } - } - - private void initializeTracer(SpanCollector spanCollector) { - try { - SdkTracerProvider provider = - SdkTracerProvider.builder().addSpanProcessor(this).build(); - OpenTelemetrySdk sdk = - OpenTelemetrySdk.builder().setTracerProvider(provider).build(); - Tracer tracer; - try { - GlobalOpenTelemetry.set(sdk); - tracer = sdk.getTracer("apitally"); - } catch (IllegalStateException e) { - tracer = GlobalOpenTelemetry.getTracer("apitally"); - } - spanCollector.setTracer(tracer); - } catch (Exception e) { - logger.warn("Failed to setup OpenTelemetry tracer", e); - } - } - - @Override - public void onStart(Context parentContext, ReadWriteSpan span) { - if (delegate != null) { - delegate.onStart(parentContext, span); - } - } - - @Override - public boolean isStartRequired() { - return delegate != null && delegate.isStartRequired(); - } - - @Override - public void onEnd(ReadableSpan span) { - if (delegate != null) { - delegate.onEnd(span); - } - } - - @Override - public boolean isEndRequired() { - return delegate != null && delegate.isEndRequired(); - } - - public SpanCollector.SpanHandle startCollection() { - return delegate != null ? delegate.startCollection() : null; - } -} diff --git a/src/test/java/io/apitally/common/ApitallyClientTest.java b/src/test/java/io/apitally/common/ApitallyClientTest.java index e6b93b6..597ee66 100644 --- a/src/test/java/io/apitally/common/ApitallyClientTest.java +++ b/src/test/java/io/apitally/common/ApitallyClientTest.java @@ -60,7 +60,7 @@ void testSync() { 0L, new byte[0]); Response response = new Response(200, 0.123, responseHeaders, 13L, "{\"items\": []}".getBytes()); - client.requestLogger.logRequest(request, response, null, null, null, null); + client.requestLogger.logRequest(request, response, null, null); client.requestLogger.maintain(); List paths = Arrays.asList(new Path("GET", "/items")); diff --git a/src/test/java/io/apitally/common/RequestLoggerTest.java b/src/test/java/io/apitally/common/RequestLoggerTest.java index 8eee9b0..03fbda8 100644 --- a/src/test/java/io/apitally/common/RequestLoggerTest.java +++ b/src/test/java/io/apitally/common/RequestLoggerTest.java @@ -65,12 +65,7 @@ void testEndToEnd() { Exception exception = new Exception("test"); List logs = new ArrayList<>(); logs.add(new LogRecord(System.currentTimeMillis() / 1000.0, "test.Logger", "INFO", "Test log message")); - List spans = new ArrayList<>(); - spans.add(new SpanData("a1b2c3d4e5f6a7b8", null, "root", "INTERNAL", 1000000L, 2000000L, null, null)); - spans.add(new SpanData( - "b2c3d4e5f6a7b8c9", "a1b2c3d4e5f6a7b8", "child", "INTERNAL", 1100000L, 1900000L, "OK", null)); - String traceId = "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"; - requestLogger.logRequest(request, response, exception, logs, spans, traceId); + requestLogger.logRequest(request, response, exception, logs); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); @@ -112,15 +107,6 @@ void testEndToEnd() { assertEquals("INFO", logsNode.get(0).get("level").asText()); assertEquals("Test log message", logsNode.get(0).get("message").asText()); - assertEquals( - "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", jsonNode.get("trace_id").asText()); - JsonNode spansNode = jsonNode.get("spans"); - assertTrue(spansNode.isArray()); - assertEquals(2, spansNode.size()); - assertEquals("root", spansNode.get(0).get("name").asText()); - assertEquals("child", spansNode.get(1).get("name").asText()); - assertEquals("a1b2c3d4e5f6a7b8", spansNode.get(1).get("parent_span_id").asText()); - requestLogger.clear(); items = getLoggedItems(requestLogger); @@ -154,7 +140,7 @@ void testExcludeBasedOnOptions() { "{\"key\": \"value\"}".getBytes()); Response response = new Response(200, 0.123, responseHeaders, 16L, "{\"key\": \"value\"}".getBytes()); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); @@ -187,7 +173,7 @@ public boolean shouldExclude(Request request, Response response) { new byte[0]); Response response = new Response(200, 0.123, new Header[0], 13L, "{\"items\": []}".getBytes()); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(0, items.length); @@ -206,7 +192,7 @@ void testExcludeBasedOnPath() { new byte[0]); Response response = new Response(200, 0.123, new Header[0], 17L, "{\"healthy\": true}".getBytes()); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(0, items.length); @@ -221,7 +207,7 @@ void testExcludeBasedOnUserAgent() { System.currentTimeMillis() / 1000.0, null, "GET", "/", "http://test/", requestHeaders, 0L, new byte[0]); Response response = new Response(200, 0, new Header[0], 0L, new byte[0]); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(0, items.length); @@ -250,7 +236,7 @@ void testMaskHeaders() { new byte[0]); Response response = new Response(200, 0, new Header[0], 0L, new byte[0]); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); @@ -285,7 +271,7 @@ void testMaskQueryParams() { new byte[0]); Response response = new Response(200, 0, new Header[0], 0L, new byte[0]); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); @@ -334,7 +320,7 @@ public byte[] maskResponseBody(Request request, Response response) { Response response = new Response( 200, 0, new Header[] {new Header("Content-Type", "application/json")}, 4L, "test".getBytes()); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); @@ -379,7 +365,7 @@ void testMaskBodyFields() { (long) responseBodyJson.getBytes().length, responseBodyJson.getBytes()); - requestLogger.logRequest(request, response, null, null, null, null); + requestLogger.logRequest(request, response, null, null); JsonNode[] items = getLoggedItems(requestLogger); assertEquals(1, items.length); diff --git a/src/test/java/io/apitally/common/SpanCollectorTest.java b/src/test/java/io/apitally/common/SpanCollectorTest.java deleted file mode 100644 index c49ab2a..0000000 --- a/src/test/java/io/apitally/common/SpanCollectorTest.java +++ /dev/null @@ -1,164 +0,0 @@ -package io.apitally.common; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import io.apitally.common.dto.SpanData; -import io.apitally.spring.ApitallySpanCollector; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.api.trace.Tracer; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class SpanCollectorTest { - - private SpanCollector collector; - - @BeforeEach - void setUp() { - GlobalOpenTelemetry.resetForTest(); - ApitallySpanCollector.getInstance().setDelegate(null); - } - - @AfterEach - void tearDown() { - if (collector != null) { - collector.resetForTest(); - } - ApitallySpanCollector.getInstance().setDelegate(null); - GlobalOpenTelemetry.resetForTest(); - } - - private SpanCollector createAndRegisterCollector(boolean enabled) { - collector = new SpanCollector(enabled); - ApitallySpanCollector.getInstance().setDelegate(collector); - return collector; - } - - @Test - void testDisabledCollector() { - SpanCollector collector = createAndRegisterCollector(false); - - SpanCollector.SpanHandle handle = collector.startCollection(); - assertNull(handle); - } - - @Test - void testEnabledCollector() { - SpanCollector collector = createAndRegisterCollector(true); - - SpanCollector.SpanHandle handle = collector.startCollection(); - assertNotNull(handle); - assertNotNull(handle.getTraceId()); - assertEquals(32, handle.getTraceId().length()); - - List spans = handle.end(); - assertNotNull(spans); - assertEquals(1, spans.size()); - assertEquals("root", spans.get(0).getName()); - assertNull(spans.get(0).getParentSpanId()); - } - - @Test - void testCollectorWithChildSpans() { - SpanCollector collector = createAndRegisterCollector(true); - - SpanCollector.SpanHandle handle = collector.startCollection(); - Tracer tracer = GlobalOpenTelemetry.getTracer("test"); - - Span child1 = tracer.spanBuilder("child1").startSpan(); - child1.end(); - - Span child2 = tracer.spanBuilder("child2").startSpan(); - child2.end(); - - handle.setName("TestController.getTest"); - - List spans = handle.end(); - assertNotNull(spans); - assertEquals(3, spans.size()); - - Set spanNames = spans.stream().map(SpanData::getName).collect(Collectors.toSet()); - assertTrue(spanNames.contains("TestController.getTest")); - assertTrue(spanNames.contains("child1")); - assertTrue(spanNames.contains("child2")); - - SpanData rootSpan = spans.stream() - .filter(s -> s.getName().equals("TestController.getTest")) - .findFirst() - .orElse(null); - assertNotNull(rootSpan); - assertNull(rootSpan.getParentSpanId()); - - SpanData childSpan = spans.stream() - .filter(s -> s.getName().equals("child1")) - .findFirst() - .orElse(null); - assertNotNull(childSpan); - assertEquals(rootSpan.getSpanId(), childSpan.getParentSpanId()); - } - - @Test - void testDoesNotCollectUnrelatedSpans() { - SpanCollector collector = createAndRegisterCollector(true); - Tracer tracer = GlobalOpenTelemetry.getTracer("test"); - - Span outsideSpan = tracer.spanBuilder("outsideSpan").startSpan(); - outsideSpan.end(); - - SpanCollector.SpanHandle handle = collector.startCollection(); - - Span insideSpan = tracer.spanBuilder("insideSpan").startSpan(); - insideSpan.end(); - - List spans = handle.end(); - assertNotNull(spans); - - Set spanNames = spans.stream().map(SpanData::getName).collect(Collectors.toSet()); - assertTrue(spanNames.contains("root")); - assertTrue(spanNames.contains("insideSpan")); - assertFalse(spanNames.contains("outsideSpan")); - } - - @Test - void testSpanDataSerialization() { - SpanCollector collector = createAndRegisterCollector(true); - - SpanCollector.SpanHandle handle = collector.startCollection(); - Tracer tracer = GlobalOpenTelemetry.getTracer("test"); - - Span span = tracer.spanBuilder("testSpan").startSpan(); - span.setAttribute("http.method", "GET"); - span.setAttribute("http.status_code", 200); - span.setStatus(StatusCode.OK); - span.end(); - - List spans = handle.end(); - assertNotNull(spans); - - SpanData testSpan = spans.stream() - .filter(s -> s.getName().equals("testSpan")) - .findFirst() - .orElse(null); - assertNotNull(testSpan); - assertEquals(16, testSpan.getSpanId().length()); - assertEquals("INTERNAL", testSpan.getKind()); - assertTrue(testSpan.getStartTime() > 0); - assertTrue(testSpan.getEndTime() > 0); - assertTrue(testSpan.getEndTime() >= testSpan.getStartTime()); - - assertEquals("OK", testSpan.getStatus()); - assertNotNull(testSpan.getAttributes()); - assertEquals("GET", testSpan.getAttributes().get("http.method")); - assertEquals(200L, testSpan.getAttributes().get("http.status_code")); - } -} diff --git a/src/test/java/io/apitally/spring/ApitallyFilterTest.java b/src/test/java/io/apitally/spring/ApitallyFilterTest.java index fd40f0e..17b63e8 100644 --- a/src/test/java/io/apitally/spring/ApitallyFilterTest.java +++ b/src/test/java/io/apitally/spring/ApitallyFilterTest.java @@ -53,7 +53,6 @@ public ApitallyClient apitallyClient(ApitallyProperties properties) { LogAppender.register(); ApitallyClient client = new ApitallyClient(properties.getClientId(), properties.getEnv(), properties.getRequestLogging()); - ApitallySpanCollector.getInstance().setDelegate(client.spanCollector); return client; } @@ -281,13 +280,6 @@ void testRequestLogger() { assertTrue(firstItem.get("logs").size() > 0); assertTrue(firstItem.get("logs").get(0).get("message").asText().contains("Getting items")); - // Verify spans were captured - assertTrue(firstItem.has("spans")); - assertTrue(firstItem.get("spans").isArray()); - assertTrue(firstItem.get("spans").size() >= 2); // root span + child span - assertTrue(StreamSupport.stream(firstItem.get("spans").spliterator(), false) - .anyMatch(span -> span.get("name").asText().equals("fetchItems"))); - // Verify POST request logging with request body JsonNode secondItem = items[1]; assertEquals("POST", secondItem.get("request").get("method").asText()); diff --git a/src/test/java/io/apitally/spring/app/TestController.java b/src/test/java/io/apitally/spring/app/TestController.java index 9f936ba..c8acce1 100644 --- a/src/test/java/io/apitally/spring/app/TestController.java +++ b/src/test/java/io/apitally/spring/app/TestController.java @@ -1,9 +1,6 @@ package io.apitally.spring.app; import io.apitally.spring.ApitallyConsumer; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.ConstraintViolationException; import jakarta.validation.Valid; @@ -41,13 +38,9 @@ public List getItems( ApitallyConsumer consumer = new ApitallyConsumer("tester", "Tester", "Test Group"); request.setAttribute("apitallyConsumer", consumer); - Tracer tracer = GlobalOpenTelemetry.getTracer("test"); - Span childSpan = tracer.spanBuilder("fetchItems").startSpan(); - childSpan.setAttribute("filter", name != null ? name : "none"); List items = new ArrayList(); items.add(new TestItem(1, "bob")); items.add(new TestItem(2, "alice")); - childSpan.end(); logger.debug("Returning {} items", items.size()); return items; From f36002106599f85a8384e65b7e14c17afb2cc919 Mon Sep 17 00:00:00 2001 From: Simon Gurcke Date: Thu, 29 Jan 2026 22:53:05 +1000 Subject: [PATCH 2/2] Fix --- .../java/io/apitally/common/RequestLoggingConfig.java | 9 --------- src/main/java/io/apitally/spring/ApitallyFilter.java | 1 - src/test/java/io/apitally/common/RequestLoggerTest.java | 1 - src/test/java/io/apitally/spring/ApitallyFilterTest.java | 1 - src/test/resources/application.yml | 1 - 5 files changed, 13 deletions(-) diff --git a/src/main/java/io/apitally/common/RequestLoggingConfig.java b/src/main/java/io/apitally/common/RequestLoggingConfig.java index 34c6fa6..9f0688d 100644 --- a/src/main/java/io/apitally/common/RequestLoggingConfig.java +++ b/src/main/java/io/apitally/common/RequestLoggingConfig.java @@ -12,7 +12,6 @@ public class RequestLoggingConfig { private boolean responseBodyIncluded = false; private boolean exceptionIncluded = true; private boolean logCaptureEnabled = false; - private boolean tracingEnabled = false; private List queryParamMaskPatterns = new ArrayList<>(); private List headerMaskPatterns = new ArrayList<>(); private List bodyFieldMaskPatterns = new ArrayList<>(); @@ -83,14 +82,6 @@ public void setLogCaptureEnabled(boolean logCaptureEnabled) { this.logCaptureEnabled = logCaptureEnabled; } - public boolean isTracingEnabled() { - return tracingEnabled; - } - - public void setTracingEnabled(boolean tracingEnabled) { - this.tracingEnabled = tracingEnabled; - } - public List getQueryParamMaskPatterns() { return queryParamMaskPatterns; } diff --git a/src/main/java/io/apitally/spring/ApitallyFilter.java b/src/main/java/io/apitally/spring/ApitallyFilter.java index 267d217..e6f2cee 100644 --- a/src/main/java/io/apitally/spring/ApitallyFilter.java +++ b/src/main/java/io/apitally/spring/ApitallyFilter.java @@ -72,7 +72,6 @@ protected void doFilterInternal( cachingResponse == null ? new CountingResponseWrapper(response) : null; final boolean shouldCaptureLogs = requestLoggingEnabled && requestLoggingConfig.isLogCaptureEnabled(); - final boolean shouldCaptureSpans = requestLoggingEnabled && requestLoggingConfig.isTracingEnabled(); Exception exception = null; final long startTime = System.currentTimeMillis(); diff --git a/src/test/java/io/apitally/common/RequestLoggerTest.java b/src/test/java/io/apitally/common/RequestLoggerTest.java index 03fbda8..ca1683c 100644 --- a/src/test/java/io/apitally/common/RequestLoggerTest.java +++ b/src/test/java/io/apitally/common/RequestLoggerTest.java @@ -35,7 +35,6 @@ void setUp() { requestLoggingConfig.setResponseHeadersIncluded(true); requestLoggingConfig.setResponseBodyIncluded(true); requestLoggingConfig.setLogCaptureEnabled(true); - requestLoggingConfig.setTracingEnabled(true); requestLogger = new RequestLogger(requestLoggingConfig); } diff --git a/src/test/java/io/apitally/spring/ApitallyFilterTest.java b/src/test/java/io/apitally/spring/ApitallyFilterTest.java index 17b63e8..6fb6fcb 100644 --- a/src/test/java/io/apitally/spring/ApitallyFilterTest.java +++ b/src/test/java/io/apitally/spring/ApitallyFilterTest.java @@ -248,7 +248,6 @@ void testRequestLogger() { apitallyClient.requestLogger.getConfig().setRequestBodyIncluded(true); apitallyClient.requestLogger.getConfig().setResponseBodyIncluded(true); apitallyClient.requestLogger.getConfig().setLogCaptureEnabled(true); - apitallyClient.requestLogger.getConfig().setTracingEnabled(true); apitallyClient.requestLogger.clear(); ResponseEntity response = restTemplate.getForEntity("/items", String.class); diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index f93d993..a1c9bfb 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -9,7 +9,6 @@ apitally: response-body-included: true response-headers-included: true log-capture-enabled: true - tracing-enabled: true callbacks-class: io.apitally.spring.app.RequestLoggingCallbacks spring: