Remove MicrometerTracingAdapter in favor of Lettuce's Micrometer support.
Closes #3093
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
= Observability
|
||||
|
||||
Getting insights from an application component about its operations, timing and relation to application code is crucial to understand latency.
|
||||
Spring Data Redis ships with a Micrometer integration through the Lettuce driver to collect observations during Redis interaction.
|
||||
Lettuce ships with a Micrometer integration to collect observations during Redis interaction.
|
||||
Once the integration is set up, Micrometer will create meters and spans (for distributed tracing) for each Redis command.
|
||||
|
||||
To enable the integration, apply the following configuration to `LettuceClientConfiguration`:
|
||||
@@ -16,7 +16,7 @@ class ObservabilityConfiguration {
|
||||
public ClientResources clientResources(ObservationRegistry observationRegistry) {
|
||||
|
||||
return ClientResources.builder()
|
||||
.tracing(new MicrometerTracingAdapter(observationRegistry, "my-redis-cache"))
|
||||
.tracing(new MicrometerTracing(observationRegistry, "my-redis-cache"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -31,77 +31,7 @@ class ObservabilityConfiguration {
|
||||
}
|
||||
----
|
||||
|
||||
See also https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/database/#redis[OpenTelemetry Semantic Conventions] for further reference.
|
||||
See also for further reference:
|
||||
* https://redis.github.io/lettuce/advanced-usage/#micrometer[Lettuce Tracing]
|
||||
* https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/database/#redis[OpenTelemetry Semantic Conventions] .
|
||||
|
||||
[[observability-metrics]]
|
||||
== Observability - Metrics
|
||||
|
||||
Below you can find a list of all metrics declared by this project.
|
||||
|
||||
[[observability-metrics-redis-command-observation]]
|
||||
== Redis Command Observation
|
||||
|
||||
____
|
||||
Timer created around a Redis command execution.
|
||||
____
|
||||
|
||||
**Metric name** `spring.data.redis`. **Type** `timer` and **base unit** `seconds`.
|
||||
|
||||
Fully qualified name of the enclosing class `org.springframework.data.redis.connection.lettuce.observability.RedisObservation`.
|
||||
|
||||
|
||||
|
||||
.Low cardinality Keys
|
||||
[cols="a,a"]
|
||||
|===
|
||||
|Name | Description
|
||||
|`db.operation`|Redis command value.
|
||||
|`db.redis.database_index`|Redis database index.
|
||||
|`db.system`|Database system.
|
||||
|`db.user`|Redis user.
|
||||
|`net.peer.name`|Name of the database host.
|
||||
|`net.peer.port`|Logical remote port number.
|
||||
|`net.sock.peer.addr`|Mongo peer address.
|
||||
|`net.sock.peer.port`|Mongo peer port.
|
||||
|`net.transport`|Network transport.
|
||||
|===
|
||||
|
||||
.High cardinality Keys
|
||||
[cols="a,a"]
|
||||
|===
|
||||
|Name | Description
|
||||
|`db.statement`|Redis statement.
|
||||
|`spring.data.redis.command.error`|Redis error response.
|
||||
|===
|
||||
|
||||
[[observability-spans]]
|
||||
== Observability - Spans
|
||||
|
||||
Below you can find a list of all spans declared by this project.
|
||||
|
||||
[[observability-spans-redis-command-observation]]
|
||||
== Redis Command Observation Span
|
||||
|
||||
> Timer created around a Redis command execution.
|
||||
|
||||
**Span name** `spring.data.redis`.
|
||||
|
||||
Fully qualified name of the enclosing class `org.springframework.data.redis.connection.lettuce.observability.RedisObservation`.
|
||||
|
||||
|
||||
|
||||
.Tag Keys
|
||||
|===
|
||||
|Name | Description
|
||||
|`db.operation`|Redis command value.
|
||||
|`db.redis.database_index`|Redis database index.
|
||||
|`db.statement`|Redis statement.
|
||||
|`db.system`|Database system.
|
||||
|`db.user`|Redis user.
|
||||
|`net.peer.name`|Name of the database host.
|
||||
|`net.peer.port`|Logical remote port number.
|
||||
|`net.sock.peer.addr`|Mongo peer address.
|
||||
|`net.sock.peer.port`|Mongo peer port.
|
||||
|`net.transport`|Network transport.
|
||||
|`spring.data.redis.command.error`|Redis error response.
|
||||
|===
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
import io.lettuce.core.tracing.Tracing.Endpoint;
|
||||
import io.micrometer.common.KeyValues;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.HighCardinalityCommandKeyNames;
|
||||
import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.LowCardinalityCommandKeyNames;
|
||||
|
||||
/**
|
||||
* Default {@link LettuceObservationConvention} implementation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
record DefaultLettuceObservationConvention(
|
||||
boolean includeCommandArgsInSpanTags) implements LettuceObservationConvention {
|
||||
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(LettuceObservationContext context) {
|
||||
|
||||
Endpoint ep = context.getRequiredEndpoint();
|
||||
KeyValues keyValues = KeyValues.of(LowCardinalityCommandKeyNames.DATABASE_SYSTEM.withValue("redis"), //
|
||||
LowCardinalityCommandKeyNames.REDIS_COMMAND.withValue(context.getRequiredCommand().getType().toString()));
|
||||
|
||||
if (ep instanceof SocketAddressEndpoint endpoint) {
|
||||
|
||||
if (endpoint.socketAddress() instanceof InetSocketAddress inet) {
|
||||
keyValues = keyValues
|
||||
.and(KeyValues.of(LowCardinalityCommandKeyNames.NET_SOCK_PEER_ADDR.withValue(inet.getHostString()),
|
||||
LowCardinalityCommandKeyNames.NET_SOCK_PEER_PORT.withValue("" + inet.getPort()),
|
||||
LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("IP.TCP")));
|
||||
} else {
|
||||
keyValues = keyValues
|
||||
.and(KeyValues.of(LowCardinalityCommandKeyNames.NET_PEER_NAME.withValue(endpoint.toString()),
|
||||
LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("Unix")));
|
||||
}
|
||||
}
|
||||
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValues getHighCardinalityKeyValues(LettuceObservationContext context) {
|
||||
|
||||
RedisCommand<?, ?, ?> command = context.getRequiredCommand();
|
||||
|
||||
if (includeCommandArgsInSpanTags) {
|
||||
|
||||
if (command.getArgs() != null) {
|
||||
return KeyValues.of(HighCardinalityCommandKeyNames.STATEMENT
|
||||
.withValue(command.getType().toString() + " " + command.getArgs().toCommandString()));
|
||||
}
|
||||
}
|
||||
|
||||
return KeyValues.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextualName(LettuceObservationContext context) {
|
||||
return context.getRequiredCommand().getType().toString().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
import io.lettuce.core.tracing.Tracing.Endpoint;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.transport.Kind;
|
||||
import io.micrometer.observation.transport.SenderContext;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Micrometer {@link Observation.Context} holding Lettuce contextual details.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
public class LettuceObservationContext extends SenderContext<Object> {
|
||||
|
||||
private volatile @Nullable RedisCommand<?, ?, ?> command;
|
||||
|
||||
private volatile @Nullable Endpoint endpoint;
|
||||
|
||||
public LettuceObservationContext(String serviceName) {
|
||||
super((carrier, key, value) -> {}, Kind.CLIENT);
|
||||
setRemoteServiceName(serviceName);
|
||||
}
|
||||
|
||||
public RedisCommand<?, ?, ?> getRequiredCommand() {
|
||||
|
||||
RedisCommand<?, ?, ?> local = command;
|
||||
|
||||
if (local == null) {
|
||||
throw new IllegalArgumentException("LettuceObservationContext is not associated with a Command");
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setCommand(RedisCommand<?, ?, ?> command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public Endpoint getRequiredEndpoint() {
|
||||
|
||||
Endpoint local = endpoint;
|
||||
|
||||
if (local == null) {
|
||||
throw new IllegalArgumentException("LettuceObservationContext is not associated with a Endpoint");
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setEndpoint(Endpoint endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
|
||||
/**
|
||||
* {@link ObservationConvention} for {@link LettuceObservationContext}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
interface LettuceObservationConvention extends ObservationConvention<LettuceObservationContext> {
|
||||
|
||||
@Override
|
||||
default boolean supportsContext(Observation.Context context) {
|
||||
return context instanceof LettuceObservationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.lettuce.core.protocol.CompleteableCommand;
|
||||
import io.lettuce.core.protocol.RedisCommand;
|
||||
import io.lettuce.core.tracing.TraceContext;
|
||||
import io.lettuce.core.tracing.TraceContextProvider;
|
||||
import io.lettuce.core.tracing.Tracer;
|
||||
import io.lettuce.core.tracing.Tracer.Span;
|
||||
import io.lettuce.core.tracing.TracerProvider;
|
||||
import io.lettuce.core.tracing.Tracing;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.HighCardinalityCommandKeyNames;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link Tracing} adapter using Micrometer's {@link Observation}. This adapter integrates with Micrometer to propagate
|
||||
* observations into timers, distributed traces and any other registered handlers. Observations include a set of tags
|
||||
* capturing Redis runtime information.
|
||||
* <h3>Capturing full statements</h3> This adapter can capture full statements when enabling
|
||||
* {@code includeCommandArgsInSpanTags}. You should carefully consider the impact of this setting as all command
|
||||
* arguments will be captured in traces including these that may contain sensitive details.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Yanming Zhou
|
||||
* @since 3.0
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
public class MicrometerTracingAdapter implements Tracing {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MicrometerTracingAdapter.class);
|
||||
|
||||
private final ObservationRegistry observationRegistry;
|
||||
private final String serviceName;
|
||||
private final boolean includeCommandArgsInSpanTags;
|
||||
|
||||
private final LettuceObservationConvention observationConvention;
|
||||
|
||||
/**
|
||||
* Create a new {@link MicrometerTracingAdapter} instance.
|
||||
*
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param serviceName service name to be used.
|
||||
*/
|
||||
public MicrometerTracingAdapter(ObservationRegistry observationRegistry, String serviceName) {
|
||||
this(observationRegistry, serviceName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link MicrometerTracingAdapter} instance.
|
||||
*
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param serviceName service name to be used.
|
||||
* @param includeCommandArgsInSpanTags whether to attach the full command into the trace. Use this flag with caution
|
||||
* as sensitive arguments will be captured in the observation spans and metric tags.
|
||||
*/
|
||||
public MicrometerTracingAdapter(ObservationRegistry observationRegistry, String serviceName,
|
||||
boolean includeCommandArgsInSpanTags) {
|
||||
|
||||
this.observationRegistry = observationRegistry;
|
||||
this.serviceName = serviceName;
|
||||
this.observationConvention = new DefaultLettuceObservationConvention(includeCommandArgsInSpanTags);
|
||||
this.includeCommandArgsInSpanTags = includeCommandArgsInSpanTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracerProvider getTracerProvider() {
|
||||
return () -> new MicrometerTracer(observationRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceContextProvider initialTraceContextProvider() {
|
||||
return new MicrometerTraceContextProvider(observationRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeCommandArgsInSpanTags() {
|
||||
return includeCommandArgsInSpanTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Endpoint createEndpoint(SocketAddress socketAddress) {
|
||||
return new SocketAddressEndpoint(socketAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Tracer} implementation based on Micrometer's {@link ObservationRegistry}.
|
||||
*/
|
||||
public class MicrometerTracer extends Tracer {
|
||||
|
||||
private final ObservationRegistry observationRegistry;
|
||||
|
||||
public MicrometerTracer(ObservationRegistry observationRegistry) {
|
||||
this.observationRegistry = observationRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span nextSpan() {
|
||||
return this.postProcessSpan(createObservation(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span nextSpan(TraceContext traceContext) {
|
||||
return postProcessSpan(createObservation(traceContext));
|
||||
}
|
||||
|
||||
private Observation createObservation(@Nullable TraceContext parentContext) {
|
||||
|
||||
return RedisObservation.REDIS_COMMAND_OBSERVATION.observation(observationRegistry, () -> {
|
||||
|
||||
LettuceObservationContext context = new LettuceObservationContext(serviceName);
|
||||
|
||||
if (parentContext instanceof MicrometerTraceContext traceContext) {
|
||||
context.setParentObservation(traceContext.observation());
|
||||
}
|
||||
return context;
|
||||
});
|
||||
}
|
||||
|
||||
private Tracer.Span postProcessSpan(Observation observation) {
|
||||
|
||||
return !observation.isNoop() ? new MicrometerSpan(observation.observationConvention(observationConvention))
|
||||
: NoOpSpan.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op {@link Span} implementation.
|
||||
*/
|
||||
static class NoOpSpan extends Tracer.Span {
|
||||
|
||||
static final NoOpSpan INSTANCE = new NoOpSpan();
|
||||
|
||||
public NoOpSpan() {}
|
||||
|
||||
@Override
|
||||
public Tracer.Span start(RedisCommand<?, ?, ?> command) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span name(String name) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span annotate(String value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span tag(String key, String value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span error(Throwable throwable) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracer.Span remoteEndpoint(Tracing.Endpoint endpoint) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Micrometer {@link Observation}-based {@link Span} implementation.
|
||||
*/
|
||||
static class MicrometerSpan extends Tracer.Span {
|
||||
|
||||
private final Observation observation;
|
||||
|
||||
private @Nullable RedisCommand<?, ?, ?> command;
|
||||
|
||||
public MicrometerSpan(Observation observation) {
|
||||
this.observation = observation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span start(RedisCommand<?, ?, ?> command) {
|
||||
|
||||
((LettuceObservationContext) observation.getContext()).setCommand(command);
|
||||
|
||||
this.command = command;
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Starting Observation for Command %s".formatted(command));
|
||||
}
|
||||
|
||||
if (command instanceof CompleteableCommand<?> completeableCommand) {
|
||||
|
||||
completeableCommand.onComplete((o, throwable) -> {
|
||||
|
||||
if (command.getOutput() != null) {
|
||||
|
||||
String error = command.getOutput().getError();
|
||||
if (error != null) {
|
||||
observation.highCardinalityKeyValue(HighCardinalityCommandKeyNames.ERROR.withValue(error));
|
||||
} else if (throwable != null) {
|
||||
error(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
});
|
||||
} else {
|
||||
throw new IllegalArgumentException("Command " + command
|
||||
+ " must implement CompleteableCommand to attach Span completion to command completion");
|
||||
}
|
||||
|
||||
observation.start();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span name(String name) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span annotate(String annotation) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span tag(String key, String value) {
|
||||
observation.highCardinalityKeyValue(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span error(Throwable throwable) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attaching error to Observation for Command %s".formatted(command));
|
||||
}
|
||||
|
||||
observation.error(throwable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span remoteEndpoint(Endpoint endpoint) {
|
||||
|
||||
((LettuceObservationContext) observation.getContext()).setEndpoint(endpoint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopping Observation for Command %s".formatted(command));
|
||||
}
|
||||
|
||||
observation.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TraceContextProvider} using {@link ObservationRegistry}.
|
||||
*/
|
||||
record MicrometerTraceContextProvider(ObservationRegistry registry) implements TraceContextProvider {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public TraceContext getTraceContext() {
|
||||
|
||||
Observation observation = registry.getCurrentObservation();
|
||||
|
||||
if (observation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MicrometerTraceContext(observation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<TraceContext> getTraceContextLater() {
|
||||
|
||||
return Mono.deferContextual(Mono::justOrEmpty).filter((it) -> {
|
||||
return it.hasKey(TraceContext.class) || it.hasKey(Observation.class)
|
||||
|| it.hasKey(ObservationThreadLocalAccessor.KEY);
|
||||
}).map((it) -> {
|
||||
|
||||
if (it.hasKey(Observation.class)) {
|
||||
return new MicrometerTraceContext(it.get(Observation.class));
|
||||
}
|
||||
|
||||
if (it.hasKey(TraceContext.class)) {
|
||||
return it.get(TraceContext.class);
|
||||
}
|
||||
|
||||
return new MicrometerTraceContext(it.get(ObservationThreadLocalAccessor.KEY));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TraceContext} implementation using {@link Observation}.
|
||||
*
|
||||
* @param observation
|
||||
*/
|
||||
record MicrometerTraceContext(Observation observation) implements TraceContext {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.micrometer.common.docs.KeyName;
|
||||
import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
|
||||
/**
|
||||
* A Redis-based {@link io.micrometer.observation.Observation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
public enum RedisObservation implements ObservationDocumentation {
|
||||
|
||||
/**
|
||||
* Timer created around a Redis command execution.
|
||||
*/
|
||||
REDIS_COMMAND_OBSERVATION {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "spring.data.redis";
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getLowCardinalityKeyNames() {
|
||||
return LowCardinalityCommandKeyNames.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyName[] getHighCardinalityKeyNames() {
|
||||
return HighCardinalityCommandKeyNames.values();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enums related to low cardinality key names for Redis commands.
|
||||
*/
|
||||
enum LowCardinalityCommandKeyNames implements KeyName {
|
||||
|
||||
/**
|
||||
* Database system.
|
||||
*/
|
||||
DATABASE_SYSTEM {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "db.system";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Network transport.
|
||||
*/
|
||||
NET_TRANSPORT {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "net.transport";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Name of the database host.
|
||||
*/
|
||||
NET_PEER_NAME {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "net.peer.name";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Logical remote port number.
|
||||
*/
|
||||
NET_PEER_PORT {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "net.peer.port";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Mongo peer address.
|
||||
*/
|
||||
NET_SOCK_PEER_ADDR {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "net.sock.peer.addr";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Mongo peer port.
|
||||
*/
|
||||
NET_SOCK_PEER_PORT {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "net.sock.peer.port";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Redis user.
|
||||
*/
|
||||
DB_USER {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "db.user";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Redis database index.
|
||||
*/
|
||||
DB_INDEX {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "db.redis.database_index";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Redis command value.
|
||||
*/
|
||||
REDIS_COMMAND {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "db.operation";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enums related to high cardinality key names for Redis commands.
|
||||
*/
|
||||
enum HighCardinalityCommandKeyNames implements KeyName {
|
||||
|
||||
/**
|
||||
* Redis statement.
|
||||
*/
|
||||
STATEMENT {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "db.statement";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Redis error response.
|
||||
*/
|
||||
ERROR {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "spring.data.redis.command.error";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 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.data.redis.connection.lettuce.observability;
|
||||
|
||||
import io.lettuce.core.tracing.Tracing.Endpoint;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
* @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through
|
||||
* {@link io.lettuce.core.tracing.MicrometerTracing}.
|
||||
*/
|
||||
@Deprecated(since = "3.4", forRemoval = true)
|
||||
record SocketAddressEndpoint(SocketAddress socketAddress) implements Endpoint {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if (socketAddress instanceof InetSocketAddress inet) {
|
||||
return inet.getHostString() + ":" + inet.getPort();
|
||||
}
|
||||
|
||||
return socketAddress.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Integration of Micrometer Tracing for Lettuce Observability.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.data.redis.connection.lettuce.observability;
|
||||
Reference in New Issue
Block a user