io.smallrye.graphql.cdi.metrics.MPMetricsService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smallrye-graphql-cdi Show documentation
Show all versions of smallrye-graphql-cdi Show documentation
Allow lookup up of GraphQL Beans via CDI
package io.smallrye.graphql.cdi.metrics;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.enterprise.util.AnnotationLiteral;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.Tag;
import org.eclipse.microprofile.metrics.annotation.RegistryType;
import org.jboss.logging.Logger;
import io.smallrye.graphql.api.Context;
import io.smallrye.graphql.schema.model.OperationType;
import io.smallrye.graphql.spi.MetricsService;
/**
* Listening for event and create metrics from it. Uses MP Metrics 3.x API.
*
* @author Jan Martiska ([email protected])
* @author Phillip Kruger ([email protected])
*/
public class MPMetricsService implements MetricsService {
private MetricRegistry metricRegistry;
private final Map> metricsMemory = new ConcurrentHashMap<>();
private final Map subscriptions = new ConcurrentHashMap<>();
private static final String METRIC_NAME = "mp_graphql";
private static final String METRIC_SUBSCRIPTIONS = "mp_graphql_subscription";
private Logger LOG = Logger.getLogger(MPMetricsService.class);
public MPMetricsService() {
// If MP Metrics are not available, this will throw an exception
// and make sure that this service doesn't get registered
getMetricRegistry();
}
private MetricRegistry getMetricRegistry() {
if (metricRegistry == null) {
this.metricRegistry = CDI.current().select(MetricRegistry.class, new VendorType()).get();
}
return metricRegistry;
}
private Tag[] getTags(MetricMeasurement metricMeasurement) {
return new Tag[] {
new Tag("name", metricMeasurement.getName()),
new Tag("type", metricMeasurement.getOperationType()),
new Tag("source", String.valueOf(metricMeasurement.isSource()))
};
}
@Override
public void start(Long measurementId, Context context) {
metricsMemory.put(measurementId, new MetricMeasurement<>(context.getFieldName(),
context.hasSource(),
context.getOperationType(),
System.nanoTime()));
LOG.tracef("(" + measurementId + ") Started recording metrics for: %s", context.getFieldName());
}
@Override
public void end(Long measurementId) {
MetricMeasurement metricMeasurement = metricsMemory.remove(measurementId);
long duration = System.nanoTime() - metricMeasurement.getMetric();
getMetricRegistry().simpleTimer(METRIC_NAME, getTags(metricMeasurement))
.update(Duration.ofNanos(duration));
LOG.tracef("(" + measurementId + ") Finished recording metrics for: %s", metricMeasurement.getName());
}
@Override
public void subscriptionStart(Context context) {
if (!OperationType.SUBSCRIPTION.name().equals(context.getOperationType())) {
return;
}
subscriptions.computeIfAbsent(context.getFieldName(), k -> new AtomicLong(0));
subscriptions.get(context.getFieldName()).incrementAndGet();
getMetricRegistry().gauge(
METRIC_SUBSCRIPTIONS,
() -> subscriptions.get(context.getFieldName()).get(),
new Tag("name", context.getFieldName()));
}
@Override
public void subscriptionEnd(Context context) {
if (!OperationType.SUBSCRIPTION.name().equals(context.getOperationType())) {
return;
}
Optional.ofNullable(subscriptions.get(context.getFieldName())).ifPresent(AtomicLong::decrementAndGet);
}
class VendorType extends AnnotationLiteral implements RegistryType {
@Override
public MetricRegistry.Type type() {
return MetricRegistry.Type.VENDOR;
}
}
}