Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JdbcTelemetry and JdbcTelemetryBuilder #9685

Merged
merged 4 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
hannahchan marked this conversation as resolved.
Show resolved Hide resolved
.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
Loading