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}