001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.metrics;
020
021import io.micrometer.core.instrument.Meter;
022import io.micrometer.core.instrument.MeterRegistry;
023import io.micrometer.core.instrument.Tags;
024import io.micrometer.core.instrument.Timer;
025import io.micrometer.core.instrument.Counter;
026import io.micrometer.core.instrument.Gauge;
027import io.micrometer.core.instrument.search.Search;
028
029import java.time.Duration;
030import java.util.Arrays;
031import java.util.Objects;
032import java.util.concurrent.Callable;
033import java.util.concurrent.locks.Lock;
034import java.util.concurrent.locks.ReentrantLock;
035import java.util.function.Supplier;
036
037public class MeterFactory {
038    private static final Lock metersLock = new ReentrantLock();
039
040    public static Timer timer(MeterRegistry registry, MeterInfo meterInfo, Tags tags) {
041        return createMeter(registry, meterInfo, tags,
042          () -> Timer.builder(meterInfo.id()).tags(meterInfo.add(tags)).description(meterInfo.description())
043            .publishPercentiles(0.5, 0.95)
044            .publishPercentileHistogram()
045            .minimumExpectedValue(Duration.ofMillis(1))
046            .maximumExpectedValue(Duration.ofSeconds(60))
047            .register(registry));
048    }
049
050    public static Counter counter(MeterRegistry registry, MeterInfo meterInfo, Tags tags) {
051        return createMeter(registry, meterInfo, tags,
052          () -> Counter.builder(meterInfo.id()).tags(meterInfo.add(tags)).description(meterInfo.description()).register(registry));
053    }
054
055    public static Counter updateCounter(MeterRegistry registry, String meterName, Tags tags, String description) {
056        return Counter.builder(meterName).tags(tags).description(description).register(registry);
057    }
058
059    public static Counter updateCounter(MeterRegistry registry, MeterInfo meterInfo, Tags tags) {
060        return updateCounter(registry, meterInfo.id(), meterInfo.add(tags), meterInfo.description());
061    }
062
063    public static Gauge gauge(MeterRegistry registry, MeterInfo meterInfo, Tags tags, String unit, Supplier<Number> n) {
064        return createMeter(registry, meterInfo, tags,
065          () -> Gauge.builder(meterInfo.id(), n)
066            .tags(meterInfo.add(tags))
067            .description(meterInfo.description())
068            .baseUnit(unit)
069            .register(registry));
070    }
071
072    public static void remove  (MeterRegistry registry, Meter... meters) {
073        Arrays.stream(meters).filter(Objects::nonNull).forEach(registry::remove);
074    }
075
076    @SuppressWarnings("unchecked")
077    private static <T extends Meter> T createMeter(MeterRegistry registry, MeterInfo meterInfo, Tags tags, Callable<T> creator) {
078        metersLock.lock();
079        try {
080            T meter = (T) Search.in(registry).name(meterInfo.id()).tags(meterInfo.add(tags)).meter();
081            if (meter == null) {
082                try {
083                    meter = creator.call();
084                } catch (Exception e) {
085                    throw new RuntimeException (e);
086                }
087            }
088            return meter;
089        } finally {
090            metersLock.unlock();
091        }
092    }
093}