diff --git a/src/main/java/io/cryostat/agent/Agent.java b/src/main/java/io/cryostat/agent/Agent.java index 495c96c7..11d8eb71 100644 --- a/src/main/java/io/cryostat/agent/Agent.java +++ b/src/main/java/io/cryostat/agent/Agent.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.lang.instrument.Instrumentation; +import java.lang.management.ManagementFactory; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Path; @@ -36,6 +37,8 @@ import javax.inject.Named; import javax.inject.Singleton; +import javax.management.MBeanServer; +import javax.management.ObjectName; import io.cryostat.agent.ConfigModule.URIRange; import io.cryostat.agent.VersionInfo.Semver; @@ -44,6 +47,7 @@ import io.cryostat.agent.model.PluginInfo; import io.cryostat.agent.shaded.ShadeLogger; import io.cryostat.agent.triggers.TriggerEvaluator; +import io.cryostat.libcryostat.net.CryostatAgentMXBean; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; @@ -240,6 +244,10 @@ public void accept(AgentArgs args) { try { final Client client = DaggerAgent_Client.builder().build(); + CryostatAgentMXBean mxBean = client.agentMXBean(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + mbs.registerMBean(mxBean, new ObjectName(CryostatAgentMXBean.OBJECT_NAME)); + boolean sample = client.fleetSampleValue() < client.fleetSamplingRatio(); log.trace( "fleetSampleValue: {} , fleetSampleRatio: {}", @@ -378,6 +386,8 @@ interface Client { @Named(ConfigModule.CRYOSTAT_AGENT_BASEURI_RANGE) URIRange uriRange(); + CryostatAgent agentMXBean(); + WebServer webServer(); Registration registration(); diff --git a/src/main/java/io/cryostat/agent/ConfigModule.java b/src/main/java/io/cryostat/agent/ConfigModule.java index 4833e621..ebba99c8 100644 --- a/src/main/java/io/cryostat/agent/ConfigModule.java +++ b/src/main/java/io/cryostat/agent/ConfigModule.java @@ -50,6 +50,7 @@ import io.cryostat.agent.util.ResourcesUtil; import io.cryostat.agent.util.StringUtils; +import io.cryostat.libcryostat.net.CryostatAgentMXBean; import dagger.Module; import dagger.Provides; @@ -819,6 +820,13 @@ public static String provideCryostatAgentInstanceId(Config config) { .orElseGet(() -> UUID.randomUUID().toString()); } + @Provides + @Singleton + public static CryostatAgentMXBean provideCryostatAgentMXBean( + @Named(CRYOSTAT_AGENT_INSTANCE_ID) String id) { + return new CryostatAgent(id); + } + @Provides @Singleton @Named(CRYOSTAT_AGENT_APP_NAME) diff --git a/src/main/java/io/cryostat/agent/CryostatAgent.java b/src/main/java/io/cryostat/agent/CryostatAgent.java new file mode 100644 index 00000000..301d61de --- /dev/null +++ b/src/main/java/io/cryostat/agent/CryostatAgent.java @@ -0,0 +1,36 @@ +/* + * Copyright The Cryostat Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cryostat.agent; + +import javax.inject.Inject; +import javax.inject.Named; + +import io.cryostat.libcryostat.net.CryostatAgentMXBean; + +public class CryostatAgent implements CryostatAgentMXBean { + + private final String id; + + @Inject + CryostatAgent(@Named(ConfigModule.CRYOSTAT_AGENT_INSTANCE_ID) String id) { + this.id = id; + } + + @Override + public String getId() { + return id.toString(); + } +} diff --git a/src/main/java/io/cryostat/agent/MainModule.java b/src/main/java/io/cryostat/agent/MainModule.java index 46697b21..82724783 100644 --- a/src/main/java/io/cryostat/agent/MainModule.java +++ b/src/main/java/io/cryostat/agent/MainModule.java @@ -825,9 +825,9 @@ public static FlightRecorderHelper provideFlightRecorderHelper() { @Provides @Singleton @Named(JVM_ID) - public static String provideJvmId() { + public static String provideJvmId(@Named(ConfigModule.CRYOSTAT_AGENT_INSTANCE_ID) String id) { try { - return JvmIdentifier.getLocal().getHash(); + return JvmIdentifier.getLocal(id).getHash(); } catch (IDException e) { throw new RuntimeException(e); } diff --git a/src/main/java/io/cryostat/agent/remote/InvokeContext.java b/src/main/java/io/cryostat/agent/remote/InvokeContext.java index 7fdf7873..17df2031 100644 --- a/src/main/java/io/cryostat/agent/remote/InvokeContext.java +++ b/src/main/java/io/cryostat/agent/remote/InvokeContext.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.management.ManagementFactory; +import java.nio.file.Files; import java.nio.file.Paths; import java.util.Objects; import java.util.UUID; @@ -45,7 +46,6 @@ class InvokeContext extends MutatingRemoteContext { private static final String DUMP_THREADS = "threadPrint"; private static final String DUMP_THREADS_TO_FIlE = "threadDumpToFile"; - private static final String DIAGNOSTIC_BEAN_NAME = "com.sun.management:type=DiagnosticCommand"; private final Logger log = LoggerFactory.getLogger(getClass()); private final ObjectMapper mapper; @@ -74,7 +74,12 @@ public void handle(HttpExchange exchange) throws IOException { mapper.readValue(body, MBeanInvocationRequest.class); String requestId = ""; String filename = - config.getValue(ConfigModule.CRYOSTAT_AGENT_APP_NAME, String.class); + Files.createTempFile( + config.getValue( + ConfigModule.CRYOSTAT_AGENT_APP_NAME, + String.class), + (String) null) + .toString(); if (!req.isValid()) { exchange.sendResponseHeaders( HttpStatus.SC_BAD_REQUEST, BODY_LENGTH_NONE); @@ -138,16 +143,24 @@ static class MBeanInvocationRequest { public Object[] parameters; public String[] signature; + private static final String CRYOSTAT_AGENT_BEAN_NAME = + "io.cryostat.agent.CryostatAgent:name=agent"; private static final String HOTSPOT_DIAGNOSTIC_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"; + private static final String DIAGNOSTIC_COMMAND_BEAN_NAME = + "com.sun.management:type=DiagnosticCommand"; public boolean isValid() { - if (this.beanName.equals(ManagementFactory.MEMORY_MXBEAN_NAME) - || this.beanName.equals(HOTSPOT_DIAGNOSTIC_BEAN_NAME)) { + if (CRYOSTAT_AGENT_BEAN_NAME.equals(beanName)) { return true; - } else if (this.beanName.equals(DIAGNOSTIC_BEAN_NAME) - && (this.operation.equals(DUMP_THREADS) - || this.operation.equals(DUMP_THREADS_TO_FIlE))) { + } + if (ManagementFactory.MEMORY_MXBEAN_NAME.equals(beanName) + || HOTSPOT_DIAGNOSTIC_BEAN_NAME.equals(beanName)) { + return true; + } + if (DIAGNOSTIC_COMMAND_BEAN_NAME.equals(beanName) + && (DUMP_THREADS.equals(this.operation) + || DUMP_THREADS_TO_FIlE.equals(this.operation))) { return true; } return false;