001/* 002 * Copyright (C) 2015-2023 The Prometheus jmx_exporter Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package io.prometheus.jmx; 018 019import io.prometheus.client.CollectorRegistry; 020import io.prometheus.client.exporter.HTTPServer; 021import io.prometheus.client.hotspot.DefaultExports; 022import io.prometheus.jmx.common.http.ConfigurationException; 023import io.prometheus.jmx.common.http.HTTPServerFactory; 024import java.io.File; 025import java.lang.instrument.Instrumentation; 026import java.net.InetSocketAddress; 027import java.util.regex.Matcher; 028import java.util.regex.Pattern; 029 030public class JavaAgent { 031 032 public static final String CONFIGURATION_REGEX = 033 "^(?:((?:[\\w.-]+)|(?:\\[.+])):)?" 034 + // host name, or ipv4, or ipv6 address in brackets 035 "(\\d{1,5}):" 036 + // port 037 "(.+)"; // config file 038 039 static HTTPServer server; 040 041 public static void agentmain(String agentArgument, Instrumentation instrumentation) 042 throws Exception { 043 premain(agentArgument, instrumentation); 044 } 045 046 public static void premain(String agentArgument, Instrumentation instrumentation) 047 throws Exception { 048 // Bind to all interfaces by default (this includes IPv6). 049 String host = "0.0.0.0"; 050 051 try { 052 Config config = parseConfig(agentArgument, host); 053 054 new BuildInfoCollector().register(); 055 new JmxCollector(new File(config.file), JmxCollector.Mode.AGENT).register(); 056 DefaultExports.initialize(); 057 058 server = 059 new HTTPServerFactory() 060 .createHTTPServer( 061 config.socket, 062 CollectorRegistry.defaultRegistry, 063 true, 064 new File(config.file)); 065 } catch (ConfigurationException e) { 066 System.err.println("Configuration Exception : " + e.getMessage()); 067 System.exit(1); 068 } catch (IllegalArgumentException e) { 069 System.err.println( 070 "Usage: -javaagent:/path/to/JavaAgent.jar=[host:]<port>:<yaml configuration" 071 + " file> " 072 + e.getMessage()); 073 System.exit(1); 074 } 075 } 076 077 /** 078 * Parse the Java Agent configuration. The arguments are typically specified to the JVM as a 079 * javaagent as {@code -javaagent:/path/to/agent.jar=<CONFIG>}. This method parses the {@code 080 * <CONFIG>} portion. 081 * 082 * @param args provided agent args 083 * @param ifc default bind interface 084 * @return configuration to use for our application 085 */ 086 public static Config parseConfig(String args, String ifc) { 087 Pattern pattern = Pattern.compile(CONFIGURATION_REGEX); 088 089 Matcher matcher = pattern.matcher(args); 090 if (!matcher.matches()) { 091 throw new IllegalArgumentException("Malformed arguments - " + args); 092 } 093 094 String givenHost = matcher.group(1); 095 String givenPort = matcher.group(2); 096 String givenConfigFile = matcher.group(3); 097 098 int port = Integer.parseInt(givenPort); 099 100 InetSocketAddress socket; 101 if (givenHost != null && !givenHost.isEmpty()) { 102 socket = new InetSocketAddress(givenHost, port); 103 } else { 104 socket = new InetSocketAddress(ifc, port); 105 givenHost = ifc; 106 } 107 108 return new Config(givenHost, port, givenConfigFile, socket); 109 } 110 111 static class Config { 112 String host; 113 int port; 114 String file; 115 InetSocketAddress socket; 116 117 Config(String host, int port, String file, InetSocketAddress socket) { 118 this.host = host; 119 this.port = port; 120 this.file = file; 121 this.socket = socket; 122 } 123 } 124}