Skip to content

Commit f46cf5c

Browse files
committed
implement stable service ID
1 parent 7d6e440 commit f46cf5c

File tree

2 files changed

+81
-22
lines changed

2 files changed

+81
-22
lines changed

jmx-scraper/src/main/java/io/opentelemetry/contrib/jmxscraper/JmxScraper.java

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55

66
package io.opentelemetry.contrib.jmxscraper;
77

8-
import io.opentelemetry.api.GlobalOpenTelemetry;
98
import io.opentelemetry.api.OpenTelemetry;
9+
import io.opentelemetry.api.common.AttributeKey;
10+
import io.opentelemetry.api.common.Attributes;
1011
import io.opentelemetry.contrib.jmxscraper.config.JmxScraperConfig;
1112
import io.opentelemetry.contrib.jmxscraper.config.PropertiesCustomizer;
1213
import io.opentelemetry.contrib.jmxscraper.config.PropertiesSupplier;
1314
import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight;
1415
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
1516
import io.opentelemetry.instrumentation.jmx.yaml.RuleParser;
16-
import io.opentelemetry.sdk.OpenTelemetrySdk;
1717
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
1818
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
19+
import io.opentelemetry.sdk.resources.Resource;
1920
import java.io.DataInputStream;
2021
import java.io.IOException;
2122
import java.io.InputStream;
@@ -27,15 +28,20 @@
2728
import java.util.Collections;
2829
import java.util.List;
2930
import java.util.Map;
30-
import java.util.Optional;
3131
import java.util.Properties;
32+
import java.util.UUID;
3233
import java.util.concurrent.atomic.AtomicBoolean;
3334
import java.util.logging.Level;
3435
import java.util.logging.Logger;
3536
import javax.management.MBeanServerConnection;
37+
import javax.management.ObjectName;
3638
import javax.management.remote.JMXConnector;
3739

3840
public class JmxScraper {
41+
42+
private static final AttributeKey<String> SERVICE_INSTANCE_ID =
43+
AttributeKey.stringKey("service.instance.id");
44+
3945
private static final Logger logger = Logger.getLogger(JmxScraper.class.getName());
4046
private static final String CONFIG_ARG = "-config";
4147
private static final String TEST_ARG = "-test";
@@ -65,30 +71,35 @@ public static void main(String[] args) {
6571
propagateToSystemProperties(argsConfig);
6672

6773
PropertiesCustomizer configCustomizer = new PropertiesCustomizer();
68-
JmxScraperConfig scraperConfig = configCustomizer.getScraperConfig();
69-
70-
long exportSeconds = scraperConfig.getSamplingInterval().toMillis() / 1000;
71-
logger.log(Level.INFO, "metrics export interval (seconds) = " + exportSeconds);
7274

73-
JmxConnectorBuilder connectorBuilder =
74-
JmxConnectorBuilder.createNew(scraperConfig.getServiceUrl());
75+
// auto-configure SDK
76+
OpenTelemetry openTelemetry =
77+
AutoConfiguredOpenTelemetrySdk.builder()
78+
.addPropertiesSupplier(new PropertiesSupplier(argsConfig))
79+
.addPropertiesCustomizer(configCustomizer)
80+
// we rely on the config customizer to be executed first to get effective config
81+
.addResourceCustomizer(
82+
(resource, configProperties) -> {
83+
UUID instanceId =
84+
getRemoteServiceInstanceId(configCustomizer.getConnectorBuilder());
85+
if (resource.getAttribute(SERVICE_INSTANCE_ID) != null || instanceId == null) {
86+
return resource;
87+
}
88+
logger.log(Level.INFO, "remote service instance ID: " + instanceId);
89+
return resource.merge(
90+
Resource.create(Attributes.of(SERVICE_INSTANCE_ID, instanceId.toString())));
91+
})
92+
.build()
93+
.getOpenTelemetrySdk();
7594

76-
Optional.ofNullable(scraperConfig.getUsername()).ifPresent(connectorBuilder::withUser);
77-
Optional.ofNullable(scraperConfig.getPassword()).ifPresent(connectorBuilder::withPassword);
78-
79-
if (scraperConfig.isRegistrySsl()) {
80-
connectorBuilder.withSslRegistry();
81-
}
95+
// scraper configuration and connector builder are built using effective SDK configuration
96+
// thus we have to get it after the SDK is built
97+
JmxScraperConfig scraperConfig = configCustomizer.getScraperConfig();
98+
JmxConnectorBuilder connectorBuilder = configCustomizer.getConnectorBuilder();
8299

83100
if (testMode) {
84101
System.exit(testConnection(connectorBuilder) ? 0 : 1);
85102
} else {
86-
// auto-configure SDK
87-
OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.builder()
88-
.addPropertiesSupplier(new PropertiesSupplier(argsConfig))
89-
.addPropertiesCustomizer(configCustomizer)
90-
.build()
91-
.getOpenTelemetrySdk();
92103
JmxMetricInsight jmxInsight =
93104
JmxMetricInsight.createService(
94105
openTelemetry, scraperConfig.getSamplingInterval().toMillis());
@@ -116,7 +127,6 @@ public static void main(String[] args) {
116127

117128
private static boolean testConnection(JmxConnectorBuilder connectorBuilder) {
118129
try (JMXConnector connector = connectorBuilder.build()) {
119-
120130
MBeanServerConnection connection = connector.getMBeanServerConnection();
121131
Integer mbeanCount = connection.getMBeanCount();
122132
if (mbeanCount > 0) {
@@ -132,6 +142,30 @@ private static boolean testConnection(JmxConnectorBuilder connectorBuilder) {
132142
}
133143
}
134144

145+
// TODO : test on local JVM and call it more than once for stability
146+
static UUID getRemoteServiceInstanceId(JmxConnectorBuilder connectorBuilder) {
147+
try (JMXConnector jmxConnector = connectorBuilder.build()) {
148+
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
149+
150+
StringBuilder id = new StringBuilder();
151+
try {
152+
ObjectName objectName = new ObjectName("java.lang:type=Runtime");
153+
for (String attribute : Arrays.asList("StartTime", "Pid", "Name")) {
154+
Object value = connection.getAttribute(objectName, attribute);
155+
if (id.length() > 0) {
156+
id.append(",");
157+
}
158+
id.append(value);
159+
}
160+
return UUID.nameUUIDFromBytes(id.toString().getBytes());
161+
} catch (Exception e) {
162+
throw new RuntimeException(e);
163+
}
164+
} catch (IOException e) {
165+
return null;
166+
}
167+
}
168+
135169
// package private for testing
136170
static void propagateToSystemProperties(Properties properties) {
137171
for (Map.Entry<Object, Object> entry : properties.entrySet()) {

jmx-scraper/src/main/java/io/opentelemetry/contrib/jmxscraper/config/PropertiesCustomizer.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
import static io.opentelemetry.contrib.jmxscraper.config.JmxScraperConfig.JMX_INTERVAL_LEGACY;
99
import static io.opentelemetry.contrib.jmxscraper.config.JmxScraperConfig.METRIC_EXPORT_INTERVAL;
1010

11+
import io.opentelemetry.contrib.jmxscraper.JmxConnectorBuilder;
1112
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
1213
import java.util.HashMap;
1314
import java.util.Map;
15+
import java.util.Optional;
1416
import java.util.function.Function;
17+
import java.util.logging.Level;
1518
import java.util.logging.Logger;
1619
import javax.annotation.Nullable;
1720

@@ -24,6 +27,8 @@ public class PropertiesCustomizer implements Function<ConfigProperties, Map<Stri
2427

2528
@Nullable private JmxScraperConfig scraperConfig;
2629

30+
@Nullable private JmxConnectorBuilder connectorBuilder;
31+
2732
@Override
2833
public Map<String, String> apply(ConfigProperties config) {
2934
Map<String, String> result = new HashMap<>();
@@ -45,6 +50,19 @@ public Map<String, String> apply(ConfigProperties config) {
4550
}
4651

4752
scraperConfig = JmxScraperConfig.fromConfig(config);
53+
54+
long exportSeconds = scraperConfig.getSamplingInterval().toMillis() / 1000;
55+
logger.log(Level.INFO, "metrics export interval (seconds) = " + exportSeconds);
56+
57+
connectorBuilder = JmxConnectorBuilder.createNew(scraperConfig.getServiceUrl());
58+
59+
Optional.ofNullable(scraperConfig.getUsername()).ifPresent(connectorBuilder::withUser);
60+
Optional.ofNullable(scraperConfig.getPassword()).ifPresent(connectorBuilder::withPassword);
61+
62+
if (scraperConfig.isRegistrySsl()) {
63+
connectorBuilder.withSslRegistry();
64+
}
65+
4866
return result;
4967
}
5068

@@ -60,4 +78,11 @@ public JmxScraperConfig getScraperConfig() {
6078
}
6179
return scraperConfig;
6280
}
81+
82+
public JmxConnectorBuilder getConnectorBuilder() {
83+
if (connectorBuilder == null) {
84+
throw new IllegalStateException("apply() must be called before getConnectorBuilder()");
85+
}
86+
return connectorBuilder;
87+
}
6388
}

0 commit comments

Comments
 (0)