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 Vert.x pool metrics to Quarkus Micrometer #29805

Merged
merged 2 commits into from
Dec 14, 2022
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 @@ -10,6 +10,7 @@
import io.vertx.core.net.SocketAddress;
import io.vertx.core.spi.VertxMetricsFactory;
import io.vertx.core.spi.metrics.HttpServerMetrics;
import io.vertx.core.spi.metrics.PoolMetrics;
import io.vertx.core.spi.metrics.VertxMetrics;

public class VertxMeterBinderAdapter extends MetricsOptions implements VertxMetricsFactory, VertxMetrics {
Expand Down Expand Up @@ -55,4 +56,10 @@ public MetricsOptions newOptions() {
}
return null;
}

@Override
public PoolMetrics<?> createPoolMetrics(String poolType, String poolName, int maxPoolSize) {
return new VertxPoolMetrics(Metrics.globalRegistry, poolType, poolName, maxPoolSize);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package io.quarkus.micrometer.runtime.binder.vertx;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Supplier;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import io.vertx.core.spi.metrics.PoolMetrics;

/**
* Adaptation of the Vert.x Pool Metrics implementation for Quarkus Micrometer.
*/
public class VertxPoolMetrics implements PoolMetrics<VertxPoolMetrics.EventTiming> {

private final String poolType;
private final int maxPoolSize;

private final Timer usage;
private final AtomicReference<Double> ratio = new AtomicReference<>();
private final LongAdder current = new LongAdder();
private final LongAdder queue = new LongAdder();
private final Counter completed;
private final Timer queueDelay;

VertxPoolMetrics(MeterRegistry registry, String poolType, String poolName, int maxPoolSize) {
this.poolType = poolType;
this.maxPoolSize = maxPoolSize;

Tags tags = Tags.of(Tag.of("pool.type", poolType), Tag.of("pool.name", poolName));

queueDelay = Timer.builder(name("queue.delay"))
.description("Time spent in the waiting queue before being processed")
.tags(tags)
.register(registry);

usage = Timer.builder(name("usage"))
.description("Time spent using resources from the pool")
.tags(tags)
.register(registry);

Gauge.builder(name("queue.size"), new Supplier<Number>() {
@Override
public Number get() {
return queue.doubleValue();
}
})
.description("Number of pending elements in the waiting queue")
.tags(tags)
.strongReference(true)
.register(registry);

Gauge.builder(name("active"), new Supplier<Number>() {
@Override
public Number get() {
return current.doubleValue();
}
})
.description("The number of resources from the pool currently used")
.tags(tags)
.strongReference(true)
.register(registry);

if (maxPoolSize > 0) {
Gauge.builder(name("idle"), new Supplier<Number>() {
@Override
public Number get() {
return maxPoolSize - current.doubleValue();
}
})
.description("The number of resources from the pool currently used")
.tags(tags)
.strongReference(true)
.register(registry);

Gauge.builder(name("ratio"), ratio::get)
.description("Pool usage ratio")
.tags(tags)
.strongReference(true)
.register(registry);
}

completed = Counter.builder(name("completed"))
.description("Number of times resources from the pool have been acquired")
.tags(tags)
.register(registry);

}

private String name(String suffix) {
return poolType + ".pool." + suffix;
}

@Override
public EventTiming submitted() {
queue.increment();
return new EventTiming(queueDelay);
}

@Override
public void rejected(EventTiming submitted) {
queue.decrement();
submitted.end();
}

@Override
public EventTiming begin(EventTiming submitted) {
queue.decrement();
submitted.end();
current.increment();
computeRatio(current.longValue());
return new EventTiming(usage);
}

@Override
public void end(EventTiming timer, boolean succeeded) {
current.decrement();
computeRatio(current.longValue());
timer.end();

completed.increment();
}

@Override
public void close() {
}

private void computeRatio(long inUse) {
if (maxPoolSize > 0) {
ratio.set((double) inUse / maxPoolSize);
}
}

public static class EventTiming {
private final long nanoStart;
private final Timer timer;

private EventTiming(Timer timer) {
this.timer = timer;
this.nanoStart = System.nanoTime();
}

public void end() {
timer.record(System.nanoTime() - nanoStart, TimeUnit.NANOSECONDS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ public static Redis create(String name, Vertx vertx, RedisClientConfig config) {
options.setPassword(config.password.orElse(null));
config.poolCleanerInterval.ifPresent(d -> options.setPoolCleanerInterval((int) d.toMillis()));
options.setPoolRecycleTimeout((int) config.poolRecycleTimeout.toMillis());
// TODO Pool name?

options.setPoolName(name);

config.role.ifPresent(options::setRole);
options.setType(config.clientType);
Expand Down