Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
45 changes: 42 additions & 3 deletions argus-agent/src/main/java/io/argus/agent/ArgusAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import io.argus.agent.config.AgentConfig;
import io.argus.agent.jfr.JfrStreamingEngine;
import io.argus.core.buffer.RingBuffer;
import io.argus.core.event.CPUEvent;
import io.argus.core.event.GCEvent;
import io.argus.core.event.VirtualThreadEvent;
import io.argus.server.ArgusServer;

Expand Down Expand Up @@ -45,6 +47,8 @@ public final class ArgusAgent {

private static volatile JfrStreamingEngine engine;
private static volatile RingBuffer<VirtualThreadEvent> eventBuffer;
private static volatile RingBuffer<GCEvent> gcEventBuffer;
private static volatile RingBuffer<CPUEvent> cpuEventBuffer;
private static volatile ArgusServer server;
private static volatile AgentConfig config;

Expand Down Expand Up @@ -79,12 +83,29 @@ private static void initialize(String agentArgs) {
// Load configuration
config = AgentConfig.fromSystemProperties();

// Initialize event buffer
// Initialize event buffers
eventBuffer = new RingBuffer<>(config.getBufferSize());

// Initialize GC event buffer if enabled
if (config.isGcEnabled()) {
gcEventBuffer = new RingBuffer<>(config.getBufferSize());
}

// Initialize CPU event buffer if enabled
if (config.isCpuEnabled()) {
cpuEventBuffer = new RingBuffer<>(config.getBufferSize());
}

// Start JFR streaming engine
System.out.println("[Argus] Initializing JFR streaming engine...");
engine = new JfrStreamingEngine(eventBuffer);
engine = new JfrStreamingEngine(
eventBuffer,
gcEventBuffer,
cpuEventBuffer,
config.isGcEnabled(),
config.isCpuEnabled(),
config.getCpuIntervalMs()
);
engine.start();

// Start server if enabled
Expand All @@ -100,7 +121,7 @@ private static void initialize(String agentArgs) {
}

private static void startServer() {
server = new ArgusServer(config.getServerPort(), eventBuffer);
server = new ArgusServer(config.getServerPort(), eventBuffer, gcEventBuffer, cpuEventBuffer);
Thread.ofPlatform()
.name("argus-server")
.daemon(true)
Expand Down Expand Up @@ -147,6 +168,24 @@ public static RingBuffer<VirtualThreadEvent> getEventBuffer() {
return eventBuffer;
}

/**
* Returns the GC event buffer for consumers.
*
* @return GC event buffer, or null if GC monitoring is disabled
*/
public static RingBuffer<GCEvent> getGcEventBuffer() {
return gcEventBuffer;
}

/**
* Returns the CPU event buffer for consumers.
*
* @return CPU event buffer, or null if CPU monitoring is disabled
*/
public static RingBuffer<CPUEvent> getCpuEventBuffer() {
return cpuEventBuffer;
}

/**
* Returns the JFR streaming engine.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,35 @@
* <li>{@code argus.buffer.size} - Ring buffer size (default: 65536)</li>
* <li>{@code argus.server.enabled} - Enable built-in server (default: true)</li>
* <li>{@code argus.server.port} - Server port (default: 9202)</li>
* <li>{@code argus.gc.enabled} - Enable GC monitoring (default: true)</li>
* <li>{@code argus.cpu.enabled} - Enable CPU monitoring (default: true)</li>
* <li>{@code argus.cpu.interval} - CPU sampling interval in ms (default: 1000)</li>
* </ul>
*/
public final class AgentConfig {

private static final int DEFAULT_BUFFER_SIZE = 65536;
private static final int DEFAULT_SERVER_PORT = 9202;
private static final boolean DEFAULT_SERVER_ENABLED = true;
private static final boolean DEFAULT_GC_ENABLED = true;
private static final boolean DEFAULT_CPU_ENABLED = true;
private static final int DEFAULT_CPU_INTERVAL_MS = 1000;

private final int bufferSize;
private final int serverPort;
private final boolean serverEnabled;
private final boolean gcEnabled;
private final boolean cpuEnabled;
private final int cpuIntervalMs;

private AgentConfig(int bufferSize, int serverPort, boolean serverEnabled) {
private AgentConfig(int bufferSize, int serverPort, boolean serverEnabled,
boolean gcEnabled, boolean cpuEnabled, int cpuIntervalMs) {
this.bufferSize = bufferSize;
this.serverPort = serverPort;
this.serverEnabled = serverEnabled;
this.gcEnabled = gcEnabled;
this.cpuEnabled = cpuEnabled;
this.cpuIntervalMs = cpuIntervalMs;
}

/**
Expand All @@ -39,8 +52,13 @@ public static AgentConfig fromSystemProperties() {
int serverPort = Integer.getInteger("argus.server.port", DEFAULT_SERVER_PORT);
boolean serverEnabled = Boolean.parseBoolean(
System.getProperty("argus.server.enabled", String.valueOf(DEFAULT_SERVER_ENABLED)));
boolean gcEnabled = Boolean.parseBoolean(
System.getProperty("argus.gc.enabled", String.valueOf(DEFAULT_GC_ENABLED)));
boolean cpuEnabled = Boolean.parseBoolean(
System.getProperty("argus.cpu.enabled", String.valueOf(DEFAULT_CPU_ENABLED)));
int cpuIntervalMs = Integer.getInteger("argus.cpu.interval", DEFAULT_CPU_INTERVAL_MS);

return new AgentConfig(bufferSize, serverPort, serverEnabled);
return new AgentConfig(bufferSize, serverPort, serverEnabled, gcEnabled, cpuEnabled, cpuIntervalMs);
}

/**
Expand All @@ -49,7 +67,8 @@ public static AgentConfig fromSystemProperties() {
* @return default configuration
*/
public static AgentConfig defaults() {
return new AgentConfig(DEFAULT_BUFFER_SIZE, DEFAULT_SERVER_PORT, DEFAULT_SERVER_ENABLED);
return new AgentConfig(DEFAULT_BUFFER_SIZE, DEFAULT_SERVER_PORT, DEFAULT_SERVER_ENABLED,
DEFAULT_GC_ENABLED, DEFAULT_CPU_ENABLED, DEFAULT_CPU_INTERVAL_MS);
}

/**
Expand All @@ -73,12 +92,27 @@ public boolean isServerEnabled() {
return serverEnabled;
}

public boolean isGcEnabled() {
return gcEnabled;
}

public boolean isCpuEnabled() {
return cpuEnabled;
}

public int getCpuIntervalMs() {
return cpuIntervalMs;
}

@Override
public String toString() {
return "AgentConfig{" +
"bufferSize=" + bufferSize +
", serverPort=" + serverPort +
", serverEnabled=" + serverEnabled +
", gcEnabled=" + gcEnabled +
", cpuEnabled=" + cpuEnabled +
", cpuIntervalMs=" + cpuIntervalMs +
'}';
}

Expand All @@ -89,6 +123,9 @@ public static final class Builder {
private int bufferSize = DEFAULT_BUFFER_SIZE;
private int serverPort = DEFAULT_SERVER_PORT;
private boolean serverEnabled = DEFAULT_SERVER_ENABLED;
private boolean gcEnabled = DEFAULT_GC_ENABLED;
private boolean cpuEnabled = DEFAULT_CPU_ENABLED;
private int cpuIntervalMs = DEFAULT_CPU_INTERVAL_MS;

private Builder() {
}
Expand All @@ -108,8 +145,24 @@ public Builder serverEnabled(boolean serverEnabled) {
return this;
}

public Builder gcEnabled(boolean gcEnabled) {
this.gcEnabled = gcEnabled;
return this;
}

public Builder cpuEnabled(boolean cpuEnabled) {
this.cpuEnabled = cpuEnabled;
return this;
}

public Builder cpuIntervalMs(int cpuIntervalMs) {
this.cpuIntervalMs = cpuIntervalMs;
return this;
}

public AgentConfig build() {
return new AgentConfig(bufferSize, serverPort, serverEnabled);
return new AgentConfig(bufferSize, serverPort, serverEnabled,
gcEnabled, cpuEnabled, cpuIntervalMs);
}
}
}
101 changes: 101 additions & 0 deletions argus-agent/src/main/java/io/argus/agent/jfr/CPUEventExtractor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.argus.agent.jfr;

import io.argus.core.event.CPUEvent;
import jdk.jfr.consumer.RecordedEvent;

import java.time.Instant;

/**
* Extracts CPU event data from JFR RecordedEvent objects.
*
* <p>This class handles extraction of CPU load information
* from the {@code jdk.CPULoad} JFR event.
*/
public final class CPUEventExtractor {

/**
* Extracts a CPUEvent from a jdk.CPULoad JFR event.
*
* @param event the JFR event
* @return the extracted CPUEvent
*/
public CPUEvent extractCPULoad(RecordedEvent event) {
Instant timestamp = event.getStartTime();
double jvmUser = extractJvmUser(event);
double jvmSystem = extractJvmSystem(event);
double machineTotal = extractMachineTotal(event);

return CPUEvent.of(timestamp, jvmUser, jvmSystem, machineTotal);
}

private double extractJvmUser(RecordedEvent event) {
// Try jvmUser field
try {
return event.getDouble("jvmUser");
} catch (Exception ignored) {
}

// Try jvmUserCPU field
try {
return event.getDouble("jvmUserCPU");
} catch (Exception ignored) {
}

return 0.0;
}

private double extractJvmSystem(RecordedEvent event) {
// Try jvmSystem field
try {
return event.getDouble("jvmSystem");
} catch (Exception ignored) {
}

// Try jvmSystemCPU field
try {
return event.getDouble("jvmSystemCPU");
} catch (Exception ignored) {
}

return 0.0;
}

private double extractMachineTotal(RecordedEvent event) {
// Try machineTotal field
try {
return event.getDouble("machineTotal");
} catch (Exception ignored) {
}

// Try machineCPU field
try {
return event.getDouble("machineCPU");
} catch (Exception ignored) {
}

// Try systemTotal field
try {
return event.getDouble("systemTotal");
} catch (Exception ignored) {
}

return 0.0;
}

/**
* Debug method to print all available fields in a CPU JFR event.
*/
public void debugPrintFields(RecordedEvent event) {
System.out.println("[Argus Debug] CPU Event: " + event.getEventType().getName());
event.getFields().forEach(field -> {
try {
Object value = event.getValue(field.getName());
System.out.printf(" %s (%s) = %s%n",
field.getName(), field.getTypeName(), value);
} catch (Exception e) {
System.out.printf(" %s (%s) = ERROR: %s%n",
field.getName(), field.getTypeName(), e.getMessage());
}
});
}
}
Loading