This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feat/camel-tui in repository https://gitbox.apache.org/repos/asf/camel.git
commit 02bfc17a8f33384ca8cd28178435aee5eaf41ecb Author: Claus Ibsen <[email protected]> AuthorDate: Mon May 18 11:22:21 2026 +0200 CAMEL-XXXX: rest-openapi mock mode now emits BacklogTracer trace events When missingOperation=mock and no route exists for an operation, the mock response was returned directly bypassing the normal route pipeline entirely, so no BacklogTracer trace events were recorded. The TUI inspect/trace tab therefore showed no activity for mocked operations. Fix by: - Adding shouldTrace(NamedNode, Exchange), traceBeforeNode(NamedNode, Exchange), traceAfterNode(NamedNode, Exchange), traceEvent(BacklogTracerEventMessage), and incrementTraceCounter() to the org.apache.camel.spi.BacklogTracer SPI interface (all already implemented in the concrete BacklogTracer class). - Implementing traceBeforeNode/traceAfterNode in the concrete BacklogTracer, building a DefaultBacklogTracerEventMessage with the exchange state. - Adding a MockOperationNode (minimal NamedNode) to DefaultRestOpenapiProcessorStrategy representing the mock operation, and calling traceBeforeNode/traceAfterNode around loadMockData() with a try/finally to guarantee the after event always fires. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../DefaultRestOpenapiProcessorStrategy.java | 77 +++++++++++++++++++++- .../java/org/apache/camel/spi/BacklogTracer.java | 40 +++++++++++ .../apache/camel/impl/debugger/BacklogTracer.java | 56 +++++++++++++++- 3 files changed, 171 insertions(+), 2 deletions(-) diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java index 086e6d84fdc4..696f9e654394 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java @@ -36,10 +36,12 @@ import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.NamedNode; import org.apache.camel.NonManagedService; import org.apache.camel.Route; import org.apache.camel.component.platform.http.PlatformHttpComponent; import org.apache.camel.component.platform.http.spi.PlatformHttpConsumerAware; +import org.apache.camel.spi.BacklogTracer; import org.apache.camel.spi.PackageScanResourceResolver; import org.apache.camel.spi.ProducerCache; import org.apache.camel.spi.Resource; @@ -208,7 +210,19 @@ public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport exchange.setRouteStop(true); } else if ("mock".equalsIgnoreCase(missingOperation)) { // no route then try to load mock data as the answer - loadMockData(operation, verb, path, exchange); + BacklogTracer backlogTracer + = camelContext.getCamelContextExtension().getContextPlugin(BacklogTracer.class); + NamedNode mockNode = new MockOperationNode(verb, path, operation.getOperationId()); + if (backlogTracer != null && backlogTracer.isEnabled()) { + backlogTracer.traceBeforeNode(mockNode, exchange); + } + try { + loadMockData(operation, verb, path, exchange); + } finally { + if (backlogTracer != null && backlogTracer.isEnabled()) { + backlogTracer.traceAfterNode(mockNode, exchange); + } + } } if (requestError == null) { var responseError = binding.doClientResponseValidation(exchange); @@ -441,4 +455,65 @@ public class DefaultRestOpenapiProcessorStrategy extends ServiceSupport } } + /** + * Minimal {@link NamedNode} to represent a mocked OpenAPI operation for tracing purposes. + */ + private static final class MockOperationNode implements NamedNode { + + private final String id; + private final String label; + + private MockOperationNode(String verb, String path, String operationId) { + this.id = operationId != null ? operationId : verb + ":" + path; + this.label = "mock:" + verb + ":" + path; + } + + @Override + public String getId() { + return id; + } + + @Override + public String getNodePrefixId() { + return null; + } + + @Override + public String getShortName() { + return "mock"; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getDescriptionText() { + return null; + } + + @Override + public NamedNode getParent() { + return null; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public void setLineNumber(int lineNumber) { + } + + @Override + public String getLocation() { + return null; + } + + @Override + public void setLocation(String location) { + } + } } diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java index 7667775c5f2f..4c514e2a9318 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java @@ -19,6 +19,8 @@ package org.apache.camel.spi; import java.util.Collection; import java.util.List; +import org.apache.camel.Exchange; +import org.apache.camel.NamedNode; import org.jspecify.annotations.Nullable; /** @@ -181,6 +183,13 @@ public interface BacklogTracer { */ long getTraceCounter(); + /** + * Increments and returns the trace counter. + * + * @since 4.21 + */ + long incrementTraceCounter(); + /** * Number of traced messages in the backlog */ @@ -191,6 +200,37 @@ public interface BacklogTracer { */ void resetTraceCounter(); + /** + * Whether the tracer should trace the given node and exchange (taking into account patterns and filters). + * + * @since 4.21 + */ + boolean shouldTrace(NamedNode node, Exchange exchange); + + /** + * Trace a "before node" event for components that process exchanges inline and bypass the normal route pipeline + * (e.g. mock mode in rest-openapi consumer). The concrete implementation builds and stores the trace event. + * + * @since 4.21 + */ + void traceBeforeNode(NamedNode node, Exchange exchange); + + /** + * Trace an "after node" event for components that process exchanges inline and bypass the normal route pipeline + * (e.g. mock mode in rest-openapi consumer). The concrete implementation builds and stores the trace event. + * + * @since 4.21 + */ + void traceAfterNode(NamedNode node, Exchange exchange); + + /** + * Records a trace event. Used by components that handle processing inline (e.g. mock mode in rest-openapi consumer) + * and therefore bypass the normal route pipeline where tracing is applied automatically. + * + * @since 4.21 + */ + void traceEvent(BacklogTracerEventMessage event); + /** * Get all tracing data (without removing) */ diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java index 3f75319df11e..0bad0466d434 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java @@ -27,11 +27,14 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; +import org.apache.camel.ExchangePropertyKey; import org.apache.camel.NamedNode; import org.apache.camel.Predicate; import org.apache.camel.spi.BacklogTracerEventMessage; import org.apache.camel.spi.Language; import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.support.LoggerHelper; +import org.apache.camel.support.MessageHelper; import org.apache.camel.support.PatternHelper; import org.apache.camel.support.service.ServiceSupport; import org.apache.camel.util.StringHelper; @@ -98,6 +101,7 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp * @param exchange the exchange * @return <tt>true</tt> to trace, <tt>false</tt> to skip tracing */ + @Override public boolean shouldTrace(NamedNode definition, Exchange exchange) { // special in standby mode we allow using tracer to capture latest tracing data for // enriched message history @@ -138,7 +142,56 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp return false; } - public void traceEvent(DefaultBacklogTracerEventMessage event) { + @Override + public void traceBeforeNode(NamedNode node, Exchange exchange) { + if (!shouldTrace(node, exchange)) { + return; + } + long timestamp = System.currentTimeMillis(); + String toNode = node.getId(); + String toNodeParentId = node.getParentId(); + String toNodeShortName = node.getShortName(); + String toNodeLabel = StringHelper.limitLength(node.getLabel(), 50); + String exchangeId = exchange.getExchangeId(); + String correlationExchangeId = exchange.getProperty(ExchangePropertyKey.CORRELATION_ID, String.class); + int level = node.getLevel(); + String fromRouteId = exchange.getFromRouteId(); + String source = LoggerHelper.getLineNumberLoggerName(node); + JsonObject data = MessageHelper.dumpAsJSonObject(exchange.getIn(), isIncludeExchangeProperties(), + isIncludeExchangeVariables(), true, true, isBodyIncludeStreams(), isBodyIncludeFiles(), getBodyMaxChars()); + DefaultBacklogTracerEventMessage event = new DefaultBacklogTracerEventMessage( + camelContext, false, false, incrementTraceCounter(), timestamp, source, fromRouteId, null, toNode, + toNodeParentId, null, null, toNodeShortName, toNodeLabel, level, + exchangeId, correlationExchangeId, false, false, data); + traceEvent(event); + } + + @Override + public void traceAfterNode(NamedNode node, Exchange exchange) { + if (!shouldTrace(node, exchange)) { + return; + } + long timestamp = System.currentTimeMillis(); + String toNode = node.getId(); + String toNodeParentId = node.getParentId(); + String toNodeShortName = node.getShortName(); + String toNodeLabel = StringHelper.limitLength(node.getLabel(), 50); + String exchangeId = exchange.getExchangeId(); + String correlationExchangeId = exchange.getProperty(ExchangePropertyKey.CORRELATION_ID, String.class); + int level = node.getLevel(); + String fromRouteId = exchange.getFromRouteId(); + String source = LoggerHelper.getLineNumberLoggerName(node); + JsonObject data = MessageHelper.dumpAsJSonObject(exchange.getIn(), isIncludeExchangeProperties(), + isIncludeExchangeVariables(), true, true, isBodyIncludeStreams(), isBodyIncludeFiles(), getBodyMaxChars()); + DefaultBacklogTracerEventMessage event = new DefaultBacklogTracerEventMessage( + camelContext, false, true, incrementTraceCounter(), timestamp, source, fromRouteId, null, toNode, + toNodeParentId, null, null, toNodeShortName, toNodeLabel, level, + exchangeId, correlationExchangeId, false, false, data); + traceEvent(event); + } + + @Override + public void traceEvent(BacklogTracerEventMessage event) { // special in standby mode we allow using tracer to capture latest tracing data for // enriched message history boolean history = (enabled || standby) && camelContext.isMessageHistory(); @@ -495,6 +548,7 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp provisionalHistoryQueue.clear(); } + @Override public long incrementTraceCounter() { return traceCounter.incrementAndGet(); }
