Provide better support for activating observability with Spring Data Cassandra.
Resolves #1321. Original pull request: #1322
This commit is contained in:
committed by
Mark Paluch
parent
ddfff47a45
commit
a42bc734ea
@@ -19,7 +19,7 @@ import io.micrometer.common.docs.KeyName;
|
|||||||
import io.micrometer.observation.docs.ObservationDocumentation;
|
import io.micrometer.observation.docs.ObservationDocumentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra-based implementation of {@link DocumentedObservation}.
|
* Cassandra-based implementation of {@link ObservationDocumentation}.
|
||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Marcin Grzejszczak
|
* @author Marcin Grzejszczak
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2022 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.cassandra.observability;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import io.micrometer.tracing.Tracer;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of beans enable observability with Spring Data Cassandra.
|
||||||
|
*
|
||||||
|
* @author Greg Turnquist
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
public class CassandraObservationConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CqlSessionObservationConvention observationConvention() {
|
||||||
|
return new DefaultCassandraObservationConvention();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CqlSessionTracingObservationHandler cqlSessionTracingObservationHandler(
|
||||||
|
Optional<ObservationRegistry> observationRegistry, Tracer tracer) {
|
||||||
|
|
||||||
|
CqlSessionTracingObservationHandler observationHandler = new CqlSessionTracingObservationHandler(tracer);
|
||||||
|
observationRegistry.ifPresent(registry -> registry.observationConfig().observationHandler(observationHandler));
|
||||||
|
return observationHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CqlSessionTracingBeanPostProcessor traceCqlSessionBeanPostProcessor(ObservationRegistry observationRegistry,
|
||||||
|
CqlSessionObservationConvention observationConvention) {
|
||||||
|
return new CqlSessionTracingBeanPostProcessor(observationRegistry, observationConvention);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,7 +102,7 @@ final class CqlSessionTracingInterceptor implements MethodInterceptor {
|
|||||||
Function<Statement<?>, Object> statementExecutor) {
|
Function<Statement<?>, Object> statementExecutor) {
|
||||||
|
|
||||||
if (this.observationRegistry.getCurrentObservation() == null) {
|
if (this.observationRegistry.getCurrentObservation() == null) {
|
||||||
return null;
|
return statementExecutor.apply(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
Observation observation = childObservation(statement, methodName, this.delegateSession);
|
Observation observation = childObservation(statement, methodName, this.delegateSession);
|
||||||
@@ -111,14 +111,7 @@ final class CqlSessionTracingInterceptor implements MethodInterceptor {
|
|||||||
log.debug("Created a new child observation before query [" + observation + "]");
|
log.debug("Created a new child observation before query [" + observation + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Observation.Scope scope = observation.openScope()) {
|
return observation.observe(() -> statementExecutor.apply(statement));
|
||||||
return statementExecutor.apply(statement);
|
|
||||||
} catch (Exception e) {
|
|
||||||
observation.error(e);
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
observation.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +147,7 @@ final class CqlSessionTracingInterceptor implements MethodInterceptor {
|
|||||||
.observation(this.observationRegistry, () -> observationContext) //
|
.observation(this.observationRegistry, () -> observationContext) //
|
||||||
.contextualName(CassandraObservation.CASSANDRA_QUERY_OBSERVATION.getContextualName()) //
|
.contextualName(CassandraObservation.CASSANDRA_QUERY_OBSERVATION.getContextualName()) //
|
||||||
.highCardinalityKeyValues(this.observationConvention.getHighCardinalityKeyValues(observationContext)) //
|
.highCardinalityKeyValues(this.observationConvention.getHighCardinalityKeyValues(observationContext)) //
|
||||||
.lowCardinalityKeyValues(this.observationConvention.getLowCardinalityKeyValues(observationContext)) //
|
.lowCardinalityKeyValues(this.observationConvention.getLowCardinalityKeyValues(observationContext));
|
||||||
.start();
|
// .start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import com.datastax.oss.driver.api.core.cql.*;
|
|||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public class DefaultCassandraObservationContention implements CqlSessionObservationConvention {
|
public class DefaultCassandraObservationConvention implements CqlSessionObservationConvention {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyValues getLowCardinalityKeyValues(CqlSessionContext context) {
|
public KeyValues getLowCardinalityKeyValues(CqlSessionContext context) {
|
||||||
@@ -40,8 +40,8 @@ public class DefaultCassandraObservationContention implements CqlSessionObservat
|
|||||||
KeyValues keyValues = KeyValues.of(
|
KeyValues keyValues = KeyValues.of(
|
||||||
LowCardinalityKeyNames.SESSION_NAME
|
LowCardinalityKeyNames.SESSION_NAME
|
||||||
.withValue(Optional.ofNullable(context.getDelegateSession().getName()).orElse("unknown")),
|
.withValue(Optional.ofNullable(context.getDelegateSession().getName()).orElse("unknown")),
|
||||||
LowCardinalityKeyNames.KEYSPACE_NAME.withValue(
|
LowCardinalityKeyNames.KEYSPACE_NAME
|
||||||
Optional.ofNullable(context.getStatement().getKeyspace()).map(CqlIdentifier::asInternal).orElse("unknown")),
|
.withValue(context.getDelegateSession().getKeyspace().map(CqlIdentifier::asInternal).orElse("unknown")),
|
||||||
LowCardinalityKeyNames.METHOD_NAME.withValue(context.getMethodName()));
|
LowCardinalityKeyNames.METHOD_NAME.withValue(context.getMethodName()));
|
||||||
|
|
||||||
if (context.getStatement().getNode() != null) {
|
if (context.getStatement().getNode() != null) {
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2022 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.cassandra.observability;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation to enable Cassandra observability.
|
||||||
|
*
|
||||||
|
* @author Greg Turnquist
|
||||||
|
* @since 4.0.0
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import(CassandraObservationConfiguration.class)
|
||||||
|
public @interface EnableCassandraObservability {
|
||||||
|
}
|
||||||
@@ -18,7 +18,13 @@ package org.springframework.data.cassandra.observability;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationHandler;
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import io.micrometer.tracing.Tracer;
|
||||||
|
import io.micrometer.tracing.test.simple.SimpleTracer;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -29,6 +35,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlSession;
|
import com.datastax.oss.driver.api.core.CqlSession;
|
||||||
|
|
||||||
@@ -44,6 +51,8 @@ import com.datastax.oss.driver.api.core.CqlSession;
|
|||||||
public class CqlSessionTracingBeanPostProcessorTests {
|
public class CqlSessionTracingBeanPostProcessorTests {
|
||||||
|
|
||||||
@Autowired CqlSession session;
|
@Autowired CqlSession session;
|
||||||
|
@Autowired ObservationRegistry registry;
|
||||||
|
@Autowired CqlSessionTracingObservationHandler handler;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void injectedCqlSessionShouldBeWrapped() throws Exception {
|
void injectedCqlSessionShouldBeWrapped() throws Exception {
|
||||||
@@ -58,7 +67,22 @@ public class CqlSessionTracingBeanPostProcessorTests {
|
|||||||
assertThat(advised.getTargetSource().getTarget()).isEqualTo(TestConfig.originalSession);
|
assertThat(advised.getTargetSource().getTarget()).isEqualTo(TestConfig.originalSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void injectedObservationHandlerIsRegisteredWithRegistry() {
|
||||||
|
|
||||||
|
ObservationRegistry.ObservationConfig config = registry.observationConfig();
|
||||||
|
|
||||||
|
Method getObservationHandlers = ReflectionUtils.findMethod(ObservationRegistry.ObservationConfig.class,
|
||||||
|
"getObservationHandlers");
|
||||||
|
ReflectionUtils.makeAccessible(getObservationHandlers);
|
||||||
|
Collection<ObservationHandler<?>> handlers = (Collection<ObservationHandler<?>>) ReflectionUtils
|
||||||
|
.invokeMethod(getObservationHandlers, config);
|
||||||
|
|
||||||
|
assertThat(handlers).contains(handler);
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableCassandraObservability
|
||||||
static class TestConfig {
|
static class TestConfig {
|
||||||
|
|
||||||
static CqlSession originalSession = mock(CqlSession.class);
|
static CqlSession originalSession = mock(CqlSession.class);
|
||||||
@@ -74,14 +98,8 @@ public class CqlSessionTracingBeanPostProcessorTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
CqlSessionObservationConvention observationConvention() {
|
Tracer tracer() {
|
||||||
return new DefaultCassandraObservationContention();
|
return new SimpleTracer();
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CqlSessionTracingBeanPostProcessor traceCqlSessionBeanPostProcessor(ObservationRegistry observationRegistry,
|
|
||||||
CqlSessionObservationConvention tagsProvider) {
|
|
||||||
return new CqlSessionTracingBeanPostProcessor(observationRegistry, tagsProvider);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public class CqlSessionTracingTests extends IntegrationTestsSupport {
|
|||||||
ObservationRegistry observationRegistry = ObservationRegistry.create();
|
ObservationRegistry observationRegistry = ObservationRegistry.create();
|
||||||
observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));
|
observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));
|
||||||
|
|
||||||
CqlSessionObservationConvention observationContention = new DefaultCassandraObservationContention();
|
CqlSessionObservationConvention observationContention = new DefaultCassandraObservationConvention();
|
||||||
|
|
||||||
SimpleTracer tracer = new SimpleTracer();
|
SimpleTracer tracer = new SimpleTracer();
|
||||||
observationRegistry.observationConfig().observationHandler(new CqlSessionTracingObservationHandler(tracer));
|
observationRegistry.observationConfig().observationHandler(new CqlSessionTracingObservationHandler(tracer));
|
||||||
@@ -109,7 +109,7 @@ public class CqlSessionTracingTests extends IntegrationTestsSupport {
|
|||||||
ObservationRegistry observationRegistry = ObservationRegistry.create();
|
ObservationRegistry observationRegistry = ObservationRegistry.create();
|
||||||
observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));
|
observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));
|
||||||
|
|
||||||
CqlSessionObservationConvention observationContention = new DefaultCassandraObservationContention();
|
CqlSessionObservationConvention observationContention = new DefaultCassandraObservationConvention();
|
||||||
SimpleTracer tracer = new SimpleTracer();
|
SimpleTracer tracer = new SimpleTracer();
|
||||||
observationRegistry.observationConfig().observationHandler(new CqlSessionTracingObservationHandler(tracer));
|
observationRegistry.observationConfig().observationHandler(new CqlSessionTracingObservationHandler(tracer));
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ public class CqlSessionTracingTests extends IntegrationTestsSupport {
|
|||||||
|
|
||||||
MeterRegistryAssert.then(meterRegistry).hasTimerWithNameAndTags(CASSANDRA_QUERY_OBSERVATION.getName(), KeyValues.of( //
|
MeterRegistryAssert.then(meterRegistry).hasTimerWithNameAndTags(CASSANDRA_QUERY_OBSERVATION.getName(), KeyValues.of( //
|
||||||
LowCardinalityKeyNames.SESSION_NAME.withValue("s5"), //
|
LowCardinalityKeyNames.SESSION_NAME.withValue("s5"), //
|
||||||
LowCardinalityKeyNames.KEYSPACE_NAME.withValue("unknown"), //
|
LowCardinalityKeyNames.KEYSPACE_NAME.withValue("system"), //
|
||||||
KeyValue.of("error", "none") //
|
KeyValue.of("error", "none") //
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ public class CqlSessionTracingTests extends IntegrationTestsSupport {
|
|||||||
.hasRemoteServiceNameEqualTo("cassandra-s5") //
|
.hasRemoteServiceNameEqualTo("cassandra-s5") //
|
||||||
.hasNameEqualTo(CASSANDRA_QUERY_OBSERVATION.getContextualName()) //
|
.hasNameEqualTo(CASSANDRA_QUERY_OBSERVATION.getContextualName()) //
|
||||||
.hasTag(LowCardinalityKeyNames.SESSION_NAME, "s5") //
|
.hasTag(LowCardinalityKeyNames.SESSION_NAME, "s5") //
|
||||||
.hasTag(LowCardinalityKeyNames.KEYSPACE_NAME, "unknown") //
|
.hasTag(LowCardinalityKeyNames.KEYSPACE_NAME, "system") //
|
||||||
.hasTag(HighCardinalityKeyNames.CQL_TAG, CREATE_KEYSPACE) //
|
.hasTag(HighCardinalityKeyNames.CQL_TAG, CREATE_KEYSPACE) //
|
||||||
.hasIpThatIsBlank() //
|
.hasIpThatIsBlank() //
|
||||||
.hasPortEqualTo(0) //
|
.hasPortEqualTo(0) //
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import io.micrometer.tracing.test.reporter.BuildingBlocks;
|
|||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -46,7 +45,6 @@ import com.datastax.oss.driver.api.core.CqlSession;
|
|||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@Disabled("Run this manually to visually test spans in Zipkin")
|
|
||||||
@ExtendWith({ SpringExtension.class, CassandraExtension.class })
|
@ExtendWith({ SpringExtension.class, CassandraExtension.class })
|
||||||
@TestKeyspaceName
|
@TestKeyspaceName
|
||||||
public class ZipkinIntegrationTests extends SampleTestRunner {
|
public class ZipkinIntegrationTests extends SampleTestRunner {
|
||||||
@@ -91,6 +89,9 @@ public class ZipkinIntegrationTests extends SampleTestRunner {
|
|||||||
|
|
||||||
return (tracer, meterRegistry) -> {
|
return (tracer, meterRegistry) -> {
|
||||||
|
|
||||||
|
OBSERVATION_REGISTRY.observationConfig()
|
||||||
|
.observationHandler(new CqlSessionTracingObservationHandler(tracer.getTracer()));
|
||||||
|
|
||||||
session.execute("DROP KEYSPACE IF EXISTS ConfigTest");
|
session.execute("DROP KEYSPACE IF EXISTS ConfigTest");
|
||||||
session.execute("CREATE KEYSPACE ConfigTest " + "WITH "
|
session.execute("CREATE KEYSPACE ConfigTest " + "WITH "
|
||||||
+ "REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
+ "REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
||||||
@@ -117,13 +118,13 @@ public class ZipkinIntegrationTests extends SampleTestRunner {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
CqlSessionObservationConvention observationContention() {
|
CqlSessionObservationConvention observationContention() {
|
||||||
return new DefaultCassandraObservationContention();
|
return new DefaultCassandraObservationConvention();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
CqlSessionTracingBeanPostProcessor traceCqlSessionBeanPostProcessor(ObservationRegistry observationRegistry,
|
CqlSessionTracingBeanPostProcessor traceCqlSessionBeanPostProcessor(ObservationRegistry observationRegistry,
|
||||||
CqlSessionObservationConvention tagsProvider) {
|
CqlSessionObservationConvention observationConvention) {
|
||||||
return new CqlSessionTracingBeanPostProcessor(observationRegistry, tagsProvider);
|
return new CqlSessionTracingBeanPostProcessor(observationRegistry, observationConvention);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,3 +8,77 @@ include::{root-target}_conventions.adoc[]
|
|||||||
include::{root-target}_metrics.adoc[]
|
include::{root-target}_metrics.adoc[]
|
||||||
|
|
||||||
include::{root-target}_spans.adoc[]
|
include::{root-target}_spans.adoc[]
|
||||||
|
|
||||||
|
[[observability.registration]]
|
||||||
|
== Observability Registration
|
||||||
|
|
||||||
|
Spring Data Cassandra is not yet supported in Spring Boot to automatically enable observability.
|
||||||
|
Don't worry, we've got you covered!
|
||||||
|
Simply add the `@EnableCassandraObservability` annotation to your Spring Boot application, and you'll be all set.
|
||||||
|
|
||||||
|
.Activating observability for your Spring Boot application
|
||||||
|
====
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableCassandraObservability // <1>
|
||||||
|
public class SpringDataCassandraObservabilityApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringDataCassandraObservabilityApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
<1> This annotation will activate the bits needed start wrapping CQL calls and register them with your tracer of choice.
|
||||||
|
====
|
||||||
|
|
||||||
|
By the way, Spring Boot DOES have autoconfigured hooks into various parts of the system.
|
||||||
|
For example, there is an observation filter that Spring Boot will apply to Spring MVC ensuring all your calls are wrapped properly.
|
||||||
|
And if anywhere in the midst of that web call, you invoke Spring Data Cassandra (either through `CqlTemplate` or a custom repository), it will get captured properly.
|
||||||
|
|
||||||
|
Something that is NOT covered are situations where your code runs independently.
|
||||||
|
For example, if you have some block that is run during startup inside a `CommandLineRunner`, there is no way for Spring Boot to know that this should observed.
|
||||||
|
Check out the code block below:
|
||||||
|
|
||||||
|
.Loading data for a sample application
|
||||||
|
====
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
CommandLineRunner initData(EmployeeRepository repository) {
|
||||||
|
return args -> {
|
||||||
|
repository.save(new Employee("1", "Frodo", "ring bearer"));
|
||||||
|
repository.save(new Employee("2", "Bilbo", "burglar"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
----
|
||||||
|
This tactic is used all the time in demos. These calls to a Spring Data Cassandra repository will NOT be observed.
|
||||||
|
====
|
||||||
|
|
||||||
|
If you DO want to observe such a code block, you must wrap it yourself, as shown below:
|
||||||
|
|
||||||
|
.Observing the loading of data in a sample application
|
||||||
|
====
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
CommandLineRunner initData(EmployeeRepository repository, ObservationRegistry registry) { // <1>
|
||||||
|
return args -> {
|
||||||
|
Observation.createNotStarted("init-database", registry).observe(() -> { // <2>
|
||||||
|
repository.save(new Employee("1", "Frodo", "ring bearer"));
|
||||||
|
repository.save(new Employee("2", "Bilbo", "burglar"));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
----
|
||||||
|
<1> Your `CommandLineRunner` requires access to the app context's `ObservationRegistry`
|
||||||
|
<2> You need to create your own `Observation` using the `createNotStarted()` method. Give it any contextual name you like, but be sure to include the `registry`.
|
||||||
|
====
|
||||||
|
|
||||||
|
The `observe()` method takes a Java 8 lambda function which is invoked inside a common Micrometer pattern of:
|
||||||
|
|
||||||
|
* Starting the observation.
|
||||||
|
* Invoking your callback.
|
||||||
|
* Properly ending the observation by either reporting an error if it fails or stopping the observation if it succeeds.
|
||||||
|
|
||||||
|
This will allow you to observe chunks of code that may fall outside of currently autoconfigured operations.
|
||||||
|
|||||||
Reference in New Issue
Block a user