001package io.prometheus.jmx; 002 003import java.io.File; 004import java.lang.instrument.Instrumentation; 005import java.net.InetSocketAddress; 006import java.util.regex.Matcher; 007import java.util.regex.Pattern; 008 009import io.prometheus.client.CollectorRegistry; 010import io.prometheus.client.exporter.HTTPServer; 011import io.prometheus.client.hotspot.DefaultExports; 012 013public class JavaAgent { 014 015 static HTTPServer server; 016 017 public static void agentmain(String agentArgument, Instrumentation instrumentation) throws Exception { 018 premain(agentArgument, instrumentation); 019 } 020 021 public static void premain(String agentArgument, Instrumentation instrumentation) throws Exception { 022 // Bind to all interfaces by default (this includes IPv6). 023 String host = "0.0.0.0"; 024 025 try { 026 Config config = parseConfig(agentArgument, host); 027 028 new BuildInfoCollector().register(); 029 new JmxCollector(new File(config.file)).register(); 030 DefaultExports.initialize(); 031 server = new HTTPServer(config.socket, CollectorRegistry.defaultRegistry, true); 032 } 033 catch (IllegalArgumentException e) { 034 System.err.println("Usage: -javaagent:/path/to/JavaAgent.jar=[host:]<port>:<yaml configuration file>"); 035 System.exit(1); 036 } 037 } 038 039 /** 040 * Parse the Java Agent configuration. The arguments are typically specified to the JVM as a javaagent as 041 * {@code -javaagent:/path/to/agent.jar=<CONFIG>}. This method parses the {@code <CONFIG>} portion. 042 * @param args provided agent args 043 * @param ifc default bind interface 044 * @return configuration to use for our application 045 */ 046 public static Config parseConfig(String args, String ifc) { 047 Pattern pattern = Pattern.compile( 048 "^(?:((?:[\\w.]+)|(?:\\[.+])):)?" + // host name, or ipv4, or ipv6 address in brackets 049 "(\\d{1,5}):" + // port 050 "(.+)"); // config file 051 052 Matcher matcher = pattern.matcher(args); 053 if (!matcher.matches()) { 054 throw new IllegalArgumentException("Malformed arguments - " + args); 055 } 056 057 String givenHost = matcher.group(1); 058 String givenPort = matcher.group(2); 059 String givenConfigFile = matcher.group(3); 060 061 int port = Integer.parseInt(givenPort); 062 063 InetSocketAddress socket; 064 if (givenHost != null && !givenHost.isEmpty()) { 065 socket = new InetSocketAddress(givenHost, port); 066 } 067 else { 068 socket = new InetSocketAddress(ifc, port); 069 givenHost = ifc; 070 } 071 072 return new Config(givenHost, port, givenConfigFile, socket); 073 } 074 075 static class Config { 076 String host; 077 int port; 078 String file; 079 InetSocketAddress socket; 080 081 Config(String host, int port, String file, InetSocketAddress socket) { 082 this.host = host; 083 this.port = port; 084 this.file = file; 085 this.socket = socket; 086 } 087 } 088}