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

io.helidon.metrics.api.NoOpMeter Maven / Gradle / Ivy

There is a newer version: 4.1.4
Show newest version
/*
 * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
 *
 * 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
 *
 *     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 io.helidon.metrics.api;

import java.io.PrintStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;

/**
 * No-op implementation of the Helidon {@link io.helidon.metrics.api.Meter} interface.
 *
 * 

* It's a big class, but it's fairly nicely organized and it keeps the no-op meter implementations * from cluttering up the containing directory as separate classes. *

*/ class NoOpMeter implements Meter, NoOpWrapper { private final Id id; private final String unit; private final String description; private final Type type; private final String scope; private NoOpMeter(NoOpMeter.Builder builder) { this(new NoOpMeter.Id(builder.name, builder.tags), builder.unit, builder.description, builder.type, builder.scope); } private NoOpMeter(Id id, String baseUnit, String description, Type type, String scope) { this.id = id; this.unit = Objects.requireNonNullElse(baseUnit, ""); this.description = Objects.requireNonNullElse(description, ""); this.type = type; this.scope = scope; } static Map tagsMap(Iterable tags) { var result = new TreeMap(); tags.forEach(tag -> result.put(tag.key(), tag.value())); return result; } @Override public Id id() { return id; } @Override public Optional baseUnit() { return Optional.ofNullable(unit); } @Override public Optional description() { return Optional.ofNullable(description); } @Override public Type type() { return type; } @Override public Optional scope() { return Optional.ofNullable(scope); } private static NoOpMeter.Id create(NoOpMeter.Builder builder) { return new NoOpMeter.Id(builder.name(), builder.tags()); } static class Id implements Meter.Id { private final String name; private final List tags = new ArrayList<>(); // must be ordered by tag name for consistency private Id(String name, Map tags) { this.name = name; tags.forEach((k, v) -> this.tags.add(Tag.create(k, v))); this.tags.sort(Comparator.comparing(Tag::key)); } static Id create(String name, Map tags) { return new Id(name, tags); } @Override public String name() { return name; } @Override public List tags() { return Collections.unmodifiableList(tags); } String tag(String key) { return tags.stream() .filter(t -> t.key().equals(key)) .map(Tag::value) .findFirst() .orElse(null); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Id id = (Id) o; return name.equals(id.name) && tags.equals(id.tags); } @Override public int hashCode() { return Objects.hash(name, tags); } } abstract static class Builder, M extends Meter> implements Wrapper { private final String name; private final Map tags = new TreeMap<>(); // tree map for ordering by tag name private final Type type; private String description; private String unit; private String scope; private Builder(String name, Type type) { this.name = name; this.type = type; } abstract M build(); public B tags(Iterable tags) { tags.forEach(tag -> this.tags.put(tag.key(), tag.value())); return identity(); } public B addTag(Tag tag) { tags.put(tag.key(), tag.value()); return identity(); } public B description(String description) { this.description = description; return identity(); } public B baseUnit(String unit) { this.unit = unit; return identity(); } public B scope(String scope) { this.scope = scope; return identity(); } public B identity() { return (B) this; } public String name() { return name; } public Map tags() { return new TreeMap<>(tags); } public Optional baseUnit() { return Optional.ofNullable(unit); } public Optional description() { return Optional.ofNullable(description); } public Optional scope() { return Optional.ofNullable(scope); } @Override public R unwrap(Class c) { return c.cast(this); } } static class Counter extends NoOpMeter implements io.helidon.metrics.api.Counter { protected Counter(Builder builder) { super(builder); } static Counter create(String name, Iterable tags) { return builder(name) .tags(tags) .build(); } static Counter.Builder builder(String name) { return new Builder(name); } @Override public void increment() { } @Override public void increment(long amount) { } @Override public long count() { return 0L; } static class Builder extends NoOpMeter.Builder implements io.helidon.metrics.api.Counter.Builder { protected Builder(String name) { super(name, Type.COUNTER); } @Override public Counter build() { return new NoOpMeter.Counter(this); } } } static class FunctionalCounter extends NoOpMeter implements io.helidon.metrics.api.FunctionalCounter { private FunctionalCounter(Builder builder) { super(builder); } static FunctionalCounter.Builder builder(String name, T target, Function fn) { return new FunctionalCounter.Builder<>(name, target, fn); } @Override public long count() { return 0; } static class Builder extends NoOpMeter.Builder, FunctionalCounter> implements io.helidon.metrics.api.FunctionalCounter.Builder { private final T stateObject; private final Function fn; private Builder(String name, T stateObject, Function fn) { super(name, Type.COUNTER); this.stateObject = stateObject; this.fn = fn; } @Override public T stateObject() { return stateObject; } @Override public Function fn() { return fn; } @Override public FunctionalCounter build() { return new FunctionalCounter(this); } } } static class DistributionSummary extends NoOpMeter implements io.helidon.metrics.api.DistributionSummary { private DistributionSummary(Builder builder) { super(builder); } static DistributionSummary.Builder builder(String name) { return new DistributionSummary.Builder(name); } @Override public void record(double amount) { } @Override public long count() { return 0; } @Override public double totalAmount() { return 0; } @Override public double mean() { return 0; } @Override public double max() { return 0; } @Override public io.helidon.metrics.api.HistogramSnapshot snapshot() { return new NoOpMeter.HistogramSnapshot(0L, 0D, 0D); } static class Builder extends NoOpMeter.Builder implements io.helidon.metrics.api.DistributionSummary.Builder { private static final double DEFAULT_SCALE = 1.0D; private io.helidon.metrics.api.DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder; private Double scale; private boolean publishPercentileHistogram; private Builder(String name) { super(name, Type.DISTRIBUTION_SUMMARY); } @Override public DistributionSummary build() { return new DistributionSummary(this); } @Override public Builder scale(double scale) { this.scale = scale; return identity(); } @Override public Builder distributionStatisticsConfig( io.helidon.metrics.api.DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder) { this.distributionStatisticsConfigBuilder = distributionStatisticsConfigBuilder; return identity(); } @Override public io.helidon.metrics.api.DistributionSummary.Builder publishPercentileHistogram(boolean value) { this.publishPercentileHistogram = value; return identity(); } @Override public Optional scale() { return Optional.ofNullable(scale); } @Override public Optional distributionStatisticsConfig() { return Optional.ofNullable(distributionStatisticsConfigBuilder); } @Override public Optional publishPercentileHistogram() { return Optional.ofNullable(publishPercentileHistogram); } } } static class HistogramSnapshot implements io.helidon.metrics.api.HistogramSnapshot, NoOpWrapper { private final long count; private final double total; private final double max; private HistogramSnapshot(long count, double total, double max) { this.count = count; this.total = total; this.max = max; } static HistogramSnapshot empty(long count, double total, double max) { return new HistogramSnapshot(count, total, max); } @Override public long count() { return count; } @Override public double total() { return total; } @Override public double total(TimeUnit timeUnit) { return timeUnit.convert((long) total, TimeUnit.NANOSECONDS); } @Override public double max() { return max; } @Override public double mean() { return total / count; } @Override public double mean(TimeUnit timeUnit) { return timeUnit.convert((long) mean(), TimeUnit.NANOSECONDS); } @Override public Iterable percentileValues() { return Set.of(); } @Override public Iterable histogramCounts() { return Set.of(); } @Override public void outputSummary(PrintStream out, double scale) { } } abstract static class Gauge extends NoOpMeter implements io.helidon.metrics.api.Gauge { protected Gauge(NoOpMeter.Gauge.Builder builder) { super(builder); } static Builder.DoubleFunctionBased builder(String name, T stateObject, ToDoubleFunction fn) { return new Builder.DoubleFunctionBased<>(name, stateObject, fn); } static Builder.SupplierBased builder(String name, Supplier supplier) { return new Builder.SupplierBased<>(name, supplier); } abstract static class Builder, N extends Number> extends NoOpMeter.Builder> implements io.helidon.metrics.api.Gauge.Builder { protected Builder(String name) { super(name, Type.GAUGE); } static class DoubleFunctionBased extends Builder, Double> { private final T stateObject; private final ToDoubleFunction fn; private DoubleFunctionBased(String name, T stateObject, ToDoubleFunction fn) { super(name); this.stateObject = stateObject; this.fn = fn; } @Override Gauge build() { return new Gauge<>(this) { @Override public Double value() { return fn.applyAsDouble(stateObject); } }; } @Override public Supplier supplier() { return () -> fn.applyAsDouble(stateObject); } } static class SupplierBased extends Builder, N> { private final Supplier supplier; private SupplierBased(String name, Supplier supplier) { super(name); this.supplier = supplier; } @Override Gauge build() { return new Gauge<>(this) { @Override public N value() { return supplier.get(); } }; } @Override public Supplier supplier() { return supplier; } } } } static class Timer extends NoOpMeter implements io.helidon.metrics.api.Timer { private Timer(Builder builder) { super(builder); } static Sample start() { return new Sample(); } static Sample start(MeterRegistry meterRegistry) { return new Sample(); } static Sample start(Clock clock) { return new Sample(); } static Builder builder(String name) { return new Builder(name); } @Override public io.helidon.metrics.api.HistogramSnapshot snapshot() { return null; } @Override public void record(long amount, TimeUnit unit) { } @Override public void record(Duration duration) { } @Override public T record(Supplier f) { return null; } @Override public T record(Callable f) throws Exception { return f.call(); } @Override public void record(Runnable f) { f.run(); } @Override public Runnable wrap(Runnable f) { return f; } @Override public Callable wrap(Callable f) { return f; } @Override public Supplier wrap(Supplier f) { return null; } @Override public long count() { return 0; } @Override public double totalTime(TimeUnit unit) { return 0; } @Override public double mean(TimeUnit unit) { return 0; } @Override public double max(TimeUnit unit) { return 0; } static class Sample implements io.helidon.metrics.api.Timer.Sample { private Sample() { } @Override public long stop(io.helidon.metrics.api.Timer timer) { return 0; } } static class Builder extends NoOpMeter.Builder implements io.helidon.metrics.api.Timer.Builder { private double[] percentiles; private Duration[] buckets; private Duration min; private Duration max; private Boolean publishPercentileHistogram; private Builder(String name) { super(name, Type.TIMER); } @Override public Timer build() { return new Timer(this); } @Override public Builder percentiles(double... percentiles) { this.percentiles = percentiles; return identity(); } @Override public Builder buckets(Duration... buckets) { this.buckets = buckets; return identity(); } @Override public Builder minimumExpectedValue(Duration min) { this.min = min; return identity(); } @Override public Builder maximumExpectedValue(Duration max) { this.max = max; return identity(); } @Override public io.helidon.metrics.api.Timer.Builder publishPercentileHistogram(boolean value) { publishPercentileHistogram = value; return identity(); } @Override public Iterable percentiles() { return Arrays.stream(percentiles) .boxed().toList(); } @Override public Iterable buckets() { return List.of(buckets); } @Override public Optional minimumExpectedValue() { return Optional.ofNullable(min); } @Override public Optional maximumExpectedValue() { return Optional.ofNullable(max); } @Override public Optional publishPercentileHistogram() { return Optional.ofNullable(publishPercentileHistogram); } } } static class DistributionStatisticsConfig implements io.helidon.metrics.api.DistributionStatisticsConfig, NoOpWrapper { private DistributionStatisticsConfig(DistributionStatisticsConfig.Builder builder) { } static Builder builder() { return new Builder(); } @Override public Optional> percentiles() { return Optional.empty(); } @Override public Optional minimumExpectedValue() { return Optional.empty(); } @Override public Optional maximumExpectedValue() { return Optional.empty(); } @Override public Optional> buckets() { return Optional.empty(); } static class Builder implements io.helidon.metrics.api.DistributionStatisticsConfig.Builder, NoOpWrapper { @Override public io.helidon.metrics.api.DistributionStatisticsConfig build() { return new DistributionStatisticsConfig(this); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder minimumExpectedValue(Double min) { return identity(); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder maximumExpectedValue(Double max) { return identity(); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder percentiles(double... percentiles) { return identity(); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder percentiles(Iterable percentiles) { return identity(); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder buckets(double... buckets) { return identity(); } @Override public io.helidon.metrics.api.DistributionStatisticsConfig.Builder buckets(Iterable buckets) { return identity(); } @Override public Optional minimumExpectedValue() { return Optional.empty(); } @Override public Optional maximumExpectedValue() { return Optional.empty(); } @Override public Iterable percentiles() { return Set.of(); } @Override public Iterable buckets() { return Set.of(); } } } }