Skip to content

Add Tags support, add Metric.ID #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ public List<Metric.Statistics> collectMetrics() {
log.log(Level.DEBUG, dbMetrics.asJson().withHash(false).withNewLine(false).json());
}
for (MetaTimedMetric timedMetric : dbMetrics.timedMetrics()) {
metrics.add(new TimerStats(timedMetric.name(), timedMetric.count(), timedMetric.total(), timedMetric.max()));
metrics.add(new TimerStats(Metric.ID.of(timedMetric.name()), timedMetric.count(), timedMetric.total(), timedMetric.max()));
}
for (MetaQueryMetric metric : dbMetrics.queryMetrics()) {
metrics.add(new TimerStats(metric.name(), metric.count(), metric.total(), metric.max()));
metrics.add(new TimerStats(Metric.ID.of(metric.name()), metric.count(), metric.total(), metric.max()));
}
for (MetaCountMetric metric : dbMetrics.countMetrics()) {
metrics.add(new CounterStats(metric.name(), metric.count()));
metrics.add(new CounterStats(Metric.ID.of(metric.name()), metric.count()));
}
return metrics;
}
Expand Down
65 changes: 65 additions & 0 deletions metrics/src/main/java/io/avaje/metrics/MId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.avaje.metrics;

import java.util.Objects;

import static java.util.Objects.requireNonNull;

final class MId implements Metric.ID {

private final String name;
private final Tags tags;

MId(String name, Tags tags) {
this.name = name;
this.tags = tags;
}

@Override
public String name() {
return name;
}

@Override
public Tags tags() {
return tags;
}

@Override
public Metric.ID suffix(String suffix) {
return new MId(name + requireNonNull(suffix), tags);
}

@Override
public Metric.ID withName(String otherName) {
if (name.equals(requireNonNull(otherName))) {
return this;
}
return new MId(otherName, tags);
}

@Override
public Metric.ID withTags(Tags otherTags) {
if (tags.equals(requireNonNull(otherTags))) {
return this;
}
return new MId(name, otherTags);
}

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof MId)) return false;
MId key = (MId) object;
return Objects.equals(name, key.name) && Objects.equals(tags, key.tags);
}

@Override
public int hashCode() {
return Objects.hash(name, tags);
}

@Override
public String toString() {
return tags.isEmpty() ? name : name + ' ' + tags;
}
}
46 changes: 46 additions & 0 deletions metrics/src/main/java/io/avaje/metrics/MTags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.avaje.metrics;

import java.util.Arrays;
import java.util.Objects;

final class MTags implements Tags {

static Tags EMPTY = new MTags(new String[]{});

private final String[] keyValuePairs;

MTags(String[] keyValuePairs) {
if (keyValuePairs.length % 2 != 0) {
throw new IllegalArgumentException("Incorrect length, must be pairs of key values");
}
this.keyValuePairs = keyValuePairs;
}

@Override
public boolean isEmpty() {
return keyValuePairs.length == 0;
}

@Override
public String[] array() {
return keyValuePairs;
}

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof MTags)) return false;
MTags dTags = (MTags) object;
return Objects.deepEquals(keyValuePairs, dTags.keyValuePairs);
}

@Override
public int hashCode() {
return Arrays.hashCode(keyValuePairs);
}

@Override
public String toString() {
return keyValuePairs.length == 0 ? "" : "tags:" + Arrays.toString(keyValuePairs);
}
}
63 changes: 59 additions & 4 deletions metrics/src/main/java/io/avaje/metrics/Metric.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
*/
public interface Metric {

/**
* Return the Id of the metric.
*/
ID id();

/**
* Return the name of the metric.
*/
Expand All @@ -28,19 +33,69 @@ public interface Metric {
/**
* Reset the statistics resetting any internal counters etc.
* <p>
* Typically the MetricManager takes care of resetting the statistic/counters for the metrics when
* it periodically collects and reports all the metrics and you are not expected to use this method.
* </p>
* Typically, the MetricRegistry takes care of resetting the statistic/counters for the metrics when
* it periodically collects and reports all the metrics, and you are not expected to use this method.
*/
void reset();

/**
* Identifier of a Metric based on both the name and tags.
*/
interface ID {

/**
* Create an Id given a name only.
*/
static ID of(String name) {
return new MId(name, Tags.EMPTY);
}

/**
* Create an Id given name and tags.
*/
static ID of(String name, Tags tags) {
return new MId(name, tags);
}

/**
* Return the metric name.
*/
String name();

/**
* Return the tags.
*/
Tags tags();

/**
* Return an Id appending the suffix to the name.
*/
ID suffix(String suffix);

/**
* Return an Id with the given name..
*/
ID withName(String otherName);

/**
* Return an Id with the given name..
*/
ID withTags(Tags tags);

}

/**
* Common for statistics of all metrics.
*/
interface Statistics {

/**
* Return the associated metric name.
* Return the metric id.
*/
ID id();

/**
* Return the metric name.
*/
String name();

Expand Down
34 changes: 34 additions & 0 deletions metrics/src/main/java/io/avaje/metrics/MetricRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,51 @@ public interface MetricRegistry extends JvmMetrics {
*/
Counter counter(String name);

/**
* Return the Counter with the given name and tags.
*/
Counter counter(String name, Tags tags);

/**
* Return the Meter using the metric name.
*/
Meter meter(String name);

/**
* Return the Meter using the metric name and tags.
*/
Meter meter(String name, Tags tags);

/**
* Create and register a gauge using the supplied double values.
*/
GaugeDouble gauge(String name, DoubleSupplier supplier);

/**
* Create and register a gauge using the supplied double values.
*/
GaugeDouble gauge(String name, Tags tags, DoubleSupplier supplier);

/**
* Create and register a gauge using the supplied long values.
*/
GaugeLong gauge(String name, LongSupplier supplier);

/**
* Create and register a gauge using the supplied long values.
*/
GaugeLong gauge(String name, Tags tags, LongSupplier supplier);

/**
* Return the timer using the metric name.
*/
Timer timer(String name);

/**
* Return the timer using the metric name and tags.
*/
Timer timer(String name, Tags tags);

/**
* Return the bucket timer using the given base metric name and bucketRanges.
*
Expand All @@ -43,6 +68,15 @@ public interface MetricRegistry extends JvmMetrics {
*/
Timer timer(String name, int... bucketRanges);

/**
* Return the bucket timer using the given base metric name, tags and bucketRanges.
*
* @param name The metric name
* @param tags The metric tags
* @param bucketRanges Time in milliseconds which are used to create buckets.
*/
Timer timer(String name, Tags tags, int... bucketRanges);

/**
* Return the TimerGroup using the given base metric name.
*/
Expand Down
18 changes: 18 additions & 0 deletions metrics/src/main/java/io/avaje/metrics/Tags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.avaje.metrics;

public interface Tags {

Tags EMPTY = MTags.EMPTY;

static Tags of() {
return EMPTY;
}

static Tags of(String... keyValuePairs) {
return new MTags(keyValuePairs);
}

String[] array();

boolean isEmpty();
}
19 changes: 12 additions & 7 deletions metrics/src/main/java/io/avaje/metrics/core/BaseReportName.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@

abstract class BaseReportName {

final String name;
@Nullable String reportName;
final Metric.ID id;
volatile Metric.@Nullable ID reportId;

BaseReportName(String name) {
this.name = name;
BaseReportName(Metric.ID id) {
this.id = id;
}

final String reportName(Metric.Visitor collector) {
final String tmp = collector.namingConvention().apply(name);
this.reportName = tmp;
final Metric.ID reportId(Metric.Visitor collector) {
final var id = reportId;
return id != null ? id : useNamingConvention(collector);
}

final Metric.ID useNamingConvention(Metric.Visitor collector) {
final Metric.ID tmp = id.withName(collector.namingConvention().apply(id.name()));
this.reportId = tmp;
return tmp;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
package io.avaje.metrics.core;

import io.avaje.metrics.Metric;
import io.avaje.metrics.Timer;
import io.avaje.metrics.spi.SpiMetricBuilder;

final class BucketTimerFactory implements SpiMetricBuilder.Factory<Timer> {

@Override
public Timer createMetric(String name, int[] bucketRanges) {
public Timer createMetric(Metric.ID id, int[] bucketRanges) {
int rangeBottom = 0;
Timer[] buckets = new Timer[bucketRanges.length + 1];
for (int i = 0; i < bucketRanges.length; i++) {
int rangeTop = bucketRanges[i];
buckets[i] = createTimedMetric(name, rangeBottom, rangeTop);
buckets[i] = createTimedMetric(id, rangeBottom, rangeTop);
// move the range bottom up to the last rangeTop
rangeBottom = rangeTop;
}
buckets[bucketRanges.length] = createTimedMetric(name, rangeBottom, 0);
return new DBucketTimer(name, bucketRanges, buckets);
buckets[bucketRanges.length] = createTimedMetric(id, rangeBottom, 0);
return new DBucketTimer(id, bucketRanges, buckets);
}

private static Timer createTimedMetric(String name, int rangeBottom, int rangeTop) {
private static Timer createTimedMetric(Metric.ID id, int rangeBottom, int rangeTop) {
String suffix = (rangeTop == 0) ? String.valueOf(rangeBottom) : rangeBottom + "-" + rangeTop;
return new DTimer(name, suffix);
return new DTimer(id, suffix);
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package io.avaje.metrics.core;

import io.avaje.metrics.Counter;
import io.avaje.metrics.Metric;
import io.avaje.metrics.spi.SpiMetricBuilder;

final class CounterFactory implements SpiMetricBuilder.Factory<Counter> {

@Override
public Counter createMetric(String name, int[] bucketRanges) {
return new DCounter(name);
public Counter createMetric(Metric.ID id, int[] bucketRanges) {
return new DCounter(id);
}

}
Loading