Skip to content

Commit bcb260a

Browse files
authored
Merge pull request #87 from avaje/feature/add-global-tags
Add global tags for JVM metrics
2 parents 23c6dde + a07ad36 commit bcb260a

12 files changed

+112
-72
lines changed

metrics/src/main/java/io/avaje/metrics/JvmMetrics.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,19 @@ public interface JvmMetrics {
2525
*/
2626
JvmMetrics withReportChangesOnly();
2727

28+
/**
29+
* Set global tags to use with the JVM metrics.
30+
* <p>
31+
* By default, this will check the HOSTNAME environment variable and
32+
* when set, will use this value with a "pod" tag.
33+
*/
34+
JvmMetrics withGlobalTags(Tags globalTags);
35+
2836
/**
2937
* Set to report the metrics irrespective of whether the metric has changed.
3038
* <p>
3139
* For metrics that generally don't change like max memory or don't change as
32-
* frequently these metrics will be reported every time.
40+
* frequently, these metrics will be reported every time.
3341
* </p>
3442
*/
3543
JvmMetrics withReportAlways();

metrics/src/main/java/io/avaje/metrics/core/DGaugeLong.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ static DGaugeLong of(ID id, LongSupplier supplier, boolean changesOnly) {
1919
return changesOnly ? new ChangesOnly(id, supplier) : new All(id, supplier);
2020
}
2121

22-
static DGaugeLong once(String name, LongSupplier supplier) {
23-
return new Once(name, supplier);
22+
static DGaugeLong once(ID id, LongSupplier supplier) {
23+
return new Once(id, supplier);
2424
}
2525

2626
protected final LongSupplier supplier;
@@ -92,8 +92,8 @@ public void collect(Visitor collector) {
9292

9393
static final class Once extends DGaugeLong {
9494

95-
Once(String name, LongSupplier supplier) {
96-
super(ID.of(name), supplier);
95+
Once(ID id, LongSupplier supplier) {
96+
super(id, supplier);
9797
}
9898

9999
@Override

metrics/src/main/java/io/avaje/metrics/core/DefaultMetricProvider.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public final class DefaultMetricProvider implements SpiMetricProvider {
2525
private final SpiMetricBuilder.Factory<Meter> meterFactory;
2626
private final List<MetricSupplier> suppliers = new ArrayList<>();
2727
private final Object monitor = new Object();
28+
private Tags globalTags;
2829
private boolean withDetails;
2930
private boolean reportChangesOnly;
3031
private Function<String, String> namingConvention = NamingMatch.INSTANCE;
@@ -35,6 +36,7 @@ public DefaultMetricProvider() {
3536
this.timerFactory = builder.timer();
3637
this.meterFactory = builder.meter();
3738
this.counterFactory = builder.counter();
39+
this.globalTags = initGlobalTags();
3840
}
3941

4042
DefaultMetricProvider(DefaultMetricProvider parent) {
@@ -45,6 +47,7 @@ public DefaultMetricProvider() {
4547
this.namingConvention = parent.namingConvention;
4648
this.withDetails = parent.withDetails;
4749
this.reportChangesOnly = parent.reportChangesOnly;
50+
this.globalTags = initGlobalTags();
4851
}
4952

5053
static SpiMetricBuilder initBuilder() {
@@ -56,6 +59,15 @@ static SpiMetricBuilder initBuilder() {
5659
return new DSpiMetricBuilder();
5760
}
5861

62+
private static Tags initGlobalTags() {
63+
String hostname = System.getenv("HOSTNAME");
64+
if (hostname == null || hostname.trim().isEmpty()) {
65+
return Tags.EMPTY;
66+
} else {
67+
return Tags.of("pod:" + hostname.trim());
68+
}
69+
}
70+
5971
/**
6072
* Return true if metric collection should be disabled.
6173
* This has the effect that NOOP metric implementations are used.
@@ -91,6 +103,12 @@ public MetricRegistry namingUnderscore() {
91103
return this;
92104
}
93105

106+
@Override
107+
public JvmMetrics withGlobalTags(Tags globalTags) {
108+
this.globalTags = globalTags;
109+
return this;
110+
}
111+
94112
@Override
95113
public JvmMetrics withReportChangesOnly() {
96114
reportChangesOnly = true;
@@ -123,14 +141,14 @@ public JvmMetrics registerJvmMetrics() {
123141

124142
@Override
125143
public JvmMetrics registerProcessMemoryMetrics() {
126-
JvmProcessMemory.createGauges(this, reportChangesOnly);
144+
JvmProcessMemory.createGauges(this, reportChangesOnly, globalTags);
127145
return this;
128146
}
129147

130148
@Override
131149
public JvmMetrics registerCGroupMetrics() {
132-
JvmCGroupCpu.createGauges(this, reportChangesOnly, withDetails);
133-
JvmCGroupMemory.createGauges(this, reportChangesOnly);
150+
JvmCGroupCpu.createGauges(this, reportChangesOnly, withDetails, globalTags);
151+
JvmCGroupMemory.createGauges(this, reportChangesOnly, globalTags);
134152
return this;
135153
}
136154

@@ -152,15 +170,15 @@ public JvmMetrics registerJvmThreadMetrics() {
152170

153171
@Override
154172
public JvmMetrics registerJvmGCMetrics() {
155-
JvmGarbageCollection.createGauges(this, withDetails);
173+
JvmGarbageCollection.createGauges(this, withDetails, globalTags);
156174
JvmGCPause.createMeters(this);
157175
return this;
158176
}
159177

160178
@Override
161179
public JvmMetrics registerJvmMemoryMetrics() {
162-
JvmMemory.createHeapGroup(this, reportChangesOnly, withDetails);
163-
JvmMemory.createNonHeapGroup(this, reportChangesOnly, withDetails);
180+
JvmMemory.createHeapGroup(this, reportChangesOnly, withDetails, globalTags);
181+
JvmMemory.createNonHeapGroup(this, reportChangesOnly, withDetails, globalTags);
164182
return this;
165183
}
166184

metrics/src/main/java/io/avaje/metrics/core/JvmCGroupCpu.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.avaje.metrics.GaugeLong;
44
import io.avaje.metrics.Metric;
55
import io.avaje.metrics.MetricRegistry;
6+
import io.avaje.metrics.Tags;
67

78
import java.math.RoundingMode;
89
import java.util.Optional;
@@ -12,43 +13,43 @@
1213

1314
final class JvmCGroupCpu {
1415

15-
static void createGauges(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails) {
16-
new JvmCGroupCpu().create(registry, reportChangesOnly, withDetails);
16+
static void createGauges(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
17+
new JvmCGroupCpu().create(registry, reportChangesOnly, withDetails, globalTags);
1718
}
1819

19-
void create(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails) {
20+
void create(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
2021
FileLines cpu = new FileLines("/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage");
2122
if (cpu.exists()) {
22-
createCGroupCpuUsage(registry, cpu);
23+
createCGroupCpuUsage(registry, cpu, globalTags);
2324
}
2425
FileLines cpuStat = new FileLines("/sys/fs/cgroup/cpu,cpuacct/cpu.stat");
2526
if (cpuStat.exists()) {
26-
createCGroupCpuThrottle(registry, cpuStat, reportChangesOnly, withDetails);
27+
createCGroupCpuThrottle(registry, cpuStat, reportChangesOnly, withDetails, globalTags);
2728
}
2829
FileLines cpuShares = new FileLines("/sys/fs/cgroup/cpu,cpuacct/cpu.shares");
2930
if (cpuStat.exists()) {
30-
registry.register(createCGroupCpuRequests(cpuShares));
31+
registry.register(createCGroupCpuRequests(cpuShares, globalTags));
3132
}
3233
FileLines cpuQuota = new FileLines("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us");
3334
FileLines period = new FileLines("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us");
3435
if (cpuQuota.exists() && period.exists()) {
35-
createCGroupCpuLimit(cpuQuota, period).ifPresent(registry::register);
36+
createCGroupCpuLimit(cpuQuota, period, globalTags).ifPresent(registry::register);
3637
}
3738
}
3839

39-
Optional<GaugeLong> createCGroupCpuLimit(FileLines cpuQuota, FileLines period) {
40+
Optional<GaugeLong> createCGroupCpuLimit(FileLines cpuQuota, FileLines period, Tags globalTags) {
4041
final long cpuQuotaVal = cpuQuota.single();
4142
long quotaPeriod = period.single();
4243
if (cpuQuotaVal > 0 && quotaPeriod > 0) {
4344
final long limit = convertQuotaToLimits(cpuQuotaVal, quotaPeriod);
44-
return Optional.of(DGaugeLong.once("jvm.cgroup.cpu.limit", new FixedGauge(limit)));
45+
return Optional.of(DGaugeLong.once(Metric.ID.of("jvm.cgroup.cpu.limit", globalTags), new FixedGauge(limit)));
4546
}
4647
return Optional.empty();
4748
}
4849

49-
GaugeLong createCGroupCpuRequests(FileLines cpuShares) {
50+
GaugeLong createCGroupCpuRequests(FileLines cpuShares, Tags globalTags) {
5051
final long requests = convertSharesToRequests(cpuShares.single());
51-
return DGaugeLong.once("jvm.cgroup.cpu.requests", new FixedGauge(requests));
52+
return DGaugeLong.once(Metric.ID.of("jvm.cgroup.cpu.requests", globalTags), new FixedGauge(requests));
5253
}
5354

5455
long convertQuotaToLimits(long cpuQuotaVal, long quotaPeriod) {
@@ -69,22 +70,22 @@ long convertSharesToRequests(long shares) {
6970
.longValue();
7071
}
7172

72-
private void createCGroupCpuUsage(MetricRegistry registry, FileLines cpu) {
73-
registry.gauge("jvm.cgroup.cpu.usage", new CpuUsage(cpu));
73+
private void createCGroupCpuUsage(MetricRegistry registry, FileLines cpu, Tags globalTags) {
74+
registry.gauge("jvm.cgroup.cpu.usage", globalTags, new CpuUsage(cpu));
7475
}
7576

76-
private void createCGroupCpuThrottle(MetricRegistry registry, FileLines cpuStat, boolean reportChangesOnly, boolean withDetails) {
77+
private void createCGroupCpuThrottle(MetricRegistry registry, FileLines cpuStat, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
7778
final var source = new CpuStatsSource(cpuStat);
78-
registry.register(gauge("jvm.cgroup.cpu.throttleMicros", source::getThrottleMicros, reportChangesOnly));
79+
registry.register(gauge(Metric.ID.of("jvm.cgroup.cpu.throttleMicros", globalTags), source::getThrottleMicros, reportChangesOnly));
7980
if (withDetails) {
80-
registry.register(gauge("jvm.cgroup.cpu.numPeriod", source::getNumPeriod, reportChangesOnly));
81-
registry.register(gauge("jvm.cgroup.cpu.numThrottle", source::getNumThrottle, reportChangesOnly));
82-
registry.register(gauge("jvm.cgroup.cpu.pctThrottle", source::getPctThrottle, reportChangesOnly));
81+
registry.register(gauge(Metric.ID.of("jvm.cgroup.cpu.numPeriod", globalTags), source::getNumPeriod, reportChangesOnly));
82+
registry.register(gauge(Metric.ID.of("jvm.cgroup.cpu.numThrottle", globalTags), source::getNumThrottle, reportChangesOnly));
83+
registry.register(gauge(Metric.ID.of("jvm.cgroup.cpu.pctThrottle", globalTags), source::getPctThrottle, reportChangesOnly));
8384
}
8485
}
8586

86-
private GaugeLong gauge(String name, LongSupplier gauge, boolean reportChangesOnly) {
87-
return DGaugeLong.of(Metric.ID.of(name), gauge, reportChangesOnly);
87+
private GaugeLong gauge(Metric.ID id, LongSupplier gauge, boolean reportChangesOnly) {
88+
return DGaugeLong.of(id, gauge, reportChangesOnly);
8889
}
8990

9091
/** CPU Usage in Millicores */

metrics/src/main/java/io/avaje/metrics/core/JvmCGroupMemory.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
package io.avaje.metrics.core;
22

33
import io.avaje.metrics.GaugeLong;
4+
import io.avaje.metrics.Metric;
45
import io.avaje.metrics.MetricRegistry;
6+
import io.avaje.metrics.Tags;
57

68
final class JvmCGroupMemory {
79

810
private static final long MEG = 1_048_576;
911

10-
static void createGauges(MetricRegistry registry, boolean reportChangesOnly) {
11-
new JvmCGroupMemory().metrics(registry, reportChangesOnly);
12+
static void createGauges(MetricRegistry registry, boolean reportChangesOnly, Tags globalTags) {
13+
new JvmCGroupMemory().metrics(registry, reportChangesOnly, globalTags);
1214
}
1315

14-
private void metrics(MetricRegistry registry, boolean reportChangesOnly) {
16+
private void metrics(MetricRegistry registry, boolean reportChangesOnly, Tags globalTags) {
1517
FileLines memLimit = new FileLines("/sys/fs/cgroup/memory/memory.limit_in_bytes");
1618
FileLines memUsage = new FileLines("/sys/fs/cgroup/memory/memory.usage_in_bytes");
1719
if (memLimit.exists() && memUsage.exists()) {
1820
long limitInBytes = memLimit.single();
1921
MemSource source = new MemSource(limitInBytes, memUsage);
20-
registry.register(usage(source, reportChangesOnly));
22+
registry.register(usage(source, reportChangesOnly, globalTags));
2123
if (limitInBytes < 1_000_000_000_000L) {
2224
// only include when limit is in effect
23-
registry.register(limit(source, reportChangesOnly));
24-
registry.register(pctUsage(source, reportChangesOnly));
25+
registry.register(limit(source, reportChangesOnly, globalTags));
26+
registry.register(pctUsage(source, reportChangesOnly, globalTags));
2527
}
2628
}
2729
}
@@ -64,16 +66,16 @@ long pctUsage() {
6466
}
6567
}
6668

67-
GaugeLong usage(MemSource source, boolean reportChangesOnly) {
68-
return DGaugeLong.of("jvm.cgroup.memory.usage", source::usageMb, reportChangesOnly);
69+
GaugeLong usage(MemSource source, boolean reportChangesOnly, Tags globalTags) {
70+
return DGaugeLong.of(Metric.ID.of("jvm.cgroup.memory.usage", globalTags), source::usageMb, reportChangesOnly);
6971
}
7072

71-
GaugeLong pctUsage(MemSource source, boolean reportChangesOnly) {
72-
return DGaugeLong.of("jvm.cgroup.memory.pctUsage", source::pctUsage, reportChangesOnly);
73+
GaugeLong pctUsage(MemSource source, boolean reportChangesOnly, Tags globalTags) {
74+
return DGaugeLong.of(Metric.ID.of("jvm.cgroup.memory.pctUsage", globalTags), source::pctUsage, reportChangesOnly);
7375
}
7476

75-
GaugeLong limit(MemSource source, boolean reportChangesOnly) {
76-
return DGaugeLong.of("jvm.cgroup.memory.limit", source::limitMb, reportChangesOnly);
77+
GaugeLong limit(MemSource source, boolean reportChangesOnly, Tags globalTags) {
78+
return DGaugeLong.of(Metric.ID.of("jvm.cgroup.memory.limit", globalTags), source::limitMb, reportChangesOnly);
7779
}
7880

7981
}

metrics/src/main/java/io/avaje/metrics/core/JvmGarbageCollection.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.avaje.metrics.GaugeLong;
44
import io.avaje.metrics.MetricRegistry;
5+
import io.avaje.metrics.Tags;
56

67
import java.lang.management.GarbageCollectorMXBean;
78
import java.lang.management.ManagementFactory;
@@ -13,25 +14,25 @@
1314
*/
1415
final class JvmGarbageCollection {
1516

16-
static void createGauges(MetricRegistry registry, boolean withDetails) {
17+
static void createGauges(MetricRegistry registry, boolean withDetails, Tags globalTags) {
1718
List<GarbageCollectorMXBean> gcMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
18-
createTotalGcTime(registry, gcMXBeans);
19+
createTotalGcTime(registry, gcMXBeans, globalTags);
1920
if (withDetails) {
2021
for (GarbageCollectorMXBean gcMXBean : gcMXBeans) {
2122
// modify collector name replacing spaces with hyphens.
2223
String gcName = gcMXBean.getName().toLowerCase().replace(' ', '_').replace(".", "");
23-
registry.gauge(name("count", gcName), GaugeLong.incrementing(new Count(gcMXBean)));
24-
registry.gauge(name("time", gcName), GaugeLong.incrementing(new Time(gcMXBean)));
24+
registry.gauge(name("count", gcName), globalTags, GaugeLong.incrementing(new Count(gcMXBean)));
25+
registry.gauge(name("time", gcName), globalTags, GaugeLong.incrementing(new Time(gcMXBean)));
2526
}
2627
}
2728
}
2829

2930
/**
3031
* Return a Gauge for the total GC time in millis. Gives us a single metric to measure aggregate GC activity.
3132
*/
32-
private static void createTotalGcTime(MetricRegistry registry, List<GarbageCollectorMXBean> garbageCollectorMXBeans) {
33+
private static void createTotalGcTime(MetricRegistry registry, List<GarbageCollectorMXBean> garbageCollectorMXBeans, Tags globalTags) {
3334
GarbageCollectorMXBean[] gcBeans = garbageCollectorMXBeans.toArray(new GarbageCollectorMXBean[0]);
34-
registry.gauge("jvm.gc.time", GaugeLong.incrementing(new TotalTime(gcBeans)));
35+
registry.gauge("jvm.gc.time", globalTags, GaugeLong.incrementing(new TotalTime(gcBeans)));
3536
}
3637

3738
private static String name(String prefix, String gcName) {

metrics/src/main/java/io/avaje/metrics/core/JvmMemory.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.avaje.metrics.core;
22

3+
import io.avaje.metrics.Metric;
34
import io.avaje.metrics.MetricRegistry;
5+
import io.avaje.metrics.Tags;
46

57
import java.lang.management.ManagementFactory;
68
import java.lang.management.MemoryMXBean;
@@ -53,30 +55,32 @@ public MemoryUsage usage() {
5355
/**
5456
* Create the Heap Memory based GaugeMetricGroup.
5557
*/
56-
static void createHeapGroup(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails) {
58+
static void createHeapGroup(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
5759
HeapMemoryUsageSource source = new HeapMemoryUsageSource(ManagementFactory.getMemoryMXBean());
58-
createGroup(registry, "jvm.memory.heap", source, reportChangesOnly, withDetails);
60+
createGroup(registry, "jvm.memory.heap", source, reportChangesOnly, withDetails, globalTags);
5961
}
6062

6163
/**
6264
* Create the NonHeap Memory based GaugeDoubleMetricGroup.
6365
*/
64-
static void createNonHeapGroup(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails) {
66+
static void createNonHeapGroup(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
6567
NonHeapMemoryUsageSource source = new NonHeapMemoryUsageSource(ManagementFactory.getMemoryMXBean());
66-
createGroup(registry, "jvm.memory.nonheap", source, reportChangesOnly, withDetails);
68+
createGroup(registry, "jvm.memory.nonheap", source, reportChangesOnly, withDetails, globalTags);
6769
}
6870

69-
private static void createGroup(MetricRegistry registry, String baseName, MemoryUsageSource source, boolean reportChangesOnly, boolean withDetails) {
70-
new MemUsageGauages(source, baseName).createMetric(registry, reportChangesOnly, withDetails);
71+
private static void createGroup(MetricRegistry registry, String baseName, MemoryUsageSource source, boolean reportChangesOnly, boolean withDetails, Tags globalTags) {
72+
new MemUsageGauages(source, baseName, globalTags).createMetric(registry, reportChangesOnly, withDetails);
7173
}
7274

7375
static final class MemUsageGauages {
7476
private final MemoryUsageSource source;
7577
private final String baseName;
78+
private final Tags globalTags;
7679

77-
private MemUsageGauages(MemoryUsageSource source, String baseName) {
80+
private MemUsageGauages(MemoryUsageSource source, String baseName, Tags globalTags) {
7881
this.source = source;
7982
this.baseName = baseName;
83+
this.globalTags = globalTags;
8084
}
8185

8286
void createMetric(MetricRegistry registry, boolean reportChangesOnly, boolean withDetails) {
@@ -96,8 +100,8 @@ void createMetric(MetricRegistry registry, boolean reportChangesOnly, boolean wi
96100
}
97101
}
98102

99-
private String name(String name) {
100-
return baseName + "." + name;
103+
private Metric.ID name(String name) {
104+
return Metric.ID.of(baseName + "." + name, globalTags);
101105
}
102106

103107
private abstract static class Base {

0 commit comments

Comments
 (0)