55
66package io .opentelemetry .contrib .jmxscraper ;
77
8+ import static io .opentelemetry .semconv .incubating .ServiceIncubatingAttributes .SERVICE_INSTANCE_ID ;
89import static java .util .Arrays .asList ;
910import static java .util .Collections .singletonList ;
10- import static java .util .Optional .ofNullable ;
1111import static java .util .logging .Level .INFO ;
1212import static java .util .logging .Level .SEVERE ;
1313
14- import io .opentelemetry .api .GlobalOpenTelemetry ;
14+ import io .opentelemetry .api .OpenTelemetry ;
15+ import io .opentelemetry .api .common .Attributes ;
1516import io .opentelemetry .contrib .jmxscraper .config .JmxScraperConfig ;
1617import io .opentelemetry .contrib .jmxscraper .config .PropertiesCustomizer ;
1718import io .opentelemetry .contrib .jmxscraper .config .PropertiesSupplier ;
1819import io .opentelemetry .instrumentation .jmx .engine .JmxMetricInsight ;
1920import io .opentelemetry .instrumentation .jmx .engine .MetricConfiguration ;
2021import io .opentelemetry .instrumentation .jmx .yaml .RuleParser ;
2122import io .opentelemetry .sdk .autoconfigure .AutoConfiguredOpenTelemetrySdk ;
23+ import io .opentelemetry .sdk .autoconfigure .spi .ConfigProperties ;
2224import io .opentelemetry .sdk .autoconfigure .spi .ConfigurationException ;
25+ import io .opentelemetry .sdk .resources .Resource ;
2326import java .io .DataInputStream ;
2427import java .io .IOException ;
2528import java .io .InputStream ;
29+ import java .nio .charset .StandardCharsets ;
2630import java .nio .file .Files ;
2731import java .nio .file .Path ;
2832import java .nio .file .Paths ;
2933import java .util .ArrayList ;
34+ import java .util .Arrays ;
3035import java .util .List ;
3136import java .util .Map ;
3237import java .util .Properties ;
38+ import java .util .UUID ;
3339import java .util .concurrent .atomic .AtomicBoolean ;
40+ import java .util .function .BiFunction ;
3441import java .util .logging .Logger ;
42+ import javax .annotation .Nullable ;
3543import javax .management .MBeanServerConnection ;
44+ import javax .management .ObjectName ;
3645import javax .management .remote .JMXConnector ;
3746
3847public final class JmxScraper {
48+
3949 private static final Logger logger = Logger .getLogger (JmxScraper .class .getName ());
4050 private static final String CONFIG_ARG = "-config" ;
4151 private static final String TEST_ARG = "-test" ;
@@ -64,36 +74,41 @@ public static void main(String[] args) {
6474 Properties argsConfig = argsToConfig (effectiveArgs );
6575 propagateToSystemProperties (argsConfig );
6676
67- // auto-configure and register SDK
6877 PropertiesCustomizer configCustomizer = new PropertiesCustomizer ();
69- AutoConfiguredOpenTelemetrySdk .builder ()
70- .addPropertiesSupplier (new PropertiesSupplier (argsConfig ))
71- .addPropertiesCustomizer (configCustomizer )
72- .setResultAsGlobal ()
73- .build ();
7478
79+ // we rely on the config customizer to be executed first to get effective config.
80+ BiFunction <Resource , ConfigProperties , Resource > resourceCustomizer =
81+ (resource , configProperties ) -> {
82+ UUID instanceId = getRemoteServiceInstanceId (configCustomizer .getConnectorBuilder ());
83+ if (resource .getAttribute (SERVICE_INSTANCE_ID ) != null || instanceId == null ) {
84+ return resource ;
85+ }
86+ logger .log (INFO , "remote service instance ID: " + instanceId );
87+ return resource .merge (
88+ Resource .create (Attributes .of (SERVICE_INSTANCE_ID , instanceId .toString ())));
89+ };
90+
91+ // auto-configure SDK
92+ OpenTelemetry openTelemetry =
93+ AutoConfiguredOpenTelemetrySdk .builder ()
94+ .addPropertiesSupplier (new PropertiesSupplier (argsConfig ))
95+ .addPropertiesCustomizer (configCustomizer )
96+ .addResourceCustomizer (resourceCustomizer )
97+ .build ()
98+ .getOpenTelemetrySdk ();
99+
100+ // scraper configuration and connector builder are built using effective SDK configuration
101+ // thus we have to get it after the SDK is built
75102 JmxScraperConfig scraperConfig = configCustomizer .getScraperConfig ();
76-
77- long exportSeconds = scraperConfig .getSamplingInterval ().toMillis () / 1000 ;
78- logger .log (INFO , "metrics export interval (seconds) = " + exportSeconds );
79-
80- JmxMetricInsight service =
81- JmxMetricInsight .createService (
82- GlobalOpenTelemetry .get (), scraperConfig .getSamplingInterval ().toMillis ());
83- JmxConnectorBuilder connectorBuilder =
84- JmxConnectorBuilder .createNew (scraperConfig .getServiceUrl ());
85-
86- ofNullable (scraperConfig .getUsername ()).ifPresent (connectorBuilder ::withUser );
87- ofNullable (scraperConfig .getPassword ()).ifPresent (connectorBuilder ::withPassword );
88-
89- if (scraperConfig .isRegistrySsl ()) {
90- connectorBuilder .withSslRegistry ();
91- }
103+ JmxConnectorBuilder connectorBuilder = configCustomizer .getConnectorBuilder ();
92104
93105 if (testMode ) {
94106 System .exit (testConnection (connectorBuilder ) ? 0 : 1 );
95107 } else {
96- JmxScraper jmxScraper = new JmxScraper (connectorBuilder , service , scraperConfig );
108+ JmxMetricInsight jmxInsight =
109+ JmxMetricInsight .createService (
110+ openTelemetry , scraperConfig .getSamplingInterval ().toMillis ());
111+ JmxScraper jmxScraper = new JmxScraper (connectorBuilder , jmxInsight , scraperConfig );
97112 jmxScraper .start ();
98113 }
99114 } catch (ConfigurationException e ) {
@@ -117,7 +132,6 @@ public static void main(String[] args) {
117132
118133 private static boolean testConnection (JmxConnectorBuilder connectorBuilder ) {
119134 try (JMXConnector connector = connectorBuilder .build ()) {
120-
121135 MBeanServerConnection connection = connector .getMBeanServerConnection ();
122136 Integer mbeanCount = connection .getMBeanCount ();
123137 if (mbeanCount > 0 ) {
@@ -133,6 +147,30 @@ private static boolean testConnection(JmxConnectorBuilder connectorBuilder) {
133147 }
134148 }
135149
150+ @ Nullable
151+ private static UUID getRemoteServiceInstanceId (JmxConnectorBuilder connectorBuilder ) {
152+ try (JMXConnector jmxConnector = connectorBuilder .build ()) {
153+ MBeanServerConnection connection = jmxConnector .getMBeanServerConnection ();
154+
155+ StringBuilder id = new StringBuilder ();
156+ try {
157+ ObjectName objectName = new ObjectName ("java.lang:type=Runtime" );
158+ for (String attribute : Arrays .asList ("StartTime" , "Name" )) {
159+ Object value = connection .getAttribute (objectName , attribute );
160+ if (id .length () > 0 ) {
161+ id .append (" " );
162+ }
163+ id .append (value );
164+ }
165+ return UUID .nameUUIDFromBytes (id .toString ().getBytes (StandardCharsets .UTF_8 ));
166+ } catch (Exception e ) {
167+ throw new IllegalStateException (e );
168+ }
169+ } catch (IOException e ) {
170+ return null ;
171+ }
172+ }
173+
136174 // package private for testing
137175 static void propagateToSystemProperties (Properties properties ) {
138176 for (Map .Entry <Object , Object > entry : properties .entrySet ()) {
0 commit comments