Add JdbcTelemetry and JdbcTelemetryBuilder (#9685)
This commit is contained in:
parent
3b08db75cd
commit
2a554bd153
|
@ -5,7 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.jdbc;
|
||||
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceInstrumenterFactory.createDataSourceInstrumenter;
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createDataSourceInstrumenter;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
|
@ -27,7 +27,7 @@ public final class JdbcSingletons {
|
|||
|
||||
private static final Instrumenter<DbRequest, Void> STATEMENT_INSTRUMENTER;
|
||||
public static final Instrumenter<DataSource, DbInfo> DATASOURCE_INSTRUMENTER =
|
||||
createDataSourceInstrumenter(GlobalOpenTelemetry.get());
|
||||
createDataSourceInstrumenter(GlobalOpenTelemetry.get(), true);
|
||||
|
||||
static {
|
||||
JdbcAttributesGetter dbAttributesGetter = new JdbcAttributesGetter();
|
||||
|
|
|
@ -57,7 +57,7 @@ public class DataSourceConfig {
|
|||
dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/example");
|
||||
dataSource.setUsername("postgres");
|
||||
dataSource.setPassword("root");
|
||||
return new OpenTelemetryDataSource(dataSource);
|
||||
return JdbcTelemetry.create(openTelemetry).wrap(dataSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.jdbc.datasource;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.jdbc.internal.DbRequest;
|
||||
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/** Entrypoint for instrumenting a JDBC DataSources. */
|
||||
public final class JdbcTelemetry {
|
||||
|
||||
/** Returns a new {@link JdbcTelemetry} configured with the given {@link OpenTelemetry}. */
|
||||
public static JdbcTelemetry create(OpenTelemetry openTelemetry) {
|
||||
return builder(openTelemetry).build();
|
||||
}
|
||||
|
||||
/** Returns a new {@link JdbcTelemetryBuilder} configured with the given {@link OpenTelemetry}. */
|
||||
public static JdbcTelemetryBuilder builder(OpenTelemetry openTelemetry) {
|
||||
return new JdbcTelemetryBuilder(openTelemetry);
|
||||
}
|
||||
|
||||
private final Instrumenter<DataSource, DbInfo> dataSourceInstrumenter;
|
||||
private final Instrumenter<DbRequest, Void> statementInstrumenter;
|
||||
|
||||
JdbcTelemetry(
|
||||
Instrumenter<DataSource, DbInfo> dataSourceInstrumenter,
|
||||
Instrumenter<DbRequest, Void> statementInstrumenter) {
|
||||
this.dataSourceInstrumenter = dataSourceInstrumenter;
|
||||
this.statementInstrumenter = statementInstrumenter;
|
||||
}
|
||||
|
||||
public DataSource wrap(DataSource dataSource) {
|
||||
return new OpenTelemetryDataSource(
|
||||
dataSource, this.dataSourceInstrumenter, this.statementInstrumenter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.jdbc.datasource;
|
||||
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory;
|
||||
|
||||
/** A builder of {@link JdbcTelemetry}. */
|
||||
public final class JdbcTelemetryBuilder {
|
||||
|
||||
private final OpenTelemetry openTelemetry;
|
||||
private boolean dataSourceInstrumenterEnabled = true;
|
||||
private boolean statementInstrumenterEnabled = true;
|
||||
private boolean statementSanitizationEnabled = true;
|
||||
|
||||
JdbcTelemetryBuilder(OpenTelemetry openTelemetry) {
|
||||
this.openTelemetry = openTelemetry;
|
||||
}
|
||||
|
||||
/** Configures whether spans are created for JDBC Connections. Enabled by default. */
|
||||
@CanIgnoreReturnValue
|
||||
public JdbcTelemetryBuilder setDataSourceInstrumenterEnabled(boolean enabled) {
|
||||
this.dataSourceInstrumenterEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Configures whether spans are created for JDBC Statements. Enabled by default. */
|
||||
@CanIgnoreReturnValue
|
||||
public JdbcTelemetryBuilder setStatementInstrumenterEnabled(boolean enabled) {
|
||||
this.statementInstrumenterEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Configures whether JDBC Statements are sanitized. Enabled by default. */
|
||||
@CanIgnoreReturnValue
|
||||
public JdbcTelemetryBuilder setStatementSanitizationEnabled(boolean enabled) {
|
||||
this.statementSanitizationEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a new {@link JdbcTelemetry} with the settings of this {@link JdbcTelemetryBuilder}. */
|
||||
public JdbcTelemetry build() {
|
||||
return new JdbcTelemetry(
|
||||
JdbcInstrumenterFactory.createDataSourceInstrumenter(
|
||||
openTelemetry, dataSourceInstrumenterEnabled),
|
||||
JdbcInstrumenterFactory.createStatementInstrumenter(
|
||||
openTelemetry, statementInstrumenterEnabled, statementSanitizationEnabled));
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.jdbc.datasource;
|
||||
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.DataSourceInstrumenterFactory.createDataSourceInstrumenter;
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createDataSourceInstrumenter;
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.createStatementInstrumenter;
|
||||
import static io.opentelemetry.instrumentation.jdbc.internal.JdbcUtils.computeDbInfo;
|
||||
|
||||
|
@ -66,12 +66,29 @@ public class OpenTelemetryDataSource implements DataSource, AutoCloseable {
|
|||
* @param delegate the DataSource to wrap
|
||||
* @param openTelemetry the OpenTelemetry instance to setup for
|
||||
*/
|
||||
@Deprecated
|
||||
public OpenTelemetryDataSource(DataSource delegate, OpenTelemetry openTelemetry) {
|
||||
this.delegate = delegate;
|
||||
this.dataSourceInstrumenter = createDataSourceInstrumenter(openTelemetry);
|
||||
this.dataSourceInstrumenter = createDataSourceInstrumenter(openTelemetry, true);
|
||||
this.statementInstrumenter = createStatementInstrumenter(openTelemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a OpenTelemetry DataSource wrapping another DataSource.
|
||||
*
|
||||
* @param delegate the DataSource to wrap
|
||||
* @param dataSourceInstrumenter the DataSource Instrumenter to use
|
||||
* @param statementInstrumenter the Statement Instrumenter to use
|
||||
*/
|
||||
OpenTelemetryDataSource(
|
||||
DataSource delegate,
|
||||
Instrumenter<DataSource, DbInfo> dataSourceInstrumenter,
|
||||
Instrumenter<DbRequest, Void> statementInstrumenter) {
|
||||
this.delegate = delegate;
|
||||
this.dataSourceInstrumenter = dataSourceInstrumenter;
|
||||
this.statementInstrumenter = statementInstrumenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
Connection connection = wrapCall(delegate::getConnection);
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.jdbc.internal;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
public final class DataSourceInstrumenterFactory {
|
||||
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc";
|
||||
|
||||
public static Instrumenter<DataSource, DbInfo> createDataSourceInstrumenter(
|
||||
OpenTelemetry openTelemetry) {
|
||||
DataSourceCodeAttributesGetter getter = DataSourceCodeAttributesGetter.INSTANCE;
|
||||
return Instrumenter.<DataSource, DbInfo>builder(
|
||||
openTelemetry, INSTRUMENTATION_NAME, CodeSpanNameExtractor.create(getter))
|
||||
.addAttributesExtractor(CodeAttributesExtractor.create(getter))
|
||||
.addAttributesExtractor(DataSourceDbAttributesExtractor.INSTANCE)
|
||||
.buildInstrumenter();
|
||||
}
|
||||
|
||||
private DataSourceInstrumenterFactory() {}
|
||||
}
|
|
@ -9,10 +9,14 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
|
|||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.network.ServerAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil;
|
||||
import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
|
@ -30,19 +34,38 @@ public final class JdbcInstrumenterFactory {
|
|||
|
||||
public static Instrumenter<DbRequest, Void> createStatementInstrumenter(
|
||||
OpenTelemetry openTelemetry) {
|
||||
return createStatementInstrumenter(
|
||||
openTelemetry,
|
||||
true,
|
||||
ConfigPropertiesUtil.getBoolean(
|
||||
"otel.instrumentation.common.db-statement-sanitizer.enabled", true));
|
||||
}
|
||||
|
||||
public static Instrumenter<DbRequest, Void> createStatementInstrumenter(
|
||||
OpenTelemetry openTelemetry, boolean enabled, boolean statementSanitizationEnabled) {
|
||||
return Instrumenter.<DbRequest, Void>builder(
|
||||
openTelemetry,
|
||||
INSTRUMENTATION_NAME,
|
||||
DbClientSpanNameExtractor.create(dbAttributesGetter))
|
||||
.addAttributesExtractor(
|
||||
SqlClientAttributesExtractor.builder(dbAttributesGetter)
|
||||
.setStatementSanitizationEnabled(
|
||||
ConfigPropertiesUtil.getBoolean(
|
||||
"otel.instrumentation.common.db-statement-sanitizer.enabled", true))
|
||||
.setStatementSanitizationEnabled(statementSanitizationEnabled)
|
||||
.build())
|
||||
.addAttributesExtractor(ServerAttributesExtractor.create(netAttributesGetter))
|
||||
.setEnabled(enabled)
|
||||
.buildInstrumenter(SpanKindExtractor.alwaysClient());
|
||||
}
|
||||
|
||||
public static Instrumenter<DataSource, DbInfo> createDataSourceInstrumenter(
|
||||
OpenTelemetry openTelemetry, boolean enabled) {
|
||||
DataSourceCodeAttributesGetter getter = DataSourceCodeAttributesGetter.INSTANCE;
|
||||
return Instrumenter.<DataSource, DbInfo>builder(
|
||||
openTelemetry, INSTRUMENTATION_NAME, CodeSpanNameExtractor.create(getter))
|
||||
.addAttributesExtractor(CodeAttributesExtractor.create(getter))
|
||||
.addAttributesExtractor(DataSourceDbAttributesExtractor.INSTANCE)
|
||||
.setEnabled(enabled)
|
||||
.buildInstrumenter();
|
||||
}
|
||||
|
||||
private JdbcInstrumenterFactory() {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.jdbc.datasource;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.semconv.SemanticAttributes;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class JdbcTelemetryTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Test
|
||||
void buildWithDefaults() throws SQLException {
|
||||
JdbcTelemetry telemetry = JdbcTelemetry.builder(testing.getOpenTelemetry()).build();
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent", () -> dataSource.getConnection().createStatement().execute("SELECT 1;"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("parent"),
|
||||
span -> span.hasName("TestDataSource.getConnection"),
|
||||
span ->
|
||||
span.hasName("SELECT dbname")
|
||||
.hasAttribute(equalTo(SemanticAttributes.DB_STATEMENT, "SELECT ?;"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithAllInstrumentersDisabled() throws SQLException {
|
||||
JdbcTelemetry telemetry =
|
||||
JdbcTelemetry.builder(testing.getOpenTelemetry())
|
||||
.setDataSourceInstrumenterEnabled(false)
|
||||
.setStatementInstrumenterEnabled(false)
|
||||
.build();
|
||||
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent", () -> dataSource.getConnection().createStatement().execute("SELECT 1;"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("parent")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithDataSourceInstrumenterDisabled() throws SQLException {
|
||||
JdbcTelemetry telemetry =
|
||||
JdbcTelemetry.builder(testing.getOpenTelemetry())
|
||||
.setDataSourceInstrumenterEnabled(false)
|
||||
.build();
|
||||
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent", () -> dataSource.getConnection().createStatement().execute("SELECT 1;"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("parent"), span -> span.hasName("SELECT dbname")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithStatementInstrumenterDisabled() throws SQLException {
|
||||
JdbcTelemetry telemetry =
|
||||
JdbcTelemetry.builder(testing.getOpenTelemetry())
|
||||
.setStatementInstrumenterEnabled(false)
|
||||
.build();
|
||||
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent", () -> dataSource.getConnection().createStatement().execute("SELECT 1;"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("parent"),
|
||||
span -> span.hasName("TestDataSource.getConnection")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithSanitizationDisabled() throws SQLException {
|
||||
JdbcTelemetry telemetry =
|
||||
JdbcTelemetry.builder(testing.getOpenTelemetry())
|
||||
.setStatementSanitizationEnabled(false)
|
||||
.build();
|
||||
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent", () -> dataSource.getConnection().createStatement().execute("SELECT 1;"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("parent"),
|
||||
span -> span.hasName("TestDataSource.getConnection"),
|
||||
span ->
|
||||
span.hasName("SELECT dbname")
|
||||
.hasAttribute(equalTo(SemanticAttributes.DB_STATEMENT, "SELECT 1;"))));
|
||||
}
|
||||
}
|
|
@ -35,8 +35,8 @@ class OpenTelemetryDataSourceTest {
|
|||
@ParameterizedTest
|
||||
@ArgumentsSource(GetConnectionMethods.class)
|
||||
void shouldEmitGetConnectionSpans(GetConnectionFunction getConnection) throws SQLException {
|
||||
OpenTelemetryDataSource dataSource =
|
||||
new OpenTelemetryDataSource(new TestDataSource(), testing.getOpenTelemetry());
|
||||
JdbcTelemetry telemetry = JdbcTelemetry.create(testing.getOpenTelemetry());
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
Connection connection = testing.runWithSpan("parent", () -> getConnection.call(dataSource));
|
||||
|
||||
|
@ -67,8 +67,8 @@ class OpenTelemetryDataSourceTest {
|
|||
@ArgumentsSource(GetConnectionMethods.class)
|
||||
void shouldNotEmitGetConnectionSpansWithoutParentSpan(GetConnectionFunction getConnection)
|
||||
throws SQLException {
|
||||
OpenTelemetryDataSource dataSource =
|
||||
new OpenTelemetryDataSource(new TestDataSource(), testing.getOpenTelemetry());
|
||||
JdbcTelemetry telemetry = JdbcTelemetry.create(testing.getOpenTelemetry());
|
||||
DataSource dataSource = telemetry.wrap(new TestDataSource());
|
||||
|
||||
Connection connection = getConnection.call(dataSource);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package io.opentelemetry.spring.smoketest;
|
||||
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.jdbc.datasource.OpenTelemetryDataSource;
|
||||
import io.opentelemetry.instrumentation.jdbc.datasource.JdbcTelemetry;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -22,6 +22,6 @@ public class DatasourceConfig {
|
|||
dataSource.setUrl("jdbc:h2:mem:db");
|
||||
dataSource.setUsername("username");
|
||||
dataSource.setPassword("pwd");
|
||||
return new OpenTelemetryDataSource(dataSource, openTelemetry);
|
||||
return JdbcTelemetry.create(openTelemetry).wrap(dataSource);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue