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

Implement Vibur DBCP connection pool metrics #6092

Merged
merged 5 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions docs/standalone-library-instrumentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ that can be used if you prefer that over using the Java agent:
* [Spring RestTemplate](../instrumentation/spring/spring-web-3.1/library)
* [Spring Web MVC](../instrumentation/spring/spring-webmvc-3.1/library)
* [Spring WebFlux Client](../instrumentation/spring/spring-webflux-5.0/library)
* [Vibur DBCP](../instrumentation/vibur-dbcp-11.0/library)

And some libraries are publishing their own OpenTelemetry instrumentation (yay!), e.g.

Expand Down
1 change: 1 addition & 0 deletions docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ These are the supported libraries and frameworks:
| [Vert.x HttpClient](https://vertx.io/docs/apidocs/io/vertx/core/http/HttpClient.html) | 3.0+ |
| [Vert.x Kafka Client](https://vertx.io/docs/vertx-kafka-client/java/) | 3.6+ |
| [Vert.x RxJava2](https://vertx.io/docs/vertx-rx/java2/) | 3.5+ |
| [Vibur DBCP](https://www.vibur.org/) | 11.0+ |

## Application Servers

Expand Down
20 changes: 20 additions & 0 deletions instrumentation/vibur-dbcp-11.0/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("org.vibur")
module.set("vibur-dbcp")
versions.set("[11.0,)")
assertInverse.set(true)
}
}

dependencies {
library("org.vibur:vibur-dbcp:11.0")

implementation(project(":instrumentation:vibur-dbcp-11.0:library"))

testImplementation(project(":instrumentation:vibur-dbcp-11.0:testing"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.viburdbcp;

import static io.opentelemetry.javaagent.instrumentation.viburdbcp.ViburSingletons.telemetry;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.vibur.dbcp.ViburDBCPDataSource;

final class ViburDbcpDataSourceInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.vibur.dbcp.ViburDBCPDataSource");
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("start").and(takesArguments(0)), this.getClass().getName() + "$StartAdvice");
transformer.applyAdviceToMethod(
named("close").and(takesArguments(0)), this.getClass().getName() + "$CloseAdvice");
}

@SuppressWarnings("unused")
public static class StartAdvice {

@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.This ViburDBCPDataSource dataSource) {
telemetry().registerMetrics(dataSource);
}
}

@SuppressWarnings("unused")
public static class CloseAdvice {

@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
public static void onExit(@Advice.This ViburDBCPDataSource dataSource) {
telemetry().unregisterMetrics(dataSource);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.viburdbcp;

import static java.util.Collections.singletonList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class ViburDbcpInstrumentationModule extends InstrumentationModule {
public ViburDbcpInstrumentationModule() {
super("vibur-dbcp", "vibur-dbcp-11.0");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ViburDbcpDataSourceInstrumentation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.viburdbcp;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.viburdbcp.ViburTelemetry;

public final class ViburSingletons {

private static final ViburTelemetry viburTelemetry =
ViburTelemetry.create(GlobalOpenTelemetry.get());

public static ViburTelemetry telemetry() {
return viburTelemetry;
}

private ViburSingletons() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.viburdbcp;

import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.viburdbcp.AbstractViburInstrumentationTest;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.vibur.dbcp.ViburDBCPDataSource;

class ViburInstrumentationTest extends AbstractViburInstrumentationTest {

@RegisterExtension
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();

@Override
protected InstrumentationExtension testing() {
return testing;
}

@Override
protected void configure(ViburDBCPDataSource viburDataSource) {}
}
47 changes: 47 additions & 0 deletions instrumentation/vibur-dbcp-11.0/library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Manual Instrumentation for HikariCP
laurit marked this conversation as resolved.
Show resolved Hide resolved

Provides OpenTelemetry instrumentation for [Vibur DBCP](https://www.vibur.org/).

## Quickstart

### Add these dependencies to your project:

Replace `OPENTELEMETRY_VERSION` with the latest stable
[release](https://mvnrepository.com/artifact/io.opentelemetry). `Minimum version: 1.15.0`

For Maven, add to your `pom.xml` dependencies:

```xml

<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-viburdbcp-11.0</artifactId>
<version>OPENTELEMETRY_VERSION</version>
</dependency>
</dependencies>
```

For Gradle, add to your dependencies:

```groovy
implementation("io.opentelemetry.instrumentation:opentelemetry-viburdbcp-11.0:OPENTELEMETRY_VERSION")
```

### Usage

The instrumentation library allows registering `ViburDBCPDataSource` instances for collecting
OpenTelemetry-based metrics.

```java
ViburTelemetry viburTelemetry;

void configure(OpenTelemetry openTelemetry, ViburDBCPDataSource viburDataSource) {
viburTelemetry = ViburTelemetry.create(openTelemetry);
viburTelemetry.registerMetrics(viburDataSource);
}

void destroy(ViburDBCPDataSource viburDataSource) {
viburTelemetry.unregisterMetrics(viburDataSource);
}
```
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
@@ -0,0 +1,10 @@
plugins {
id("otel.library-instrumentation")
id("otel.nullaway-conventions")
}

dependencies {
library("org.vibur:vibur-dbcp:11.0")

testImplementation(project(":instrumentation:vibur-dbcp-11.0:testing"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.viburdbcp;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
import io.opentelemetry.instrumentation.api.metrics.db.DbConnectionPoolMetrics;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.vibur.dbcp.ViburDBCPDataSource;

final class ConnectionPoolMetrics {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.viburdbcp-11.0";

// a weak map does not make sense here because each Meter holds a reference to the dataSource
// ViburDBCPDataSource does not implement equals()/hashCode(), so it's safe to keep them in a
// plain ConcurrentHashMap
private static final Map<ViburDBCPDataSource, List<ObservableLongUpDownCounter>>
dataSourceMetrics = new ConcurrentHashMap<>();

public static void registerMetrics(OpenTelemetry openTelemetry, ViburDBCPDataSource dataSource) {
dataSourceMetrics.computeIfAbsent(
dataSource, (unused) -> createMeters(openTelemetry, dataSource));
}

private static List<ObservableLongUpDownCounter> createMeters(
OpenTelemetry openTelemetry, ViburDBCPDataSource dataSource) {
DbConnectionPoolMetrics metrics =
DbConnectionPoolMetrics.create(openTelemetry, INSTRUMENTATION_NAME, dataSource.getName());

return Arrays.asList(
metrics.usedConnections(() -> dataSource.getPool().taken()),
metrics.idleConnections(() -> dataSource.getPool().remainingCreated()),
Comment on lines +37 to +38
Copy link
Member

Choose a reason for hiding this comment

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

we may want to rethink the DbConnectionPoolMetrics API after batch recording is available in 1.15.0

metrics.maxConnections(dataSource::getPoolMaxSize));
}

public static void unregisterMetrics(ViburDBCPDataSource dataSource) {
List<ObservableLongUpDownCounter> observableInstruments = dataSourceMetrics.remove(dataSource);
if (observableInstruments != null) {
for (ObservableLongUpDownCounter observable : observableInstruments) {
observable.close();
}
}
}

private ConnectionPoolMetrics() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.viburdbcp;

import io.opentelemetry.api.OpenTelemetry;
import org.vibur.dbcp.ViburDBCPDataSource;

/** Entrypoint for instrumenting Hikari database connection pools. */
laurit marked this conversation as resolved.
Show resolved Hide resolved
public final class ViburTelemetry {

/** Returns a new {@link ViburTelemetry} configured with the given {@link OpenTelemetry}. */
public static ViburTelemetry create(OpenTelemetry openTelemetry) {
return new ViburTelemetry(openTelemetry);
}

private final OpenTelemetry openTelemetry;

private ViburTelemetry(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
}

/** Start collecting metrics for given data source. */
public void registerMetrics(ViburDBCPDataSource dataSource) {
ConnectionPoolMetrics.registerMetrics(openTelemetry, dataSource);
}

/** Stop collecting metrics for given data source. */
public void unregisterMetrics(ViburDBCPDataSource dataSource) {
ConnectionPoolMetrics.unregisterMetrics(dataSource);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.viburdbcp;

import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.vibur.dbcp.ViburDBCPDataSource;

class ViburInstrumentationTest extends AbstractViburInstrumentationTest {

@RegisterExtension
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();

@RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create();

@Override
protected InstrumentationExtension testing() {
return testing;
}

@Override
protected void configure(ViburDBCPDataSource viburDataSource) {
ViburTelemetry telemetry = ViburTelemetry.create(testing().getOpenTelemetry());
telemetry.registerMetrics(viburDataSource);
cleanup.deferCleanup(() -> telemetry.unregisterMetrics(viburDataSource));
}
}
11 changes: 11 additions & 0 deletions instrumentation/vibur-dbcp-11.0/testing/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("otel.java-conventions")
}

dependencies {
api(project(":testing-common"))
api("org.mockito:mockito-core")
api("org.mockito:mockito-junit-jupiter")

compileOnly("org.vibur:vibur-dbcp:11.0")
}
Loading