Jonas Beyer created CAMEL-22672:
-----------------------------------
Summary: [camel-observation] observations and metrics
Key: CAMEL-22672
URL: https://issues.apache.org/jira/browse/CAMEL-22672
Project: Camel
Issue Type: Bug
Affects Versions: 4.13.0
Reporter: Jonas Beyer
This is a bit of a revival of CAMEL-22349, which as far as I can tell has not
been resolved. The idea seems to be that
[https://github.com/apache/camel-spring-boot/pull/1493/files] would cause
{{@ConditionalOnMissingBean(MeterObservationHandler.class)}} in
{{org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration}}
to fail, which would prevent the creation of metrics ... in the whole context.
This did not work because the Camel {{ObservationAutoConfiguration}} has
{{@AutoConfigureAfter}} the Spring one. And so Spring tried to create both
beans leading to CAMEL-22612. The fix renamed the bean, so now both are
successfully created and with the Spring one also metrics.
I ran into the problem of many metrics on 4.14.0 and my main issue was the
naming, as {{process2}} or {{to13}} are no sensible identifiers. By naming them
hierarchically they could be conveniently suppressed via the property
{{management.metrics.enable.[prefix]: false}} or a configurable {{MeterFilter}}
instead of disabling the functionality.
Our current workaround is:
{code:java}
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.NamedNode;
import org.apache.camel.observation.MicrometerObservationTracer;
import org.apache.camel.spi.NodeIdFactory;
import org.apache.camel.support.ExtendedExchangeExtension;
import org.apache.commons.lang3.Strings;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Delegate;
import lombok.val;
public class CamelNodeIdFactory implements NodeIdFactory {
private static final String PREFIX = "camel-node";
private static final Map<String, AtomicInteger> NODE_COUNTERS = new
ConcurrentHashMap<>();
@Override
public String createId(NamedNode definition) {
val id = getId(definition);
val counter = NODE_COUNTERS.computeIfAbsent(id, k -> new
AtomicInteger()).incrementAndGet();
return id + (counter > 1 ? counter : "");
}
private String getId(NamedNode definition) {
if (definition == null) {
return PREFIX;
} else if (definition.getId() != null) {
return Strings.CS.prependIfMissing(definition.getId(), PREFIX + ".");
} else {
val parentId = getId(definition.getParent());
return parentId + "." + definition.getShortName();
}
}
@RequiredArgsConstructor
public static class SpanDecorator implements
org.apache.camel.tracing.SpanDecorator {
@Delegate
private final org.apache.camel.tracing.SpanDecorator delegate;
@Override
public String getOperationName(Exchange exchange, Endpoint endpoint) {
val exchangeExtension = (ExtendedExchangeExtension)
exchange.getExchangeExtension();
val nodeId = exchangeExtension.getHistoryNodeId();
return nodeId != null ? nodeId :
Strings.CS.prependIfMissing(exchangeExtension.getFromRouteId(), PREFIX + ".");
}
}
public static class Tracer extends MicrometerObservationTracer {
@Override
protected org.apache.camel.tracing.SpanDecorator getSpanDecorator(Endpoint
endpoint) {
return new SpanDecorator(super.getSpanDecorator(endpoint));
}
}
}{code}
with
{code:java}
@Bean(initMethod = "", destroyMethod = "") // Camel handles the lifecycle of
this bean
public MicrometerObservationTracer micrometerObservationTracer(CamelContext
camelContext,
Tracer tracer,
ObservationRegistry registry) {
camelContext.getCamelContextExtension().addContextPlugin(NodeIdFactory.class,
new CamelNodeIdFactory());
val micrometerObservationTracer = new CamelNodeIdFactory.Tracer();
micrometerObservationTracer.setTracer(tracer);
micrometerObservationTracer.setObservationRegistry(registry);
micrometerObservationTracer.setTracingStrategy(new
MicrometerTracingStrategy(micrometerObservationTracer));
micrometerObservationTracer.init(camelContext);
return micrometerObservationTracer;
} {code}
This could of course be cleaner if properly integrated into Camel.
It already enables us to turn off all route-specific metrics by default
{code:java}
management.metrics.enable.camel-node: false{code}
and turn on specific ones
{code:java}
management.metrics.enable.camel-node.[node-id]: true {code}
This is not perfect as the node id is part of the metric name instead of a tag,
but it is clear which part of the route is measured
({{{}camel_node_heartbeat_log_seconds{}}} instead of {{{}log[n]{}}}) - and it
doesn't interfere with the rest of the Spring Boot context.
cc [~squakez]
--
This message was sent by Atlassian Jira
(v8.20.10#820010)