-
-
Notifications
You must be signed in to change notification settings - Fork 86
Feature: Support OpenTelemetry API for Apollo Monitor custom metrics reporting #143
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| ~ Copyright 2022 Apollo Authors | ||
| ~ | ||
| ~ 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. | ||
| ~ | ||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <artifactId>apollo-plugin</artifactId> | ||
| <groupId>com.ctrip.framework.apollo</groupId> | ||
| <version>${revision}</version> | ||
| <relativePath>../pom.xml</relativePath> | ||
| </parent> | ||
|
|
||
| <artifactId>apollo-plugin-client-opentelemetry</artifactId> | ||
| <name>Apollo Plugin OpenTelemetry</name> | ||
| <packaging>jar</packaging> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.ctrip.framework.apollo</groupId> | ||
| <artifactId>apollo-client</artifactId> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.opentelemetry</groupId> | ||
| <artifactId>opentelemetry-api</artifactId> | ||
| <version>1.62.0</version> | ||
| </dependency> | ||
| <!-- Test dependencies --> | ||
| <dependency> | ||
| <groupId>junit</groupId> | ||
| <artifactId>junit</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-inline</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| /* | ||
| * Copyright 2026 Apollo Authors | ||
| * | ||
| * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; | ||
|
|
||
| import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; | ||
| import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter; | ||
| import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; | ||
| import com.google.common.collect.Maps; | ||
| import io.opentelemetry.api.GlobalOpenTelemetry; | ||
| import io.opentelemetry.api.common.Attributes; | ||
| import io.opentelemetry.api.common.AttributesBuilder; | ||
| import io.opentelemetry.api.metrics.*; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
| import org.slf4j.Logger; | ||
|
|
||
| /** | ||
| * OpenTelemetry implementation of Apollo client metrics exporter. | ||
| * Only uses OpenTelemetry API layer (no SDK dependency). | ||
| * | ||
| * @author leon.he@walmart.com | ||
| */ | ||
| public class OpenTelemetryApolloClientMetricsExporter extends | ||
| AbstractApolloClientMetricsExporter implements ApolloClientMetricsExporter { | ||
|
|
||
| private static final String OPENTELEMETRY = "opentelemetry"; | ||
| private static final String METER_NAME = "apollo-client"; | ||
| private static final String COUNTER_UNIT = "1"; | ||
| private static final String GAUGE_UNIT = "1"; | ||
|
|
||
| private final Logger logger = DeferredLoggerFactory.getLogger( | ||
| OpenTelemetryApolloClientMetricsExporter.class); | ||
|
|
||
| private Meter meter; | ||
| private Map<String, DoubleCounter> counterMap; | ||
| private Map<String, ObservableDoubleGauge> gaugeMap; | ||
|
|
||
| @Override | ||
| public void doInit() { | ||
| // Get meter from global OpenTelemetry | ||
| meter = GlobalOpenTelemetry.get().getMeter(METER_NAME); | ||
| // Initialize maps | ||
| counterMap = new ConcurrentHashMap<>(); | ||
| gaugeMap = new ConcurrentHashMap<>(); | ||
| logger.info("OpenTelemetry metrics exporter initialized with meter: {}", METER_NAME); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isSupport(String form) { | ||
| return OPENTELEMETRY.equals(form); | ||
| } | ||
|
|
||
| @Override | ||
| public void registerOrUpdateCounterSample(String name, Map<String, String> tags, | ||
| double incrValue) { | ||
| if (meter == null) { | ||
| logger.warn("OpenTelemetry meter not initialized, skipping counter registration for '{}'", name); | ||
| return; | ||
| } | ||
| DoubleCounter counter = counterMap.computeIfAbsent(name, | ||
| key -> meter.counterBuilder(name).setDescription("Apollo counter metrics").setUnit(COUNTER_UNIT).ofDoubles().build()); | ||
| Attributes attributes = getOrCreateAttributes(tags); | ||
| counter.add(incrValue, attributes); | ||
|
|
||
| if (logger.isDebugEnabled()) { | ||
| logger.debug("Updated OpenTelemetry counter '{}' with value: {}, tags: {}", name, incrValue, tags); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void registerOrUpdateGaugeSample(String name, Map<String, String> tags, double value) { | ||
| if (meter == null) { | ||
| logger.warn("OpenTelemetry meter not initialized, skipping gauge registration for '{}'", name); | ||
| return; | ||
| } | ||
| Attributes attributes = getOrCreateAttributes(tags); | ||
| // Register gauge if not already registered | ||
| gaugeMap.computeIfAbsent(name, key -> meter.gaugeBuilder(name) | ||
| .setDescription("Apollo gauge metrics") | ||
| .setUnit(GAUGE_UNIT) | ||
| .buildWithCallback(measurement -> { | ||
| measurement.record(value, attributes); | ||
| })); | ||
|
Comment on lines
+93
to
+99
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
file='apollo-plugin/apollo-plugin-client-opentelemetry/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/OpenTelemetryApolloClientMetricsExporter.java'
printf '%s\n' '--- target outline ---'
ast-grep outline "$file" || true
printf '%s\n' '--- target source ---'
cat -n "$file"
printf '%s\n' '--- related symbols ---'
rg -n -C 4 'gaugeMap|registerGauge|Gauge|OpenTelemetryApolloClientMetricsExporter' apollo-plugin/apollo-plugin-client-opentelemetry
printf '%s\n' '--- repository files in module ---'
git ls-files apollo-plugin/apollo-plugin-client-opentelemetryRepository: apolloconfig/apollo-java Length of output: 46548 🏁 Script executed: #!/bin/bash
set -eu
file='apollo-plugin/apollo-plugin-client-opentelemetry/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/OpenTelemetryApolloClientMetricsExporter.java'
cat -n "$file"
rg -n -C 4 'gaugeMap|registerGauge|Gauge|OpenTelemetryApolloClientMetricsExporter' apollo-plugin/apollo-plugin-client-opentelemetry
git ls-files apollo-plugin/apollo-plugin-client-opentelemetryRepository: apolloconfig/apollo-java Length of output: 46084 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- exporter contract and base class ---'
rg -n -C 8 'registerOrUpdateGaugeSample|class AbstractApolloClientMetricsExporter|interface ApolloClientMetricsExporter' \
apollo-plugin apollo-core
printf '%s\n' '--- all gauge call sites ---'
rg -n -C 5 'registerOrUpdateGaugeSample' .
printf '%s\n' '--- target test source ---'
cat -n apollo-plugin/apollo-plugin-client-opentelemetry/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/OpenTelemetryApolloClientMetricsExporterTest.java
printf '%s\n' '--- module dependency declarations ---'
cat -n apollo-plugin/apollo-plugin-client-opentelemetry/pom.xml
printf '%s\n' '--- source-level behavioral summary ---'
python3 - <<'PY'
from pathlib import Path
target = Path("apollo-plugin/apollo-plugin-client-opentelemetry/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/OpenTelemetryApolloClientMetricsExporter.java")
text = target.read_text()
print("computeIfAbsent(name) count:", text.count("gaugeMap.computeIfAbsent(name"))
print("callback records method parameters:", "measurement.record(value, attributes)" in text)
for p in Path(".").rglob("*.java"):
s = p.read_text(errors="ignore")
if "registerOrUpdateGaugeSample(" in s:
print(f"{p}: {s.count('registerOrUpdateGaugeSample(')} occurrence(s)")
PYRepository: apolloconfig/apollo-java Length of output: 50380 🏁 Script executed: #!/bin/bash
set -eu
rg -n -C 8 'registerOrUpdateGaugeSample|class AbstractApolloClientMetricsExporter|interface ApolloClientMetricsExporter' apollo-plugin apollo-core
rg -n -C 5 'registerOrUpdateGaugeSample' .
cat -n apollo-plugin/apollo-plugin-client-opentelemetry/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/OpenTelemetryApolloClientMetricsExporterTest.java
cat -n apollo-plugin/apollo-plugin-client-opentelemetry/pom.xmlRepository: apolloconfig/apollo-java Length of output: 50380 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- interface ---'
sed -n '1,90p' apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporter.java
printf '%s\n' '--- abstract forwarding path ---'
sed -n '70,110p' apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporter.java
printf '%s\n' '--- gauge model and sample producers ---'
rg -n -C 4 'new GaugeModel|GaugeModel\.|SampleModel|registerSample\(' apollo-client/src/main/java \
-g '*.java' | head -n 220
printf '%s\n' '--- focused source verifier ---'
python3 - <<'PY'
from pathlib import Path
target = Path(
"apollo-plugin/apollo-plugin-client-opentelemetry/src/main/java/"
"com/ctrip/framework/apollo/monitor/internal/exporter/impl/"
"OpenTelemetryApolloClientMetricsExporter.java"
)
text = target.read_text()
method_start = text.index("public void registerOrUpdateGaugeSample")
method_end = text.index("\n private Attributes", method_start)
method = text[method_start:method_end]
print("uses ConcurrentHashMap for gaugeMap:", "gaugeMap = new ConcurrentHashMap<>()" in text)
print("uses computeIfAbsent keyed by name:", "gaugeMap.computeIfAbsent(name" in method)
print("callback captures value:", "measurement.record(value, attributes)" in method)
print("callback created in computeIfAbsent:", method.index("buildWithCallback") > method.index("computeIfAbsent"))
print("method declares update operation:", "registerOrUpdateGaugeSample" in method)
# A source-level execution model of the callback capture.
gauge = {}
def register(name, tags, value):
if name not in gauge:
gauge[name] = lambda: (value, tags)
return gauge[name]()
print("first update:", register("metric", {"cluster": "a"}, 1.0))
print("second update:", register("metric", {"cluster": "b"}, 2.0))
print("second update retains first sample:", register("metric", {"cluster": "b"}, 2.0) == (1.0, {"cluster": "a"}))
# Count production call sites separately from declarations/tests.
for p in sorted(Path("apollo-client/src/main/java").rglob("*.java")):
s = p.read_text(errors="ignore")
n = s.count("registerSample(")
if n:
print(f"producer {p}: {n} registerSample occurrence(s)")
PYRepository: apolloconfig/apollo-java Length of output: 19576 🏁 Script executed: #!/bin/bash
set -eu
sed -n '1,90p' apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporter.java
sed -n '70,110p' apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporter.java
rg -n -C 4 'new GaugeModel|GaugeModel\.|SampleModel|registerSample\(' apollo-client/src/main/java -g '*.java' | head -n 220Repository: apolloconfig/apollo-java Length of output: 18977 Store current gauge samples outside 🤖 Prompt for AI Agents |
||
|
|
||
| if (logger.isDebugEnabled()) { | ||
| logger.debug("Updated OpenTelemetry gauge '{}' with value: {}, tags: {}", | ||
| name, value, tags); | ||
| } | ||
| } | ||
|
|
||
| private Attributes getOrCreateAttributes(Map<String, String> tags) { | ||
| if (tags == null || tags.isEmpty()) { | ||
| return Attributes.empty(); | ||
| } | ||
| AttributesBuilder builder = Attributes.builder(); | ||
| tags.forEach(builder::put); | ||
| return builder.build(); | ||
| } | ||
|
|
||
|
|
||
| @Override | ||
| public String response() { | ||
| // Return simple status information since we're only using API layer | ||
| int counterCount = counterMap != null ? counterMap.size() : 0; | ||
| int gaugeCount = gaugeMap != null ? gaugeMap.size() : 0; | ||
|
|
||
| String meterStatus = (meter != null) ? METER_NAME : "not initialized"; | ||
| return String.format( | ||
| "OpenTelemetry metrics exporter status - Counters: %d, Gauges: %d, Meter: %s", | ||
| counterCount, gaugeCount, meterStatus); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| com.ctrip.framework.apollo.monitor.internal.exporter.impl.OpenTelemetryApolloClientMetricsExporter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| /* | ||
| * Copyright 2022 Apollo Authors | ||
| * | ||
| * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; | ||
|
|
||
| import static org.junit.Assert.*; | ||
| import static org.mockito.Mockito.*; | ||
|
|
||
| import io.opentelemetry.api.GlobalOpenTelemetry; | ||
| import io.opentelemetry.api.OpenTelemetry; | ||
| import io.opentelemetry.api.metrics.Meter; | ||
| import org.junit.After; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import org.mockito.MockedStatic; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| public class OpenTelemetryApolloClientMetricsExporterTest { | ||
|
|
||
| private OpenTelemetryApolloClientMetricsExporter exporter; | ||
| private MockedStatic<GlobalOpenTelemetry> globalOpenTelemetryMock; | ||
| private OpenTelemetry openTelemetry; | ||
| private Meter meter; | ||
|
|
||
| @Before | ||
| public void setUp() { | ||
| // Mock GlobalOpenTelemetry | ||
| globalOpenTelemetryMock = mockStatic(GlobalOpenTelemetry.class); | ||
| openTelemetry = mock(OpenTelemetry.class); | ||
| meter = mock(Meter.class); | ||
|
|
||
| when(GlobalOpenTelemetry.get()).thenReturn(openTelemetry); | ||
| when(openTelemetry.getMeter("apollo-client")).thenReturn(meter); | ||
|
|
||
| exporter = new OpenTelemetryApolloClientMetricsExporter(); | ||
| exporter.doInit(); | ||
| } | ||
|
|
||
| @After | ||
| public void tearDown() { | ||
| if (globalOpenTelemetryMock != null) { | ||
| globalOpenTelemetryMock.close(); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testIsSupport() { | ||
| assertTrue(exporter.isSupport("opentelemetry")); | ||
| assertFalse(exporter.isSupport("prometheus")); | ||
| assertFalse(exporter.isSupport("other")); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDoInit() { | ||
| // Verify that meter was obtained from GlobalOpenTelemetry | ||
| globalOpenTelemetryMock.verify(() -> GlobalOpenTelemetry.get()); | ||
| verify(openTelemetry).getMeter("apollo-client"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testRegisterOrUpdateCounterSample() { | ||
| String name = "test_counter"; | ||
| Map<String, String> tags = new HashMap<>(); | ||
| tags.put("namespace", "application"); | ||
| tags.put("cluster", "default"); | ||
|
|
||
| // Mock counter builder | ||
| io.opentelemetry.api.metrics.LongCounterBuilder longCounterBuilder = mock(io.opentelemetry.api.metrics.LongCounterBuilder.class); | ||
| io.opentelemetry.api.metrics.DoubleCounterBuilder counterBuilder = mock(io.opentelemetry.api.metrics.DoubleCounterBuilder.class); | ||
| io.opentelemetry.api.metrics.DoubleCounter counter = mock(io.opentelemetry.api.metrics.DoubleCounter.class); | ||
|
|
||
| when(meter.counterBuilder(name)).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.setDescription("Apollo counter metrics")).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.setUnit("1")).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.ofDoubles()).thenReturn(counterBuilder); | ||
| when(counterBuilder.setDescription("Apollo counter metrics")).thenReturn(counterBuilder); | ||
| when(counterBuilder.setUnit("1")).thenReturn(counterBuilder); | ||
| when(counterBuilder.build()).thenReturn(counter); | ||
|
|
||
| // This will create the counter on first call | ||
| exporter.registerOrUpdateCounterSample(name, tags, 1.25); | ||
|
|
||
| // Verify counter was created | ||
| verify(meter).counterBuilder(name); | ||
| verify(counterBuilder).build(); | ||
| verify(counter).add(eq(1.25), any()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testRegisterOrUpdateGaugeSample() { | ||
| String name = "test_gauge"; | ||
| Map<String, String> tags = new HashMap<>(); | ||
| tags.put("namespace", "application"); | ||
| tags.put("cluster", "default"); | ||
|
|
||
| // Mock gauge builder | ||
| io.opentelemetry.api.metrics.DoubleGaugeBuilder gaugeBuilder = mock(io.opentelemetry.api.metrics.DoubleGaugeBuilder.class); | ||
| io.opentelemetry.api.metrics.ObservableDoubleGauge gauge = | ||
| new io.opentelemetry.api.metrics.ObservableDoubleGauge() { | ||
| }; | ||
|
|
||
| when(meter.gaugeBuilder(name)).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.setDescription("Apollo gauge metrics")).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.setUnit("1")).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.buildWithCallback(any())).thenReturn(gauge); | ||
|
|
||
| // This will create the gauge on first call | ||
| exporter.registerOrUpdateGaugeSample(name, tags, 3.14); | ||
|
|
||
| // Verify gauge was created | ||
| verify(meter).gaugeBuilder(name); | ||
| verify(gaugeBuilder).buildWithCallback(any()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testResponse() { | ||
| String response = exporter.response(); | ||
| assertNotNull(response); | ||
| assertTrue(response.contains("OpenTelemetry metrics exporter status")); | ||
| assertTrue(response.contains("Counters: 0")); | ||
| assertTrue(response.contains("Gauges: 0")); | ||
| assertTrue(response.contains("Meter: apollo-client")); | ||
| } | ||
|
|
||
| @Test | ||
| public void testResponseWithMetrics() { | ||
| // Register some metrics first | ||
| Map<String, String> tags = new HashMap<>(); | ||
| tags.put("test", "value"); | ||
|
|
||
| // Mock counter creation | ||
| io.opentelemetry.api.metrics.LongCounterBuilder longCounterBuilder = mock(io.opentelemetry.api.metrics.LongCounterBuilder.class); | ||
| io.opentelemetry.api.metrics.DoubleCounterBuilder counterBuilder = mock(io.opentelemetry.api.metrics.DoubleCounterBuilder.class); | ||
| io.opentelemetry.api.metrics.DoubleCounter counter = mock(io.opentelemetry.api.metrics.DoubleCounter.class); | ||
| when(meter.counterBuilder("test_counter")).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.setDescription(anyString())).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.setUnit(anyString())).thenReturn(longCounterBuilder); | ||
| when(longCounterBuilder.ofDoubles()).thenReturn(counterBuilder); | ||
| when(counterBuilder.setDescription(anyString())).thenReturn(counterBuilder); | ||
| when(counterBuilder.setUnit(anyString())).thenReturn(counterBuilder); | ||
| when(counterBuilder.build()).thenReturn(counter); | ||
|
|
||
| // Mock gauge creation | ||
| io.opentelemetry.api.metrics.DoubleGaugeBuilder gaugeBuilder = mock(io.opentelemetry.api.metrics.DoubleGaugeBuilder.class); | ||
| io.opentelemetry.api.metrics.ObservableDoubleGauge gauge = | ||
| new io.opentelemetry.api.metrics.ObservableDoubleGauge() { | ||
| }; | ||
| when(meter.gaugeBuilder("test_gauge")).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.setDescription(anyString())).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.setUnit(anyString())).thenReturn(gaugeBuilder); | ||
| when(gaugeBuilder.buildWithCallback(any())).thenReturn(gauge); | ||
|
|
||
| exporter.registerOrUpdateCounterSample("test_counter", tags, 1.0); | ||
| exporter.registerOrUpdateGaugeSample("test_gauge", tags, 2.0); | ||
|
|
||
| String response = exporter.response(); | ||
| assertTrue(response.contains("Counters: 1")); | ||
| assertTrue(response.contains("Gauges: 1")); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.