-
Notifications
You must be signed in to change notification settings - Fork 146
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
jmx scraper with sdk autoconfig #1651
Changes from 14 commits
e7747ee
d3afdcd
3f17316
252e554
3fbf71d
45ce9be
96c6250
1a4ab3e
6793bbe
6924d9c
ce43846
1271bba
62d41a5
44e8f6e
0f25c60
20c5cc9
7288ef3
55a1e0e
dc064db
857ac4d
646e156
d237a56
851ad44
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 |
---|---|---|
|
@@ -6,11 +6,14 @@ | |
package io.opentelemetry.contrib.jmxscraper; | ||
|
||
import io.opentelemetry.api.GlobalOpenTelemetry; | ||
import io.opentelemetry.contrib.jmxscraper.config.ConfigurationException; | ||
import io.opentelemetry.contrib.jmxscraper.config.JmxScraperConfig; | ||
import io.opentelemetry.contrib.jmxscraper.config.PropertiesCustomizer; | ||
import io.opentelemetry.contrib.jmxscraper.config.PropertiesSupplier; | ||
import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; | ||
import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; | ||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; | ||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; | ||
import java.io.DataInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
@@ -19,9 +22,11 @@ | |
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Properties; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import javax.management.MBeanServerConnection; | ||
import javax.management.remote.JMXConnector; | ||
|
@@ -30,8 +35,6 @@ public class JmxScraper { | |
private static final Logger logger = Logger.getLogger(JmxScraper.class.getName()); | ||
private static final String CONFIG_ARG = "-config"; | ||
|
||
private static final String OTEL_AUTOCONFIGURE = "otel.java.global-autoconfigure.enabled"; | ||
|
||
private final JmxConnectorBuilder client; | ||
private final JmxMetricInsight service; | ||
private final JmxScraperConfig config; | ||
|
@@ -43,58 +46,77 @@ public class JmxScraper { | |
* | ||
* @param args - must be of the form "-config {jmx_config_path,'-'}" | ||
*/ | ||
@SuppressWarnings({"SystemOut", "SystemExitOutsideMain"}) | ||
@SuppressWarnings("SystemExitOutsideMain") | ||
public static void main(String[] args) { | ||
|
||
// enable SDK auto-configure if not explicitly set by user | ||
// TODO: refactor this to use AutoConfiguredOpenTelemetrySdk | ||
if (System.getProperty(OTEL_AUTOCONFIGURE) == null) { | ||
System.setProperty(OTEL_AUTOCONFIGURE, "true"); | ||
} | ||
// set log format | ||
System.setProperty("java.util.logging.SimpleFormatter.format", "%1$tF %1$tT %4$s %5$s%n"); | ||
|
||
try { | ||
JmxScraperConfig config = | ||
JmxScraperConfig.fromProperties(parseArgs(Arrays.asList(args)), System.getProperties()); | ||
// propagate effective user-provided configuration to JVM system properties | ||
// this also enables SDK auto-configuration to use those properties | ||
config.propagateSystemProperties(); | ||
Properties argsConfig = parseArgs(Arrays.asList(args)); | ||
propagateToSystemProperties(argsConfig); | ||
|
||
// auto-configure and register SDK | ||
PropertiesCustomizer configCustomizer = new PropertiesCustomizer(); | ||
AutoConfiguredOpenTelemetrySdk.builder() | ||
.addPropertiesSupplier(new PropertiesSupplier(argsConfig)) | ||
.addPropertiesCustomizer(configCustomizer) | ||
.setResultAsGlobal() | ||
.build(); | ||
|
||
JmxScraperConfig scraperConfig = configCustomizer.getScraperConfig(); | ||
|
||
long exportSeconds = scraperConfig.getSamplingInterval().toMillis() / 1000; | ||
logger.log(Level.INFO, "metrics export interval (seconds) = " + exportSeconds); | ||
|
||
JmxMetricInsight service = | ||
JmxMetricInsight.createService( | ||
GlobalOpenTelemetry.get(), config.getIntervalMilliseconds()); | ||
JmxConnectorBuilder connectorBuilder = JmxConnectorBuilder.createNew(config.getServiceUrl()); | ||
GlobalOpenTelemetry.get(), scraperConfig.getSamplingInterval().toMillis()); | ||
JmxConnectorBuilder connectorBuilder = | ||
JmxConnectorBuilder.createNew(scraperConfig.getServiceUrl()); | ||
|
||
Optional.ofNullable(config.getUsername()).ifPresent(connectorBuilder::withUser); | ||
Optional.ofNullable(config.getPassword()).ifPresent(connectorBuilder::withPassword); | ||
Optional.ofNullable(scraperConfig.getUsername()).ifPresent(connectorBuilder::withUser); | ||
Optional.ofNullable(scraperConfig.getPassword()).ifPresent(connectorBuilder::withPassword); | ||
|
||
JmxScraper jmxScraper = new JmxScraper(connectorBuilder, service, config); | ||
JmxScraper jmxScraper = new JmxScraper(connectorBuilder, service, scraperConfig); | ||
jmxScraper.start(); | ||
|
||
} catch (ConfigurationException e) { | ||
logger.log(Level.SEVERE, "ERROR: invalid configuration ", e); | ||
SylvainJuge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
System.exit(1); | ||
} catch (ArgumentsParsingException e) { | ||
System.err.println("ERROR: " + e.getMessage()); | ||
System.err.println( | ||
logger.log(Level.SEVERE, "ERROR: invalid configuration provided through arguments", e); | ||
SylvainJuge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
logger.info( | ||
"Usage: java -jar <path_to_jmxscraper.jar> " | ||
+ "-config <path_to_config.properties or - for stdin>"); | ||
System.exit(1); | ||
} catch (ConfigurationException e) { | ||
System.err.println(e.getMessage()); | ||
System.exit(1); | ||
} catch (IOException e) { | ||
System.err.println("Unable to connect " + e.getMessage()); | ||
logger.log(Level.SEVERE, "Unable to connect ", e); | ||
System.exit(2); | ||
} catch (RuntimeException e) { | ||
e.printStackTrace(System.err); | ||
logger.log(Level.SEVERE, e.getMessage(), e); | ||
System.exit(3); | ||
} | ||
} | ||
|
||
// package private for testing | ||
static void propagateToSystemProperties(Properties properties) { | ||
for (Map.Entry<Object, Object> entry : properties.entrySet()) { | ||
String key = entry.getKey().toString(); | ||
String value = entry.getValue().toString(); | ||
if (key.startsWith("javax.net.ssl.keyStore") || key.startsWith("javax.net.ssl.trustStore")) { | ||
if (System.getProperty(key) == null) { | ||
System.setProperty(key, value); | ||
} | ||
} | ||
} | ||
} | ||
Comment on lines
+102
to
+112
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. [for reviewer] propagation of system properties is only used to set the java keystore/truststore options from the program arguments/standard input to the global JVM settings, so it was simpler to move it here. In practice this will likely be tested when we add tests with custom keystore/truststore by setting those configuration options from the standard input or the properties file. |
||
|
||
/** | ||
* Create {@link Properties} from command line options | ||
* | ||
* @param args application commandline arguments | ||
*/ | ||
static Properties parseArgs(List<String> args) | ||
throws ArgumentsParsingException, ConfigurationException { | ||
static Properties parseArgs(List<String> args) throws ArgumentsParsingException { | ||
|
||
if (args.isEmpty()) { | ||
// empty properties from stdin or external file | ||
|
@@ -116,23 +138,24 @@ static Properties parseArgs(List<String> args) | |
} | ||
} | ||
|
||
private static Properties loadPropertiesFromStdin() throws ConfigurationException { | ||
private static Properties loadPropertiesFromStdin() throws ArgumentsParsingException { | ||
Properties properties = new Properties(); | ||
try (InputStream is = new DataInputStream(System.in)) { | ||
properties.load(is); | ||
return properties; | ||
} catch (IOException e) { | ||
throw new ConfigurationException("Failed to read config properties from stdin", e); | ||
throw new ArgumentsParsingException("Failed to read config properties from stdin", e); | ||
SylvainJuge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
private static Properties loadPropertiesFromPath(String path) throws ConfigurationException { | ||
private static Properties loadPropertiesFromPath(String path) throws ArgumentsParsingException { | ||
Properties properties = new Properties(); | ||
try (InputStream is = Files.newInputStream(Paths.get(path))) { | ||
properties.load(is); | ||
return properties; | ||
} catch (IOException e) { | ||
throw new ConfigurationException("Failed to read config properties file: '" + path + "'", e); | ||
throw new ArgumentsParsingException( | ||
"Failed to read config properties file: '" + path + "'", e); | ||
} | ||
} | ||
|
||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[for reviewer] this is never changed for tests, so we can use the minimal hard-coded value of 1s.