Skip to content

Commit

Permalink
Add JdbcTelemetry and JdbcTelemetryBuilder (#9685)
Browse files Browse the repository at this point in the history
  • Loading branch information
hannahchan authored Oct 17, 2023
1 parent 3b08db7 commit 2a554bd
Show file tree
Hide file tree
Showing 10 changed files with 264 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion instrumentation/jdbc/library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -66,12 +66,29 @@ public OpenTelemetryDataSource(DataSource delegate) {
* @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);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
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
Expand All @@ -30,19 +34,38 @@ public static Instrumenter<DbRequest, Void> createStatementInstrumenter() {

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() {}
}
Original file line number Diff line number Diff line change
@@ -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;"))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down Expand Up @@ -67,8 +67,8 @@ void shouldEmitGetConnectionSpans(GetConnectionFunction getConnection) throws SQ
@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);

Expand Down
Loading

0 comments on commit 2a554bd

Please sign in to comment.