-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMonitor.java
118 lines (110 loc) · 3.77 KB
/
Monitor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicLong;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import jdk.jfr.consumer.EventStream;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedThread;
public final class Monitor {
private final static Map<String, EventStream> monitored = new HashMap<>();
private final static String REPOSITORY = "jdk.jfr.repository";
public static void main(String... args) throws InterruptedException {
System.out.println("JFR Event streaming client started.");
while (true) {
for (VirtualMachineDescriptor d : VirtualMachine.list()) {
try {
tryMonitor(d);
} catch (Exception e) {
// ignore
}
}
Thread.sleep(1000);
}
}
private static void tryMonitor(VirtualMachineDescriptor d) throws AttachNotSupportedException, IOException {
VirtualMachine vm = VirtualMachine.attach(d);
Properties p = vm.getSystemProperties();
String repo = p.getProperty(REPOSITORY);
if (repo != null) {
monitor(d.id(), d.displayName(), repo);
}
}
private static void monitor(String pid, String name, String repository) throws IOException {
if (monitored.containsKey(pid)) {
return;
}
Path path = Paths.get(repository);
EventStream es = EventStream.openRepository(path);
es.onEvent("HttpRequest", e -> {
String requestURI = e.getString("requestURI");
System.out.println("Pid: " + pid + " HTTP Request: " + requestURI + " duration=" + e.getDuration().toMillis() + " ms");
if (e.getDuration().toMillis() > 500) {
analyze(pid, e, path);
}
});
monitored.put(pid, es);
System.out.println("Monitoring: pid=" + pid + " name=" + name);
es.startAsync();
}
private static void analyze(String pid, RecordedEvent request, Path path) {
System.out.print("Slow request detected. Analyzing ... ");
long threadId = request.getThread().getId();
try (EventStream es = EventStream.openRepository(path)) {
es.setStartTime(request.getStartTime().minus(Duration.ofSeconds(1)));
es.setEndTime(request.getEndTime().plus(Duration.ofSeconds(1)));
es.onEvent("jdk.GCPhasePause", event -> {
if (overlap(event, request) && event.getDuration().toMillis() > 50) {
System.out.println("GC pause ");
System.out.println(event);
}
});
es.onEvent("jdk.JavaMonitorWait", event -> {
if (event.getThread().getId() == threadId) {
if (overlap(event, request)) {
System.out.println("Lock contention ");
System.out.println(event);
}
}
});
AtomicLong counter = new AtomicLong();
es.onEvent("jdk.ExecutionSample", event -> {
RecordedThread s = event.getThread("sampledThread");
if (s != null && s.getId() == threadId) {
if (overlap(event, request)) {
counter.getAndIncrement();
if (counter.get() == 5) {
System.out.println("Hot method ");
System.out.println(event);
}
}
}
});
es.startAsync();
// time out after 3 seconds
Thread.sleep(3_000);
} catch (Exception ioe) {
// ignore
}
}
private static boolean overlap(RecordedEvent event, RecordedEvent request) {
Instant rStart = request.getStartTime();
Instant rEnd = request.getEndTime();
Instant eStart = event.getStartTime();
Instant eEnd = event.getEndTime();
if (eStart.isAfter(rStart) && eStart.isBefore(rEnd)) {
return true;
}
if (eEnd.isAfter(rStart) && eEnd.isBefore(rEnd)) {
return true;
}
return false;
}
}