Skip to content

Commit 0e07641

Browse files
committed
Merge branch 'main' into issue-10856
2 parents 2d60508 + fed0015 commit 0e07641

File tree

42 files changed

+1747
-1037
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1747
-1037
lines changed

instrumentation/jdbc/javaagent/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dependencies {
3131
testLibrary("org.apache.tomcat:tomcat-juli:7.0.19")
3232
testLibrary("com.zaxxer:HikariCP:2.4.0")
3333
testLibrary("com.mchange:c3p0:0.9.5")
34+
testLibrary("com.alibaba:druid:1.2.20")
3435

3536
// some classes in earlier versions of derby were split out into derbytools in later versions
3637
latestDepTestLibrary("org.apache.derby:derbytools:latest.release")

instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/datasource/DataSourceInstrumentation.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.opentelemetry.context.Context;
1414
import io.opentelemetry.context.Scope;
1515
import io.opentelemetry.instrumentation.jdbc.internal.JdbcUtils;
16+
import io.opentelemetry.javaagent.bootstrap.CallDepth;
1617
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
1718
import io.opentelemetry.javaagent.bootstrap.jdbc.DbInfo;
1819
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
@@ -33,7 +34,7 @@ public ElementMatcher<TypeDescription> typeMatcher() {
3334
@Override
3435
public void transform(TypeTransformer transformer) {
3536
transformer.applyAdviceToMethod(
36-
named("getConnection").and(returns(named("java.sql.Connection"))),
37+
named("getConnection").and(returns(implementsInterface(named("java.sql.Connection")))),
3738
DataSourceInstrumentation.class.getName() + "$GetConnectionAdvice");
3839
}
3940

@@ -44,7 +45,13 @@ public static class GetConnectionAdvice {
4445
public static void start(
4546
@Advice.This DataSource ds,
4647
@Advice.Local("otelContext") Context context,
47-
@Advice.Local("otelScope") Scope scope) {
48+
@Advice.Local("otelScope") Scope scope,
49+
@Advice.Local("otelCallDepth") CallDepth callDepth) {
50+
callDepth = CallDepth.forClass(DataSource.class);
51+
if (callDepth.getAndIncrement() > 0) {
52+
return;
53+
}
54+
4855
Context parentContext = Java8BytecodeBridge.currentContext();
4956
if (!Java8BytecodeBridge.spanFromContext(parentContext).getSpanContext().isValid()) {
5057
// this instrumentation is already very noisy, and calls to getConnection outside of an
@@ -64,7 +71,12 @@ public static void stopSpan(
6471
@Advice.Return Connection connection,
6572
@Advice.Thrown Throwable throwable,
6673
@Advice.Local("otelContext") Context context,
67-
@Advice.Local("otelScope") Scope scope) {
74+
@Advice.Local("otelScope") Scope scope,
75+
@Advice.Local("otelCallDepth") CallDepth callDepth) {
76+
if (callDepth.decrementAndGet() > 0) {
77+
return;
78+
}
79+
6880
if (scope == null) {
6981
return;
7082
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.jdbc.test;
7+
8+
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
9+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
10+
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
11+
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName;
12+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
13+
import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION;
14+
import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE;
15+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
16+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME;
17+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
18+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
19+
20+
import com.alibaba.druid.pool.DruidDataSource;
21+
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
22+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
23+
import java.sql.Connection;
24+
import java.sql.SQLException;
25+
import javax.sql.DataSource;
26+
import org.junit.jupiter.api.AfterEach;
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.extension.RegisterExtension;
30+
31+
@SuppressWarnings("deprecation") // using deprecated semconv
32+
class DruicDataSourceTest {
33+
34+
@RegisterExtension
35+
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
36+
37+
private DataSource dataSource;
38+
39+
@BeforeEach
40+
void setUp() {
41+
DruidDataSource druidDataSource = new DruidDataSource();
42+
druidDataSource.setUrl("jdbc:h2:mem:test");
43+
druidDataSource.setDriverClassName("org.h2.Driver");
44+
druidDataSource.setUsername("sa");
45+
druidDataSource.setPassword("");
46+
druidDataSource.setMaxActive(1);
47+
this.dataSource = druidDataSource;
48+
}
49+
50+
@AfterEach
51+
void tearDown() {
52+
if (dataSource instanceof DruidDataSource) {
53+
((DruidDataSource) dataSource).close();
54+
}
55+
}
56+
57+
@Test
58+
void testGetConnection() throws SQLException {
59+
// In DruidDataSource we instrument both DruidPooledConnection getConnection() and the bridge
60+
// method Connection getConnection(). Here we call Connection getConnection() that delegates
61+
// to DruidPooledConnection getConnection(), and verify that only one span is created.
62+
testing.runWithSpan(
63+
"parent",
64+
() -> {
65+
try (Connection connection = dataSource.getConnection()) {
66+
return null;
67+
}
68+
});
69+
70+
testing.waitAndAssertTraces(
71+
trace ->
72+
trace.hasSpansSatisfyingExactly(
73+
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
74+
span ->
75+
span.hasName("DruidDataSource.getConnection")
76+
.hasKind(INTERNAL)
77+
.hasParent(trace.getSpan(0))
78+
.hasAttributesSatisfyingExactly(
79+
equalTo(CODE_NAMESPACE, "com.alibaba.druid.pool.DruidDataSource"),
80+
equalTo(CODE_FUNCTION, "getConnection"),
81+
equalTo(
82+
DB_CONNECTION_STRING,
83+
emitStableDatabaseSemconv() ? null : "h2:mem:"),
84+
equalTo(maybeStable(DB_NAME), "test"),
85+
equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName("h2")),
86+
equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"))));
87+
}
88+
}

instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,6 @@ void testGetConnection(
10411041
throws SQLException {
10421042
// Tomcat's pool doesn't work because the getConnection method is
10431043
// implemented in a parent class that doesn't implement DataSource
1044-
boolean recursive = datasource instanceof EmbeddedDataSource;
10451044

10461045
if (init != null) {
10471046
init.accept(datasource);
@@ -1073,14 +1072,6 @@ void testGetConnection(
10731072
.hasKind(SpanKind.INTERNAL)
10741073
.hasParent(trace.getSpan(0))
10751074
.hasAttributesSatisfyingExactly(attributesAssertions)));
1076-
if (recursive) {
1077-
assertions.add(
1078-
span ->
1079-
span.hasName(datasource.getClass().getSimpleName() + ".getConnection")
1080-
.hasKind(SpanKind.INTERNAL)
1081-
.hasParent(trace.getSpan(1))
1082-
.hasAttributesSatisfyingExactly(attributesAssertions));
1083-
}
10841075
trace.hasSpansSatisfyingExactly(assertions);
10851076
});
10861077
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Library Instrumentation for JMX Metrics
2+
3+
Provides OpenTelemetry instrumentation for [Java Management Extensions (JMX)](https://docs.oracle.com/javase/tutorial/jmx/).
4+
5+
This instrumentation collects JMX-based metrics and exports them as OpenTelemetry metrics.
6+
7+
## Quickstart
8+
9+
### Add these dependencies to your project
10+
11+
Replace `OPENTELEMETRY_VERSION` with the [latest release](https://central.sonatype.com/artifact/io.opentelemetry.instrumentation/opentelemetry-jmx-metrics).
12+
13+
For Maven, add to your `pom.xml` dependencies:
14+
15+
```xml
16+
<dependencies>
17+
<dependency>
18+
<groupId>io.opentelemetry.instrumentation</groupId>
19+
<artifactId>opentelemetry-jmx-metrics</artifactId>
20+
<version>OPENTELEMETRY_VERSION</version>
21+
</dependency>
22+
</dependencies>
23+
```
24+
25+
For Gradle, add to your dependencies:
26+
27+
```kotlin
28+
implementation("io.opentelemetry.instrumentation:opentelemetry-jmx-metrics:OPENTELEMETRY_VERSION")
29+
```
30+
31+
### Usage
32+
33+
```java
34+
import io.opentelemetry.api.OpenTelemetry;
35+
import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight;
36+
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
37+
38+
// Get an OpenTelemetry instance
39+
OpenTelemetry openTelemetry = ...;
40+
41+
JmxMetricInsight jmxMetricInsight = JmxMetricInsight.createService(openTelemetry, 5000);
42+
43+
// Configure your JMX metrics
44+
MetricConfiguration config = new MetricConfiguration();
45+
46+
jmxMetricInsight.startLocal(config);
47+
```
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Library Instrumentation for Lettuce version 5.1 and higher
2+
3+
Provides OpenTelemetry instrumentation for [Lettuce](https://lettuce.io/), enabling database client
4+
spans and metrics.
5+
6+
## Quickstart
7+
8+
### Add these dependencies to your project
9+
10+
Replace `OPENTELEMETRY_VERSION` with the [latest release](https://central.sonatype.com/artifact/io.opentelemetry.instrumentation/opentelemetry-lettuce-5.1).
11+
12+
For Maven, add to your `pom.xml` dependencies:
13+
14+
```xml
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.opentelemetry.instrumentation</groupId>
18+
<artifactId>opentelemetry-lettuce-5.1</artifactId>
19+
<version>OPENTELEMETRY_VERSION</version>
20+
</dependency>
21+
</dependencies>
22+
```
23+
24+
For Gradle, add to your dependencies:
25+
26+
```kotlin
27+
implementation("io.opentelemetry.instrumentation:opentelemetry-lettuce-5.1:OPENTELEMETRY_VERSION")
28+
```
29+
30+
### Usage
31+
32+
```java
33+
import io.lettuce.core.RedisClient;
34+
import io.lettuce.core.api.StatefulRedisConnection;
35+
import io.lettuce.core.resource.ClientResources;
36+
import io.opentelemetry.api.OpenTelemetry;
37+
import io.opentelemetry.instrumentation.lettuce.v5_1.LettuceTelemetry;
38+
39+
// Get an OpenTelemetry instance
40+
OpenTelemetry openTelemetry = ...;
41+
42+
LettuceTelemetry lettuceTelemetry = LettuceTelemetry.create(openTelemetry);
43+
44+
ClientResources clientResources = ClientResources.builder()
45+
.tracing(lettuceTelemetry.newTracing())
46+
.build();
47+
48+
RedisClient redisClient = RedisClient.create(clientResources, "redis://localhost:6379");
49+
StatefulRedisConnection<String, String> connection = redisClient.connect();
50+
```
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Library Instrumentation for Netty version 4.1 and higher
2+
3+
Provides OpenTelemetry instrumentation for [Netty](https://netty.io/), enabling HTTP client and
4+
server spans and metrics.
5+
6+
## Quickstart
7+
8+
### Add these dependencies to your project
9+
10+
Replace `OPENTELEMETRY_VERSION` with the [latest release](https://central.sonatype.com/artifact/io.opentelemetry.instrumentation/opentelemetry-netty-4.1).
11+
12+
For Maven, add to your `pom.xml` dependencies:
13+
14+
```xml
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.opentelemetry.instrumentation</groupId>
18+
<artifactId>opentelemetry-netty-4.1</artifactId>
19+
<version>OPENTELEMETRY_VERSION</version>
20+
</dependency>
21+
</dependencies>
22+
```
23+
24+
For Gradle, add to your dependencies:
25+
26+
```kotlin
27+
implementation("io.opentelemetry.instrumentation:opentelemetry-netty-4.1:OPENTELEMETRY_VERSION")
28+
```
29+
30+
### Usage
31+
32+
#### HTTP Client
33+
34+
```java
35+
import io.netty.bootstrap.Bootstrap;
36+
import io.netty.channel.Channel;
37+
import io.netty.channel.ChannelInitializer;
38+
import io.netty.channel.EventLoopGroup;
39+
import io.netty.channel.socket.SocketChannel;
40+
import io.netty.handler.codec.http.HttpClientCodec;
41+
import io.opentelemetry.api.OpenTelemetry;
42+
import io.opentelemetry.context.Context;
43+
import io.opentelemetry.instrumentation.netty.v4_1.NettyClientTelemetry;
44+
45+
// Get an OpenTelemetry instance
46+
OpenTelemetry openTelemetry = ...;
47+
48+
NettyClientTelemetry clientTelemetry = NettyClientTelemetry.create(openTelemetry);
49+
50+
EventLoopGroup eventLoopGroup = ...; // Use appropriate EventLoopGroup for your platform
51+
Class<? extends Channel> channelClass = ...; // Use appropriate Channel class for your platform
52+
53+
Bootstrap bootstrap = new Bootstrap();
54+
bootstrap.group(eventLoopGroup)
55+
.channel(channelClass)
56+
.handler(new ChannelInitializer<SocketChannel>() {
57+
@Override
58+
protected void initChannel(SocketChannel ch) {
59+
ch.pipeline()
60+
.addLast(new HttpClientCodec())
61+
.addLast(clientTelemetry.createCombinedHandler())
62+
.addLast(new YourClientHandler()); // Your application handler
63+
}
64+
});
65+
66+
Channel channel = bootstrap.connect("localhost", 8080).sync().channel();
67+
NettyClientTelemetry.setChannelContext(channel, Context.current());
68+
```
69+
70+
#### HTTP Server
71+
72+
```java
73+
import io.netty.bootstrap.ServerBootstrap;
74+
import io.netty.channel.ChannelInitializer;
75+
import io.netty.channel.EventLoopGroup;
76+
import io.netty.channel.ServerChannel;
77+
import io.netty.channel.socket.SocketChannel;
78+
import io.netty.handler.codec.http.HttpServerCodec;
79+
import io.opentelemetry.api.OpenTelemetry;
80+
import io.opentelemetry.instrumentation.netty.v4_1.NettyServerTelemetry;
81+
82+
// Get an OpenTelemetry instance
83+
OpenTelemetry openTelemetry = ...;
84+
85+
NettyServerTelemetry serverTelemetry = NettyServerTelemetry.create(openTelemetry);
86+
87+
EventLoopGroup bossGroup = ...; // Use appropriate EventLoopGroup for your platform
88+
EventLoopGroup workerGroup = ...; // Use appropriate EventLoopGroup for your platform
89+
Class<? extends ServerChannel> serverChannelClass = ...; // Use appropriate ServerChannel class for your platform
90+
91+
ServerBootstrap bootstrap = new ServerBootstrap();
92+
bootstrap.group(bossGroup, workerGroup)
93+
.channel(serverChannelClass)
94+
.childHandler(new ChannelInitializer<SocketChannel>() {
95+
@Override
96+
protected void initChannel(SocketChannel ch) {
97+
ch.pipeline()
98+
.addLast(new HttpServerCodec())
99+
.addLast(serverTelemetry.createCombinedHandler())
100+
.addLast(new YourServerHandler()); // Your application handler
101+
}
102+
});
103+
104+
bootstrap.bind(8080).sync();
105+
```

0 commit comments

Comments
 (0)