Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/main/java/io/cryostat/agent/CryostatClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,60 @@ public CompletableFuture<Void> update(
}
}

public CompletableFuture<Void> pushHeapDump(int maxFiles, String fileName, Path heapDump)
throws IOException {
Instant start = Instant.now();

HttpPost req =
new HttpPost(baseUri.resolve("/api/beta/diagnostics/heapdump/upload/" + jvmId));

CountingInputStream is = getRecordingInputStream(heapDump);

MultipartEntityBuilder entityBuilder =
MultipartEntityBuilder.create()
.addPart(
FormBodyPartBuilder.create(
"heapDump",
new InputStreamBody(
is,
ContentType.APPLICATION_OCTET_STREAM,
fileName))
.build())
.addPart(
FormBodyPartBuilder.create(
"maxFiles",
new StringBody(
Integer.toString(maxFiles),
ContentType.TEXT_PLAIN))
.build());
req.setEntity(entityBuilder.build());
return supply(
req,
(res) -> {
Instant finish = Instant.now();
log.trace(
"{} {} ({} -> {}): {}/{}",
req.getMethod(),
res.getStatusLine().getStatusCode(),
fileName,
req.getURI(),
FileUtils.byteCountToDisplaySize(is.getByteCount()),
Duration.between(start, finish));
assertOkStatus(req, res);
return (Void) null;
})
.whenComplete(
(v, t) -> {
// Heap dump files tend to be very large, clean up after uploading
try {
Files.delete(heapDump);
} catch (IOException ioe) {
log.warn("Failed to delete heap dump: ", heapDump.toString());
}
req.reset();
});
}

public CompletableFuture<Void> upload(
Harvester.PushType pushType,
Optional<TemplatedRecording> opt,
Expand Down
34 changes: 32 additions & 2 deletions src/main/java/io/cryostat/agent/remote/InvokeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;

import javax.inject.Inject;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import io.cryostat.agent.CryostatClient;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.net.httpserver.HttpExchange;
import org.apache.http.HttpStatus;
Expand All @@ -40,10 +44,13 @@ class InvokeContext extends MutatingRemoteContext {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ObjectMapper mapper;

private CryostatClient client;

@Inject
InvokeContext(ObjectMapper mapper, Config config) {
InvokeContext(ObjectMapper mapper, Config config, CryostatClient client) {
super(config);
this.mapper = mapper;
this.client = client;
}

@Override
Expand All @@ -64,6 +71,9 @@ public void handle(HttpExchange exchange) throws IOException {
exchange.sendResponseHeaders(
HttpStatus.SC_BAD_REQUEST, BODY_LENGTH_NONE);
}
log.warn(
"Dumping heap with parameters: "
+ Arrays.asList(req.parameters).toString());
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
Object response =
server.invoke(
Expand All @@ -72,6 +82,14 @@ public void handle(HttpExchange exchange) throws IOException {
req.parameters,
req.signature);

// TODO: Verify if dumpHeap is blocking, if so we should split the
// invocation
// into a separate thread and listen for when it finishes
Comment thread
andrewazores marked this conversation as resolved.
Outdated
if (req.getOperation().equals("dumpHeap")) {
String fileName = req.getParameters()[0].toString();
Comment thread
Josh-Matsuoka marked this conversation as resolved.
Outdated
client.pushHeapDump(1, fileName, Paths.get(fileName));
}

if (Objects.nonNull(response)) {
exchange.sendResponseHeaders(HttpStatus.SC_OK, BODY_LENGTH_UNKNOWN);
try (OutputStream responseStream = exchange.getResponseBody()) {
Expand Down Expand Up @@ -103,8 +121,12 @@ static class MBeanInvocationRequest<T> {
public Object[] parameters;
public String[] signature;

private static final String HOTSPOT_DIAGNOSTIC_BEAN_NAME =
"com.sun.management:type=HotSpotDiagnostic";

public boolean isValid() {
if (this.beanName.equals(ManagementFactory.MEMORY_MXBEAN_NAME)) {
if (this.beanName.equals(ManagementFactory.MEMORY_MXBEAN_NAME)
|| this.beanName.equals(HOTSPOT_DIAGNOSTIC_BEAN_NAME)) {
return true;
} else if (this.beanName.equals(DIAGNOSTIC_BEAN_NAME)
&& (this.operation.equals(DUMP_THREADS)
Expand All @@ -114,6 +136,14 @@ public boolean isValid() {
return false;
}

public Object[] getParameters() {
return parameters;
}

public void setParameters(Object[] parameters) {
this.parameters = parameters;
}

public String getBeanName() {
return beanName;
}
Expand Down
Loading