Skip to content

Implement stable semconv for db connection pool metrics #13785

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

Merged
merged 1 commit into from
Apr 30, 2025
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 @@ -27,8 +27,10 @@
*/
public final class DbConnectionPoolMetrics {

static final AttributeKey<String> POOL_NAME = stringKey("pool.name");
static final AttributeKey<String> CONNECTION_STATE = stringKey("state");
static final AttributeKey<String> POOL_NAME =
stringKey(emitStableDatabaseSemconv() ? "db.client.connection.pool.name" : "pool.name");
static final AttributeKey<String> CONNECTION_STATE =
stringKey(emitStableDatabaseSemconv() ? "db.client.connection.state" : "state");

static final String STATE_IDLE = "idle";
static final String STATE_USED = "used";
Expand Down Expand Up @@ -61,42 +63,58 @@ public ObservableLongMeasurement connections() {
emitStableDatabaseSemconv() ? "db.client.connection.count" : "db.client.connections.usage";
return meter
.upDownCounterBuilder(metricName)
.setUnit("{connections}")
.setUnit(emitStableDatabaseSemconv() ? "{connection}" : "{connections}")
.setDescription(
"The number of connections that are currently in state described by the state attribute.")
.buildObserver();
}

public ObservableLongMeasurement minIdleConnections() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.idle.min"
: "db.client.connections.idle.min";
return meter
.upDownCounterBuilder("db.client.connections.idle.min")
.setUnit("{connections}")
.upDownCounterBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "{connection}" : "{connections}")
.setDescription("The minimum number of idle open connections allowed.")
.buildObserver();
}

public ObservableLongMeasurement maxIdleConnections() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.idle.max"
: "db.client.connections.idle.max";
return meter
.upDownCounterBuilder("db.client.connections.idle.max")
.setUnit("{connections}")
.upDownCounterBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "{connection}" : "{connections}")
.setDescription("The maximum number of idle open connections allowed.")
.buildObserver();
}

public ObservableLongMeasurement maxConnections() {
String metricName =
emitStableDatabaseSemconv() ? "db.client.connection.max" : "db.client.connections.max";
return meter
.upDownCounterBuilder("db.client.connections.max")
.setUnit("{connections}")
.upDownCounterBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "{connection}" : "{connections}")
.setDescription("The maximum number of open connections allowed.")
.buildObserver();
}

public ObservableLongMeasurement pendingRequestsForConnection() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.pending_requests"
: "db.client.connections.pending_requests";
return meter
.upDownCounterBuilder("db.client.connections.pending_requests")
.setUnit("{requests}")
.upDownCounterBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "{request}" : "{requests}")
.setDescription(
"The number of pending requests for an open connection, cumulative for the entire pool.")
emitStableDatabaseSemconv()
? "The number of current pending requests for an open connection."
: "The number of pending requests for an open connection, cumulative for the entire pool.")
.buildObserver();
}

Expand All @@ -107,39 +125,51 @@ public BatchCallback batchCallback(
return meter.batchCallback(callback, observableMeasurement, additionalMeasurements);
}

// TODO: should be a BoundLongCounter
public LongCounter connectionTimeouts() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.timeouts"
: "db.client.connections.timeouts";
return meter
.counterBuilder("db.client.connections.timeouts")
.setUnit("{timeouts}")
.counterBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "{timeout}" : "{timeouts}")
.setDescription(
"The number of connection timeouts that have occurred trying to obtain a connection from the pool.")
.build();
}

// TODO: should be a BoundDoubleHistogram
public DoubleHistogram connectionCreateTime() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.create_time"
: "db.client.connections.create_time";
return meter
.histogramBuilder("db.client.connections.create_time")
.setUnit("ms")
.histogramBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "s" : "ms")
.setDescription("The time it took to create a new connection.")
.build();
}

// TODO: should be a BoundDoubleHistogram
public DoubleHistogram connectionWaitTime() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.wait_time"
: "db.client.connections.wait_time";
return meter
.histogramBuilder("db.client.connections.wait_time")
.setUnit("ms")
.histogramBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "s" : "ms")
.setDescription("The time it took to obtain an open connection from the pool.")
.build();
}

// TODO: should be a BoundDoubleHistogram
public DoubleHistogram connectionUseTime() {
String metricName =
emitStableDatabaseSemconv()
? "db.client.connection.use_time"
: "db.client.connections.use_time";
return meter
.histogramBuilder("db.client.connections.use_time")
.setUnit("ms")
.histogramBuilder(metricName)
.setUnit(emitStableDatabaseSemconv() ? "s" : "ms")
.setDescription("The time between borrowing a connection and returning it to the pool.")
.build();
}
Expand Down
10 changes: 10 additions & 0 deletions instrumentation/c3p0-0.9/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ dependencies {

testImplementation(project(":instrumentation:c3p0-0.9:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
10 changes: 10 additions & 0 deletions instrumentation/c3p0-0.9/library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ dependencies {

testImplementation(project(":instrumentation:c3p0-0.9:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
10 changes: 10 additions & 0 deletions instrumentation/hikaricp-3.0/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ dependencies {

testImplementation(project(":instrumentation:hikaricp-3.0:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
10 changes: 10 additions & 0 deletions instrumentation/hikaricp-3.0/library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ dependencies {

testImplementation(project(":instrumentation:hikaricp-3.0:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package io.opentelemetry.instrumentation.hikaricp.v3_0;

import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;

import com.zaxxer.hikari.metrics.IMetricsTracker;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BatchCallback;
Expand All @@ -15,6 +17,8 @@
final class OpenTelemetryMetricsTracker implements IMetricsTracker {

private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1);
private static final double NANOS_PER_S = TimeUnit.SECONDS.toNanos(1);
private static final double MILLIS_PER_S = TimeUnit.SECONDS.toMillis(1);

private final IMetricsTracker userMetricsTracker;

Expand Down Expand Up @@ -44,20 +48,26 @@ final class OpenTelemetryMetricsTracker implements IMetricsTracker {

@Override
public void recordConnectionCreatedMillis(long connectionCreatedMillis) {
createTime.record((double) connectionCreatedMillis, attributes);
double time =
emitStableDatabaseSemconv()
? connectionCreatedMillis / MILLIS_PER_S
: connectionCreatedMillis;
createTime.record(time, attributes);
Copy link
Member

Choose a reason for hiding this comment

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

Related to #12608

I think this should also resolve this comment? 👍

userMetricsTracker.recordConnectionCreatedMillis(connectionCreatedMillis);
}

@Override
public void recordConnectionAcquiredNanos(long elapsedAcquiredNanos) {
double millis = elapsedAcquiredNanos / NANOS_PER_MS;
waitTime.record(millis, attributes);
double time = elapsedAcquiredNanos / (emitStableDatabaseSemconv() ? NANOS_PER_S : NANOS_PER_MS);
waitTime.record(time, attributes);
userMetricsTracker.recordConnectionAcquiredNanos(elapsedAcquiredNanos);
}

@Override
public void recordConnectionUsageMillis(long elapsedBorrowedMillis) {
useTime.record((double) elapsedBorrowedMillis, attributes);
double time =
emitStableDatabaseSemconv() ? elapsedBorrowedMillis / MILLIS_PER_S : elapsedBorrowedMillis;
useTime.record(time, attributes);
userMetricsTracker.recordConnectionUsageMillis(elapsedBorrowedMillis);
}

Expand Down
8 changes: 8 additions & 0 deletions instrumentation/oracle-ucp-11.2/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ tasks {
test {
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
}

val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
8 changes: 8 additions & 0 deletions instrumentation/oracle-ucp-11.2/library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ tasks {
test {
usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
}

val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
10 changes: 10 additions & 0 deletions instrumentation/vibur-dbcp-11.0/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,13 @@ dependencies {

testImplementation(project(":instrumentation:vibur-dbcp-11.0:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
10 changes: 10 additions & 0 deletions instrumentation/vibur-dbcp-11.0/library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ dependencies {

testImplementation(project(":instrumentation:vibur-dbcp-11.0:testing"))
}

tasks {
val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=database")
}

check {
dependsOn(testStableSemconv)
}
}
Loading
Loading