io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of micrometer-core Show documentation
Show all versions of micrometer-core Show documentation
Core module of Micrometer containing instrumentation API and implementation
/*
* Copyright 2019 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micrometer.core.instrument.binder.mongodb;
import com.mongodb.client.MongoClient;
import com.mongodb.connection.ServerId;
import com.mongodb.event.*;
import io.micrometer.core.annotation.Incubating;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.lang.NonNullApi;
import io.micrometer.core.lang.NonNullFields;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* {@link ConnectionPoolListener} for collecting connection pool metrics from
* {@link MongoClient}.
*
* @author Christophe Bornet
* @author Jonatan Ivanov
* @since 1.2.0
* @implNote This implementation requires MongoDB Java driver 4 or later.
*/
@NonNullApi
@NonNullFields
@Incubating(since = "1.2.0")
public class MongoMetricsConnectionPoolListener implements ConnectionPoolListener {
private static final String METRIC_PREFIX = "mongodb.driver.pool.";
private final Map poolSizes = new ConcurrentHashMap<>();
private final Map checkedOutCounts = new ConcurrentHashMap<>();
private final Map waitQueueSizes = new ConcurrentHashMap<>();
private final Map> meters = new ConcurrentHashMap<>();
private final MeterRegistry registry;
private final MongoConnectionPoolTagsProvider tagsProvider;
/**
* Create a new {@code MongoMetricsConnectionPoolListener}.
* @param registry registry to use
*/
public MongoMetricsConnectionPoolListener(MeterRegistry registry) {
this(registry, new DefaultMongoConnectionPoolTagsProvider());
}
/**
* Create a new {@code MongoMetricsConnectionPoolListener}.
* @param registry registry to use
* @param tagsProvider tags provider to use
* @since 1.7.0
*/
public MongoMetricsConnectionPoolListener(MeterRegistry registry, MongoConnectionPoolTagsProvider tagsProvider) {
this.registry = registry;
this.tagsProvider = tagsProvider;
}
@Override
public void connectionPoolCreated(ConnectionPoolCreatedEvent event) {
List connectionMeters = new ArrayList<>();
connectionMeters.add(registerGauge(event, METRIC_PREFIX + "size",
"the current size of the connection pool, including idle and and in-use members", poolSizes));
connectionMeters.add(registerGauge(event, METRIC_PREFIX + "checkedout",
"the count of connections that are currently in use", checkedOutCounts));
connectionMeters.add(registerGauge(event, METRIC_PREFIX + "waitqueuesize",
"the current size of the wait queue for a connection from the pool", waitQueueSizes));
meters.put(event.getServerId(), connectionMeters);
}
@Override
public void connectionPoolClosed(ConnectionPoolClosedEvent event) {
ServerId serverId = event.getServerId();
for (Meter meter : meters.get(serverId)) {
registry.remove(meter);
}
meters.remove(serverId);
poolSizes.remove(serverId);
checkedOutCounts.remove(serverId);
waitQueueSizes.remove(serverId);
}
@Override
public void connectionCheckOutStarted(ConnectionCheckOutStartedEvent event) {
AtomicInteger waitQueueSize = waitQueueSizes.get(event.getServerId());
if (waitQueueSize != null) {
waitQueueSize.incrementAndGet();
}
}
@Override
public void connectionCheckedOut(ConnectionCheckedOutEvent event) {
AtomicInteger checkedOutCount = checkedOutCounts.get(event.getConnectionId().getServerId());
if (checkedOutCount != null) {
checkedOutCount.incrementAndGet();
}
AtomicInteger waitQueueSize = waitQueueSizes.get(event.getConnectionId().getServerId());
if (waitQueueSize != null) {
waitQueueSize.decrementAndGet();
}
}
@Override
public void connectionCheckOutFailed(ConnectionCheckOutFailedEvent event) {
AtomicInteger waitQueueSize = waitQueueSizes.get(event.getServerId());
if (waitQueueSize != null) {
waitQueueSize.decrementAndGet();
}
}
@Override
public void connectionCheckedIn(ConnectionCheckedInEvent event) {
AtomicInteger checkedOutCount = checkedOutCounts.get(event.getConnectionId().getServerId());
if (checkedOutCount != null) {
checkedOutCount.decrementAndGet();
}
}
@Override
public void connectionCreated(ConnectionCreatedEvent event) {
AtomicInteger poolSize = poolSizes.get(event.getConnectionId().getServerId());
if (poolSize != null) {
poolSize.incrementAndGet();
}
}
@Override
public void connectionClosed(ConnectionClosedEvent event) {
AtomicInteger poolSize = poolSizes.get(event.getConnectionId().getServerId());
if (poolSize != null) {
poolSize.decrementAndGet();
}
}
private Gauge registerGauge(ConnectionPoolCreatedEvent event, String metricName, String description,
Map metrics) {
AtomicInteger value = new AtomicInteger();
metrics.put(event.getServerId(), value);
return Gauge.builder(metricName, value, AtomicInteger::doubleValue).description(description)
.tags(tagsProvider.connectionPoolTags(event)).register(registry);
}
}