Skip to content
Draft
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 @@ -28,6 +28,7 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -59,6 +60,8 @@ public class JDBCDecorator extends DatabaseClientDecorator<DBInfo> {
DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_FULL);
public static final boolean DBM_TRACE_PREPARED_STATEMENTS =
Config.get().isDbmTracePreparedStatements();
private static final boolean FETCH_DB_METADATA = Config.get().isDbMetadataFetchingEnabled();
private static final boolean FETCH_DB_CLIENT_INFO = Config.get().isDbClientInfoFetchingEnabled();

private volatile boolean warnedAboutDBMPropagationMode = false; // to log a warning only once

Expand Down Expand Up @@ -181,7 +184,7 @@ public static DBInfo parseDBInfo(
} catch (Throwable ignore) {
}
if (dbInfo == null) {
// couldn't find DBInfo anywhere, so fall back to default
// couldn't find DBInfo from a previous call anywhere, so we try to fetch it from the DB
dbInfo = parseDBInfoFromConnection(connection);
}
// store the DBInfo on the outermost connection instance to avoid future searches
Expand All @@ -200,7 +203,7 @@ public String getDbService(final DBInfo dbInfo) {
}

public static DBInfo parseDBInfoFromConnection(final Connection connection) {
if (connection == null) {
if (connection == null || !FETCH_DB_METADATA) {
// we can log here, but it risks to be too verbose
return DBInfo.DEFAULT;
}
Expand All @@ -209,16 +212,21 @@ public static DBInfo parseDBInfoFromConnection(final Connection connection) {
final DatabaseMetaData metaData = connection.getMetaData();
final String url;
if (metaData != null && (url = metaData.getURL()) != null) {
try {
dbInfo = JDBCConnectionUrlParser.extractDBInfo(url, connection.getClientInfo());
} catch (final Throwable ex) {
// getClientInfo is likely not allowed.
dbInfo = JDBCConnectionUrlParser.extractDBInfo(url, null);
Properties clientInfo = null;
if (FETCH_DB_CLIENT_INFO) {
try {
clientInfo = connection.getClientInfo();
} catch (final Throwable ex) {
// getClientInfo is likely not allowed, we can still extract info from the url alone
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make sense to put some debug/trace log? Just thinking out loud.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean for investigation in the current case, or in general ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could help for investigation in the current case! I have no scale for how often this method is called though -- would adding debug statements here be "okay" in a production environment where we don't want to spam logs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a log, we'll need to make sure this is not merged to main if we want to keep the feature flags for further investigations

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool thanks! I'll add a do not merge tag for now to remind us

log.debug("Could not get client info from DB", ex);
}
}
dbInfo = JDBCConnectionUrlParser.extractDBInfo(url, clientInfo);
} else {
dbInfo = DBInfo.DEFAULT;
}
} catch (final SQLException se) {
log.debug("Could not get metadata from DB", se);
dbInfo = DBInfo.DEFAULT;
}
return dbInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_INFO_FETCHING_ENABLED
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_METADATA_FETCHING_ENABLED

import datadog.trace.agent.test.InstrumentationSpecification
import datadog.trace.bootstrap.instrumentation.jdbc.DBInfo
import datadog.trace.instrumentation.jdbc.JDBCDecorator
import java.sql.Connection
import test.TestDatabaseMetaData

/**
* Base test class for parseDBInfoFromConnection with different flag configurations
*/
abstract class JDBCDecoratorParseDBInfoTestBase extends InstrumentationSpecification {

def "test parseDBInfoFromConnection with null connection"() {
when:
def result = JDBCDecorator.parseDBInfoFromConnection(null)

then:
result == DBInfo.DEFAULT
}

def "test parseDBInfoFromConnection with null ClientInfo"() {
setup:
def metadata = new TestDatabaseMetaData()
metadata.setURL("jdbc:postgresql://testhost:5432/testdb")
def connection = Mock(Connection) {
getMetaData() >> metadata
getClientInfo() >> null
}

when:
def result = JDBCDecorator.parseDBInfoFromConnection(connection)

then:
if (shouldFetchMetadata()) {
result.type == "postgresql"
result.host == "testhost"
result.port == 5432
result.db == "testdb"
} else {
result == DBInfo.DEFAULT
}
}

def "test parseDBInfoFromConnection regular case"() {
setup:
def metadata = new TestDatabaseMetaData()
metadata.setURL("jdbc:postgresql://testhost:5432/testdb")
def clientInfo = new Properties()
clientInfo.setProperty("warehouse", "my-test-warehouse") // we'll check that property to know if clientInfo were used
def connection = Mock(Connection) {
getMetaData() >> (shouldFetchMetadata() ? metadata : { assert false })
getClientInfo() >> (shouldFetchClientInfo() ? clientInfo : { assert false })
}

when:
def result = JDBCDecorator.parseDBInfoFromConnection(connection)

then:
if (shouldFetchMetadata()) {
result.type == "postgresql"
result.host == "testhost"
result.port == 5432
result.db == "testdb"
if (shouldFetchClientInfo()) { // only if we _also_ fetch metadata
result.warehouse == "my-test-warehouse"
}
else {
result.warehouse == null
}
} else {
result == DBInfo.DEFAULT
}
}

abstract boolean shouldFetchMetadata()

abstract boolean shouldFetchClientInfo()
}

/**
* Test with both flags enabled (default behavior)
*/
class JDBCDecoratorParseDBInfoWithMetadataAndClientInfoForkedTest extends JDBCDecoratorParseDBInfoTestBase {

@Override
void configurePreAgent() {
super.configurePreAgent()
injectSysConfig(DB_METADATA_FETCHING_ENABLED, "true")
injectSysConfig(DB_CLIENT_INFO_FETCHING_ENABLED, "true")
}

@Override
boolean shouldFetchMetadata() {
return true
}

@Override
boolean shouldFetchClientInfo() {
return true
}
}

/**
* Test with both flags disabled
*/
class JDBCDecoratorParseDBInfoWithoutCallsForkedTest extends JDBCDecoratorParseDBInfoTestBase {

@Override
void configurePreAgent() {
super.configurePreAgent()
injectSysConfig(DB_METADATA_FETCHING_ENABLED, "false")
injectSysConfig(DB_CLIENT_INFO_FETCHING_ENABLED, "false")
}

@Override
boolean shouldFetchMetadata() {
return false
}

@Override
boolean shouldFetchClientInfo() {
return false
}
}

/**
* Test with metadata enabled but client info disabled
*/
class JDBCDecoratorParseDBInfoWithMetadataOnlyForkedTest extends JDBCDecoratorParseDBInfoTestBase {

@Override
void configurePreAgent() {
super.configurePreAgent()
injectSysConfig(DB_METADATA_FETCHING_ENABLED, "true")
injectSysConfig(DB_CLIENT_INFO_FETCHING_ENABLED, "false")
}

@Override
boolean shouldFetchMetadata() {
return true
}

@Override
boolean shouldFetchClientInfo() {
return false
}
}

class JDBCDecoratorParseDBInfoWithClientInfoOnlyForkedTest extends JDBCDecoratorParseDBInfoTestBase {

@Override
void configurePreAgent() {
super.configurePreAgent()
injectSysConfig(DB_METADATA_FETCHING_ENABLED, "false")
injectSysConfig(DB_CLIENT_INFO_FETCHING_ENABLED, "true")
}

@Override
boolean shouldFetchMetadata() {
return false
}

@Override
boolean shouldFetchClientInfo() {
return true
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public final class TraceInstrumentationConfig {
"trace.db.client.split-by-instance.type.suffix";
public static final String DB_CLIENT_HOST_SPLIT_BY_HOST = "trace.db.client.split-by-host";

public static final String DB_METADATA_FETCHING_ENABLED = "trace.db.metadata.fetching.enabled";
public static final String DB_CLIENT_INFO_FETCHING_ENABLED =
"trace.db.client.info.fetching.enabled";

public static final String JDBC_PREPARED_STATEMENT_CLASS_NAME =
"trace.jdbc.prepared.statement.class.name";

Expand Down
19 changes: 19 additions & 0 deletions internal-api/src/main/java/datadog/trace/api/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -508,9 +508,11 @@
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_HOST;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_INSTANCE;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_INSTANCE_TYPE_SUFFIX;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_INFO_FETCHING_ENABLED;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_INJECT_SQL_BASEHASH;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_PROPAGATION_MODE_MODE;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_TRACE_PREPARED_STATEMENTS;
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_METADATA_FETCHING_ENABLED;
import static datadog.trace.api.config.TraceInstrumentationConfig.ELASTICSEARCH_BODY_AND_PARAMS_ENABLED;
import static datadog.trace.api.config.TraceInstrumentationConfig.ELASTICSEARCH_BODY_ENABLED;
import static datadog.trace.api.config.TraceInstrumentationConfig.ELASTICSEARCH_PARAMS_ENABLED;
Expand Down Expand Up @@ -1076,6 +1078,8 @@ public static String getHostName() {
private final boolean dbmInjectSqlBaseHash;
private final String dbmPropagationMode;
private final boolean dbmTracePreparedStatements;
private final boolean dbMetadataFetchingEnabled;
private final boolean dbClientInfoFetchingEnabled;

private final boolean dynamicInstrumentationEnabled;
private final String dynamicInstrumentationSnapshotUrl;
Expand Down Expand Up @@ -1626,6 +1630,9 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins
DB_CLIENT_HOST_SPLIT_BY_INSTANCE_TYPE_SUFFIX,
DEFAULT_DB_CLIENT_HOST_SPLIT_BY_INSTANCE_TYPE_SUFFIX);

dbMetadataFetchingEnabled = configProvider.getBoolean(DB_METADATA_FETCHING_ENABLED, true);
dbClientInfoFetchingEnabled = configProvider.getBoolean(DB_CLIENT_INFO_FETCHING_ENABLED, true);

dbClientSplitByHost =
configProvider.getBoolean(
DB_CLIENT_HOST_SPLIT_BY_HOST, DEFAULT_DB_CLIENT_HOST_SPLIT_BY_HOST);
Expand Down Expand Up @@ -3146,6 +3153,14 @@ public boolean isDbClientSplitByHost() {
return dbClientSplitByHost;
}

public boolean isDbMetadataFetchingEnabled() {
return dbMetadataFetchingEnabled;
}

public boolean isDbClientInfoFetchingEnabled() {
return dbClientInfoFetchingEnabled;
}

public Set<String> getSplitByTags() {
return splitByTags;
}
Expand Down Expand Up @@ -5551,6 +5566,10 @@ public String toString() {
+ dbClientSplitByInstanceTypeSuffix
+ ", dbClientSplitByHost="
+ dbClientSplitByHost
+ ", dbMetadataFetchingEnabled="
+ dbMetadataFetchingEnabled
+ ", dbClientInfoFetchingEnabled="
+ dbClientInfoFetchingEnabled
+ ", dbmInjectSqlBaseHash="
+ dbmInjectSqlBaseHash
+ ", dbmPropagationMode="
Expand Down
Loading