All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.eventmesh.metrics.prometheus.PrometheusMetricsRegistryManager Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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
 *
 *     http://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 org.apache.eventmesh.metrics.prometheus;

import org.apache.eventmesh.common.Pair;
import org.apache.eventmesh.metrics.api.model.InstrumentFurther;
import org.apache.eventmesh.metrics.api.model.InstrumentType;
import org.apache.eventmesh.metrics.api.model.Metric;
import org.apache.eventmesh.metrics.api.model.ObservableMetric;
import org.apache.eventmesh.metrics.api.model.SyncMetric;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleUpDownCounter;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.View;

import lombok.experimental.UtilityClass;

/**
 * Registering and handling Prometheus metrics.
 */
@UtilityClass
public class PrometheusMetricsRegistryManager {

    private static final Map meterCache = new ConcurrentHashMap<>(32);

    private static final Map> metricCache = new ConcurrentHashMap<>(16);

    /**
     * Registers a metric in the metric cache.
     *
     * @param metric The metric to register.
     */
    public static void registerMetric(final Metric metric) {
        Set metrics = metricCache.computeIfAbsent(metric.getName(), (k) -> new HashSet<>());
        metrics.add(metric);
    }

    /**
     * Retrieves the metrics associated with a given metric name.
     *
     * @param metricName The name of the metric.
     * @return The set of metrics associated with the metric name.
     */
    protected static Set getMetrics(final String metricName) {
        return metricCache.get(metricName);
    }

    /**
     * Creates and associates metrics with a Prometheus meter using the provided OpenTelemetry instance.
     *
     * @param openTelemetry The OpenTelemetry instance.
     */
    public static void createMetric(final OpenTelemetry openTelemetry) {

        metricCache.values().stream().flatMap(metricSet -> metricSet.stream()).forEach(metric -> {
            Meter meter = meterCache.computeIfAbsent(metric.getName(), (meterName) -> openTelemetry.getMeter(meterName));
            InstrumentFurther instrumentFurther = metric.getInstrumentFurther();
            if (instrumentFurther == null) {
                instrumentFurther = new InstrumentFurther();
            }

            // Handle observable metrics
            if (metric instanceof ObservableMetric) {
                handleObservableMetric((ObservableMetric) metric, meter, instrumentFurther);
                return;
            }

            // Handle sync metrics
            if (metric instanceof SyncMetric) {
                handleMetric((SyncMetric) metric, meter, instrumentFurther);
            }
        });
    }

    /**
     * Retrieves the list of metrics and their corresponding views.
     *
     * @return The list of metric views.
     */
    public static List> getMetricsView() {
        Collection> metricSetCollection = metricCache.values();
        return metricSetCollection.stream().map(
            metricSet -> metricSet.stream().map(metric -> {
                InstrumentFurther instrumentFurther = metric.getInstrumentFurther();
                if (!Objects.nonNull(instrumentFurther)) {
                    return null;
                }
                Map ext = instrumentFurther.getExt();
                if (!Objects.nonNull(ext)) {
                    return null;
                }
                return (Pair) ext.get(InstrumentFurther.INSTRUMENT_VIEW);
            }).filter(pair -> pair != null).collect(Collectors.toList())).flatMap(viewSet -> viewSet.stream()).collect(Collectors.toList());
    }

    /**
     * Handles the creation of a sync metric based on its instrument type.
     *
     * @param metric            The sync metric.
     * @param meter             The Prometheus meter.
     * @param instrumentFurther Additional instrument information.
     */
    private static void handleMetric(final SyncMetric metric, final Meter meter, final InstrumentFurther instrumentFurther) {
        InstrumentType instrumentType = metric.getInstrumentType();
        switch (instrumentType) {
            case LONG_COUNTER: {
                LongCounter counter = meter.counterBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(counter);
                break;
            }
            case DOUBLE_COUNTER: {
                DoubleCounter counter = meter.counterBuilder(instrumentFurther.getName())
                    .ofDoubles()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(counter);
                break;
            }
            case LONG_HISTOGRAM: {
                LongHistogram histogram = meter.histogramBuilder(instrumentFurther.getName())
                    .ofLongs()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(histogram);
                break;
            }
            case DOUBLE_HISTOGRAM: {
                DoubleHistogram histogram = meter.histogramBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(histogram);
                break;
            }
            case LONG_UP_DOWN_COUNTER: {
                LongUpDownCounter counter = meter.upDownCounterBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(counter);
                break;
            }
            case DOUBLE_UP_DOWN_COUNTER: {
                DoubleUpDownCounter counter = meter.upDownCounterBuilder(instrumentFurther.getName())
                    .ofDoubles()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .build();
                metric.setInstrument(counter);
                break;
            }
            default:
                throw new IllegalArgumentException(String.format("%s not Support", instrumentType.getType().getName()));
        }
    }

    /**
     * Handles the observable metric based on the type of the instrument.
     *
     * @param observableMetric     The observable metric that needs to be handled.
     * @param meter                The meter object used to build the instrument.
     * @param instrumentFurther    The instrument further which contains the name, description and unit of the instrument.
     */
    private static void handleObservableMetric(final ObservableMetric observableMetric, final Meter meter,
        final InstrumentFurther instrumentFurther) {
        InstrumentType instrumentType = observableMetric.getInstrumentType();
        Attributes attributes = buildAttributes(observableMetric);
        switch (instrumentType) {
            case OBSERVABLE_LONG_GAUGE: {
                meter.gaugeBuilder(instrumentFurther.getName())
                    .ofLongs()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));
                break;
            }
            case OBSERVABLE_DOUBLE_GAUGE: {
                meter.gaugeBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));
                break;
            }
            case OBSERVABLE_LONG_COUNTER: {
                meter.counterBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));

                break;
            }
            case OBSERVABLE_DOUBLE_COUNTER: {
                meter.counterBuilder(instrumentFurther.getName())
                    .ofDoubles()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));

                break;
            }
            case OBSERVABLE_LONG_UP_DOWN_COUNTER: {
                meter.upDownCounterBuilder(instrumentFurther.getName())
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Long) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));
                break;
            }
            case OBSERVABLE_DOUBLE_UP_DOWN_COUNTER: {
                meter.upDownCounterBuilder(instrumentFurther.getName())
                    .ofDoubles()
                    .setDescription(instrumentFurther.getDescription())
                    .setUnit(instrumentFurther.getUnit())
                    .buildWithCallback(
                        measurement -> measurement.record((Double) Objects.requireNonNull(observableMetric.supplier()).get(), attributes));

                break;
            }
            default:
        }
    }

    /**
     * Builds the attributes for an ObservableMetric.
     *
     * @param observableMetric The ObservableMetric from which to retrieve the attributes.
     * @return The built attributes.
     */
    private static Attributes buildAttributes(ObservableMetric observableMetric) {
        Map attributes = observableMetric.getAttributes();
        AttributesBuilder builder = Attributes.builder();
        attributes.forEach(builder::put);
        return builder.build();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy