Skip to content

Commit c1e3dbf

Browse files
committed
Introduce Micrometer API to add tracing.
Closes #1212.
1 parent 9686749 commit c1e3dbf

File tree

13 files changed

+1121
-2
lines changed

13 files changed

+1121
-2
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@
354354
<id>external-cassandra</id>
355355
<properties>
356356
<build.cassandra.mode>external</build.cassandra.mode>
357-
<build.cassandra.native_transport_port>9042 </build.cassandra.native_transport_port>
357+
<build.cassandra.native_transport_port>9042</build.cassandra.native_transport_port>
358358
<build.cassandra.rpc_port>9160</build.cassandra.rpc_port>
359359
<build.cassandra.ssl_storage_port>7001</build.cassandra.ssl_storage_port>
360360
<build.cassandra.storage_port>7000</build.cassandra.storage_port>
@@ -369,7 +369,7 @@
369369

370370
<properties>
371371
<build.cassandra.mode>testcontainers</build.cassandra.mode>
372-
<build.cassandra.native_transport_port>0 </build.cassandra.native_transport_port>
372+
<build.cassandra.native_transport_port>0</build.cassandra.native_transport_port>
373373
<build.cassandra.rpc_port>0</build.cassandra.rpc_port>
374374
<build.cassandra.ssl_storage_port>0</build.cassandra.ssl_storage_port>
375375
<build.cassandra.storage_port>0</build.cassandra.storage_port>

spring-data-cassandra/pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,36 @@
7171
<artifactId>java-driver-query-builder</artifactId>
7272
</dependency>
7373

74+
<!-- Micrometer -->
75+
<dependency>
76+
<groupId>io.micrometer</groupId>
77+
<artifactId>micrometer-observation</artifactId>
78+
<optional>true</optional>
79+
</dependency>
80+
<dependency>
81+
<groupId>io.micrometer</groupId>
82+
<artifactId>micrometer-tracing-api</artifactId>
83+
<optional>true</optional>
84+
</dependency>
85+
86+
<dependency>
87+
<groupId>io.micrometer</groupId>
88+
<artifactId>micrometer-test</artifactId>
89+
<scope>test</scope>
90+
</dependency>
91+
92+
<dependency>
93+
<groupId>io.micrometer</groupId>
94+
<artifactId>micrometer-tracing-test</artifactId>
95+
<scope>test</scope>
96+
</dependency>
97+
98+
<dependency>
99+
<groupId>io.micrometer</groupId>
100+
<artifactId>micrometer-tracing-integration-test</artifactId>
101+
<scope>test</scope>
102+
</dependency>
103+
74104
<!-- Reactor -->
75105
<dependency>
76106
<groupId>io.projectreactor</groupId>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.observability;
17+
18+
import io.micrometer.common.docs.TagKey;
19+
import io.micrometer.observation.docs.DocumentedObservation;
20+
21+
/**
22+
* Cassandra-based implementation of {@link DocumentedObservation}.
23+
*
24+
* @author Mark Paluch
25+
* @author Marcin Grzejszczak
26+
* @author Greg Turnquist
27+
* @since 4.0.0
28+
*/
29+
enum CassandraObservation implements DocumentedObservation {
30+
31+
/**
32+
* Create an {@link io.micrometer.observation.Observation} for Cassandra-based queries.
33+
*/
34+
CASSANDRA_QUERY_OBSERVATION {
35+
36+
@Override
37+
public String getName() {
38+
return "spring.data.cassandra.query";
39+
}
40+
41+
@Override
42+
public String getContextualName() {
43+
return "query";
44+
}
45+
46+
@Override
47+
public TagKey[] getLowCardinalityTagKeys() {
48+
return LowCardinalityTags.values();
49+
}
50+
51+
@Override
52+
public TagKey[] getHighCardinalityTagKeys() {
53+
return HighCardinalityTags.values();
54+
}
55+
56+
@Override
57+
public String getPrefix() {
58+
return "spring.data.cassandra.";
59+
}
60+
};
61+
62+
enum LowCardinalityTags implements TagKey {
63+
64+
/**
65+
* Name of the Cassandra keyspace.
66+
*/
67+
KEYSPACE_NAME {
68+
@Override
69+
public String getKey() {
70+
return "spring.data.cassandra.keyspace";
71+
}
72+
},
73+
74+
/**
75+
* Cassandra session
76+
*/
77+
SESSION_NAME {
78+
@Override
79+
public String getKey() {
80+
return "spring.data.cassandra.sessionName";
81+
}
82+
},
83+
84+
/**
85+
* The method name
86+
*/
87+
METHOD_NAME {
88+
@Override
89+
public String getKey() {
90+
return "spring.data.cassandra.methodName";
91+
}
92+
},
93+
94+
/**
95+
* Cassandra URL
96+
*/
97+
URL {
98+
@Override
99+
public String getKey() {
100+
return "spring.data.cassandra.url";
101+
}
102+
},
103+
104+
/**
105+
* A tag containing error that occurred for the given node.
106+
*/
107+
NODE_ERROR_TAG {
108+
@Override
109+
public String getKey() {
110+
return "spring.data.cassandra.node[%s].error";
111+
}
112+
}
113+
}
114+
115+
enum HighCardinalityTags implements TagKey {
116+
117+
/**
118+
* A tag containing Cassandra CQL.
119+
*/
120+
CQL_TAG {
121+
@Override
122+
public String getKey() {
123+
return "spring.data.cassandra.cql";
124+
}
125+
}
126+
}
127+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.observability;
17+
18+
import io.micrometer.observation.Observation;
19+
20+
import org.springframework.lang.Nullable;
21+
22+
import com.datastax.oss.driver.api.core.CqlSession;
23+
import com.datastax.oss.driver.api.core.cql.Statement;
24+
25+
/**
26+
* A {@link Observation.Context} for {@link CqlSession}.
27+
*
28+
* @author Greg Turnquist
29+
* @since 4.0.0
30+
*/
31+
public class CqlSessionContext extends Observation.Context {
32+
33+
private final @Nullable Statement<?> statement;
34+
private final String methodName;
35+
private final @Nullable CqlSession delegateSession;
36+
37+
public CqlSessionContext(@Nullable Statement<?> statement, String methodName, @Nullable CqlSession delegateSession) {
38+
39+
this.statement = statement;
40+
this.methodName = methodName;
41+
this.delegateSession = delegateSession;
42+
}
43+
44+
@Nullable
45+
public Statement<?> getStatement() {
46+
return statement;
47+
}
48+
49+
public String getMethodName() {
50+
return methodName;
51+
}
52+
53+
@Nullable
54+
public CqlSession getDelegateSession() {
55+
return delegateSession;
56+
}
57+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.observability;
17+
18+
import io.micrometer.observation.Observation;
19+
20+
/**
21+
* {@link Observation.TagsProvider} for Cassandra.
22+
*
23+
* @author Greg Turnquist
24+
* @since 4.0.0
25+
*/
26+
public interface CqlSessionTagsProvider extends Observation.TagsProvider<CqlSessionContext> {
27+
28+
@Override
29+
default boolean supportsContext(Observation.Context context) {
30+
return context instanceof CqlSessionContext;
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.observability;
17+
18+
import io.micrometer.observation.ObservationRegistry;
19+
20+
import org.springframework.beans.BeansException;
21+
import org.springframework.beans.factory.config.BeanPostProcessor;
22+
23+
import com.datastax.oss.driver.api.core.CqlSession;
24+
25+
/**
26+
* {@link BeanPostProcessor} to automatically wrap all {@link CqlSession}s with a {@link CqlSessionTracingInterceptor}.
27+
*
28+
* @author Marcin Grzejszczak
29+
* @author Mark Paluch
30+
* @author Greg Turnquist
31+
* @since 4.0.0
32+
*/
33+
public class CqlSessionTracingBeanPostProcessor implements BeanPostProcessor {
34+
35+
private final ObservationRegistry observationRegistry;
36+
37+
private final CqlSessionTagsProvider tagsProvider;
38+
39+
public CqlSessionTracingBeanPostProcessor(ObservationRegistry observationRegistry,
40+
CqlSessionTagsProvider tagsProvider) {
41+
42+
this.observationRegistry = observationRegistry;
43+
this.tagsProvider = tagsProvider;
44+
}
45+
46+
@Override
47+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
48+
49+
if (bean instanceof CqlSession) {
50+
return CqlSessionTracingFactory.wrap((CqlSession) bean, this.observationRegistry, this.tagsProvider);
51+
}
52+
53+
return bean;
54+
}
55+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.observability;
17+
18+
import io.micrometer.observation.ObservationRegistry;
19+
20+
import org.springframework.aop.framework.ProxyFactory;
21+
22+
import com.datastax.oss.driver.api.core.CqlSession;
23+
24+
/**
25+
* Factory to wrap a {@link CqlSession} with a {@link CqlSessionTracingInterceptor}.
26+
*
27+
* @author Mark Paluch
28+
* @author Greg Turnquist
29+
* @since 4.0.0
30+
*/
31+
public final class CqlSessionTracingFactory {
32+
33+
private CqlSessionTracingFactory() {
34+
throw new IllegalStateException("Can't instantiate a utility class.");
35+
}
36+
37+
/**
38+
* Wrap the {@link CqlSession} with a {@link CqlSessionTracingInterceptor}.
39+
*
40+
* @param session
41+
* @param observationRegistry
42+
* @param tagsProvider
43+
* @return
44+
*/
45+
public static CqlSession wrap(CqlSession session, ObservationRegistry observationRegistry,
46+
CqlSessionTagsProvider tagsProvider) {
47+
48+
ProxyFactory proxyFactory = new ProxyFactory();
49+
50+
proxyFactory.setTarget(session);
51+
proxyFactory.addAdvice(new CqlSessionTracingInterceptor(session, observationRegistry, tagsProvider));
52+
proxyFactory.addInterface(CqlSession.class);
53+
54+
return (CqlSession) proxyFactory.getProxy();
55+
}
56+
}

0 commit comments

Comments
 (0)