Skip to content

Commit bdc6b1f

Browse files
authored
Merge pull request wildfly#19294 from jasondlee/micrometer-isolation
WFLY-21061 - Ensure that Micrometer metrics are not visible between deployments
2 parents 188ecdc + 3743f4a commit bdc6b1f

File tree

11 files changed

+927
-23
lines changed

11 files changed

+927
-23
lines changed

observability/micrometer/pom.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,21 @@
181181
<artifactId>junit</artifactId>
182182
<scope>test</scope>
183183
</dependency>
184+
185+
<dependency>
186+
<groupId>io.prometheus</groupId>
187+
<artifactId>prometheus-metrics-model</artifactId>
188+
<scope>test</scope>
189+
</dependency>
190+
<dependency>
191+
<groupId>io.prometheus</groupId>
192+
<artifactId>prometheus-metrics-config</artifactId>
193+
<scope>test</scope>
194+
</dependency>
195+
<dependency>
196+
<groupId>io.prometheus</groupId>
197+
<artifactId>prometheus-metrics-exposition-formats</artifactId>
198+
<scope>test</scope>
199+
</dependency>
184200
</dependencies>
185201
</project>

observability/micrometer/src/main/java/org/wildfly/extension/micrometer/MicrometerDeploymentProcessor.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import java.util.function.Supplier;
1414

15+
import io.micrometer.core.instrument.MeterRegistry;
1516
import org.jboss.as.controller.PathAddress;
1617
import org.jboss.as.controller.capability.CapabilityServiceSupport;
1718
import org.jboss.as.server.deployment.AttachmentKey;
@@ -25,13 +26,15 @@
2526
import org.jboss.as.weld.WeldCapability;
2627
import org.wildfly.extension.micrometer.api.MicrometerCdiExtension;
2728
import org.wildfly.extension.micrometer.metrics.MetricRegistration;
29+
import org.wildfly.extension.micrometer.registry.ApplicationRegistry;
2830
import org.wildfly.service.Installer.StartWhen;
2931
import org.wildfly.subsystem.service.ServiceDependency;
3032
import org.wildfly.subsystem.service.ServiceInstaller;
3133

3234
class MicrometerDeploymentProcessor implements DeploymentUnitProcessor {
3335
static final String WELD_CAPABILITY_NAME = "org.wildfly.weld";
3436
static final AttachmentKey<MicrometerService> CONFIG_ATTACHMENT_KEY = AttachmentKey.create(MicrometerService.class);
37+
static final AttachmentKey<MeterRegistry> REGISTRY_ATTACHMENT_KEY = AttachmentKey.create(MeterRegistry.class);
3538

3639
MicrometerDeploymentProcessor() {
3740
}
@@ -68,17 +71,27 @@ private PathAddress createDeploymentAddressPrefix(DeploymentUnit deploymentUnit)
6871
}
6972
}
7073

71-
private void registerCdiExtension(DeploymentPhaseContext deploymentPhaseContext, MicrometerService micrometerService) throws DeploymentUnitProcessingException {
72-
DeploymentUnit deploymentUnit = deploymentPhaseContext.getDeploymentUnit();
74+
private void registerCdiExtension(DeploymentPhaseContext phaseContext, MicrometerService micrometerService) throws DeploymentUnitProcessingException {
75+
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
7376
try {
7477
CapabilityServiceSupport support = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT);
7578

7679
final WeldCapability weldCapability = support.getCapabilityRuntimeAPI(WELD_CAPABILITY_NAME, WeldCapability.class);
7780
if (!weldCapability.isPartOfWeldDeployment(deploymentUnit)) {
7881
MICROMETER_LOGGER.noCdiDeployment();
7982
} else {
80-
weldCapability.registerExtensionInstance(new MicrometerCdiExtension(micrometerService.getMicrometerRegistry()),
81-
deploymentUnit);
83+
MeterRegistry applicationRegistry = null;
84+
85+
if (deploymentUnit.getParent() != null) {
86+
applicationRegistry = deploymentUnit.getParent().getAttachment(REGISTRY_ATTACHMENT_KEY);
87+
}
88+
89+
if (applicationRegistry == null) {
90+
applicationRegistry = new ApplicationRegistry(deploymentUnit.getName(),
91+
micrometerService.getMicrometerRegistry());
92+
deploymentUnit.putAttachment(REGISTRY_ATTACHMENT_KEY, applicationRegistry);
93+
}
94+
weldCapability.registerExtensionInstance(new MicrometerCdiExtension(applicationRegistry), deploymentUnit);
8295
}
8396
} catch (CapabilityServiceSupport.NoSuchCapabilityException e) {
8497
//We should not be here since the subsystem depends on weld capability. Just in case ...

observability/micrometer/src/main/java/org/wildfly/extension/micrometer/MicrometerExtensionLogger.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,8 @@ public interface MicrometerExtensionLogger extends BasicLogger {
7878

7979
@Message(id = 14, value = "Prometheus is not supported on domain mode servers")
8080
OperationFailedException prometheusNotSupportedOnHostControllers();
81+
82+
@LogMessage(level = WARN)
83+
@Message(id = 15, value = "MeterRegistry.Config is not supported in a WildFly-managed MeterRegistry.")
84+
void configNotSupported();
8185
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright The WildFly Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.wildfly.extension.micrometer.registry;
7+
8+
import java.util.List;
9+
import java.util.concurrent.TimeUnit;
10+
import java.util.function.Consumer;
11+
import java.util.function.ToDoubleFunction;
12+
import java.util.function.ToLongFunction;
13+
import java.util.stream.StreamSupport;
14+
15+
import io.micrometer.core.instrument.Counter;
16+
import io.micrometer.core.instrument.DistributionSummary;
17+
import io.micrometer.core.instrument.FunctionCounter;
18+
import io.micrometer.core.instrument.FunctionTimer;
19+
import io.micrometer.core.instrument.LongTaskTimer;
20+
import io.micrometer.core.instrument.Meter;
21+
import io.micrometer.core.instrument.MeterRegistry;
22+
import io.micrometer.core.instrument.Tag;
23+
import io.micrometer.core.instrument.Tags;
24+
import io.micrometer.core.instrument.TimeGauge;
25+
import io.micrometer.core.instrument.Timer;
26+
import io.micrometer.core.instrument.search.RequiredSearch;
27+
import io.micrometer.core.instrument.search.Search;
28+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
29+
import org.wildfly.extension.micrometer.MicrometerExtensionLogger;
30+
31+
public class ApplicationRegistry extends SimpleMeterRegistry {
32+
static final String TAG_WF_DEPLOYMENT = "WF_DEPLOYMENT";
33+
private final String deploymentName;
34+
private final MeterRegistry parentRegistry;
35+
private final More more = new ApplicationMore();
36+
37+
public ApplicationRegistry(String deploymentName, MeterRegistry parentRegistry) {
38+
this.deploymentName = deploymentName;
39+
this.parentRegistry = parentRegistry;
40+
}
41+
42+
@Override
43+
public List<Meter> getMeters() {
44+
return parentRegistry.getMeters().stream().filter(m -> !containsWrongDeploymentTag(m.getId()))
45+
.toList();
46+
}
47+
48+
@Override
49+
public void forEachMeter(Consumer<? super Meter> consumer) {
50+
parentRegistry.forEachMeter(m -> {
51+
if (!containsWrongDeploymentTag(m.getId())) {
52+
consumer.accept(m);
53+
}
54+
});
55+
}
56+
57+
@Override
58+
public Search find(String name) {
59+
return parentRegistry.find(name).tag(TAG_WF_DEPLOYMENT, deploymentName);
60+
}
61+
62+
@Override
63+
public RequiredSearch get(String name) {
64+
return parentRegistry.get(name).tag(TAG_WF_DEPLOYMENT, deploymentName);
65+
}
66+
67+
@Override
68+
public Meter remove(Meter meter) {
69+
if (containsWrongDeploymentTag(meter.getId())) {
70+
return null;
71+
}
72+
return parentRegistry.remove(meter.getId());
73+
}
74+
75+
@Override
76+
public Meter removeByPreFilterId(Meter.Id id) {
77+
if (containsWrongDeploymentTag(id)) {
78+
return null;
79+
}
80+
return parentRegistry.removeByPreFilterId(id);
81+
}
82+
83+
@Override
84+
public Meter remove(Meter.Id id) {
85+
if (containsWrongDeploymentTag(id)) {
86+
return null;
87+
}
88+
return parentRegistry.remove(id);
89+
}
90+
91+
@Override
92+
public Counter counter(String name, Iterable<Tag> tags) {
93+
var counter = findByNameAndTags(name, tags).counter();
94+
95+
if (counter == null || containsWrongDeploymentTag(counter.getId()) ) {
96+
97+
counter = parentRegistry.counter(name, addMissingTag(tags));
98+
}
99+
return counter;
100+
}
101+
102+
@Override
103+
public <T> T gauge(String name, Iterable<Tag> tags, T stateObject, ToDoubleFunction<T> valueFunction) {
104+
var gauge = findByNameAndTags(name, tags).gauge();
105+
106+
if (gauge == null || containsWrongDeploymentTag(gauge.getId()) ) {
107+
parentRegistry.gauge(name, addMissingTag(tags), stateObject, valueFunction);
108+
}
109+
110+
return stateObject;
111+
}
112+
113+
@Override
114+
public Timer timer(String name, Iterable<Tag> tags) {
115+
var timer = findByNameAndTags(name, tags).timer();
116+
if (timer == null || containsWrongDeploymentTag(timer.getId()) ) {
117+
timer = parentRegistry.timer(name, addMissingTag(tags));
118+
}
119+
return timer;
120+
}
121+
122+
@Override
123+
public DistributionSummary summary(String name, Iterable<Tag> tags) {
124+
var summary = findByNameAndTags(name, tags).summary();
125+
if (summary == null || containsWrongDeploymentTag(summary.getId()) ) {
126+
summary = parentRegistry.summary(name, addMissingTag(tags));
127+
}
128+
return summary;
129+
}
130+
131+
@Override
132+
public void clear() {
133+
getMeters().forEach(this::remove);
134+
}
135+
136+
@Override
137+
public Config config() {
138+
MicrometerExtensionLogger.MICROMETER_LOGGER.configNotSupported();
139+
return super.config();
140+
}
141+
142+
@Override
143+
public More more() {
144+
return more;
145+
}
146+
147+
private Search findByNameAndTags(String name, Iterable<Tag> tags) {
148+
return parentRegistry.find(name).tags(tags);
149+
}
150+
151+
private Iterable<Tag> addMissingTag(Iterable<Tag> tags) {
152+
var hasWfTag = StreamSupport.stream(tags.spliterator(), false)
153+
.anyMatch(t -> t.getKey().equals(TAG_WF_DEPLOYMENT));
154+
return hasWfTag ? tags : Tags.concat(tags, TAG_WF_DEPLOYMENT, deploymentName);
155+
}
156+
157+
private boolean containsWrongDeploymentTag(Meter.Id id) {
158+
// If the tag doesn't match the current deployment, whether it's missing or different, it should be denied
159+
return !deploymentName.equals(id.getTag(TAG_WF_DEPLOYMENT));
160+
}
161+
162+
private class ApplicationMore extends More {
163+
@Override
164+
public <T> FunctionCounter counter(String name, Iterable<Tag> tags, T obj, ToDoubleFunction<T> countFunction) {
165+
var meter = findByNameAndTags(name, tags).functionCounter();
166+
if (meter == null || containsWrongDeploymentTag(meter.getId()) ) {
167+
meter = parentRegistry.more().counter(name, addMissingTag(tags), obj, countFunction);
168+
}
169+
return meter;
170+
}
171+
172+
@Override
173+
public <T extends Number> FunctionCounter counter(String name, Iterable<Tag> tags, T number) {
174+
var meter = findByNameAndTags(name, tags).functionCounter();
175+
if (meter == null || containsWrongDeploymentTag(meter.getId()) ) {
176+
meter = parentRegistry.more().counter(name, addMissingTag(tags), number);
177+
}
178+
return meter;
179+
}
180+
181+
@Override
182+
public LongTaskTimer longTaskTimer(String name, Iterable<Tag> tags) {
183+
var meter = findByNameAndTags(name, tags).longTaskTimer();
184+
if (meter == null || containsWrongDeploymentTag(meter.getId()) ) {
185+
meter = parentRegistry.more().longTaskTimer(name, addMissingTag(tags));
186+
}
187+
return meter;
188+
}
189+
190+
@Override
191+
public <T> TimeGauge timeGauge(String name, Iterable<Tag> tags, T obj, TimeUnit timeFunctionUnit,
192+
ToDoubleFunction<T> timeFunction) {
193+
var meter = findByNameAndTags(name, tags).timeGauge();
194+
if (meter == null || containsWrongDeploymentTag(meter.getId()) ) {
195+
meter = parentRegistry.more().timeGauge(name, addMissingTag(tags), obj, timeFunctionUnit, timeFunction);
196+
}
197+
return meter;
198+
}
199+
200+
@Override
201+
public <T> FunctionTimer timer(String name, Iterable<Tag> tags, T obj, ToLongFunction<T> countFunction,
202+
ToDoubleFunction<T> totalTimeFunction, TimeUnit totalTimeFunctionUnit) {
203+
var meter = findByNameAndTags(name, tags).functionTimer();
204+
if (meter == null || containsWrongDeploymentTag(meter.getId()) ) {
205+
meter = parentRegistry.more().timer(name, addMissingTag(tags), obj, countFunction, totalTimeFunction, totalTimeFunctionUnit);
206+
}
207+
return meter;
208+
}
209+
}
210+
}

0 commit comments

Comments
 (0)