JStackInventoryPrinter.java
6.33 KB
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Decompiled with CFR 0_118.
*
* Could not load the following classes:
* org.apache.felix.inventory.Format
* org.apache.felix.inventory.InventoryPrinter
* org.apache.felix.scr.annotations.Activate
* org.apache.felix.scr.annotations.Component
* org.apache.felix.scr.annotations.Deactivate
* org.apache.felix.scr.annotations.Properties
* org.apache.felix.scr.annotations.Property
* org.apache.felix.scr.annotations.Service
* org.slf4j.Logger
* org.slf4j.LoggerFactory
*/
package com.adobe.granite.threaddump.impl;
import com.adobe.granite.threaddump.impl.LoggerWriter;
import com.adobe.granite.threaddump.impl.StreamGobbler;
import java.io.File;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.felix.inventory.Format;
import org.apache.felix.inventory.InventoryPrinter;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(name="com.adobe.granite.threaddump.JStackInventoryPrinter")
@Service(value={InventoryPrinter.class})
@Properties(value={@Property(name="felix.inventory.printer.name", value={"jstack-threaddump"}), @Property(name="felix.inventory.printer.title", value={"Threads (via JStack)"})})
public final class JStackInventoryPrinter
implements InventoryPrinter {
private static final Pattern JVM_NAME_PATTERN = Pattern.compile("(\\d+)@.+");
private static final Pattern JVM_VERSION_PATTERN = Pattern.compile("1\\.[78]\\..*");
private static final String OS_NAME_SYSTEM_PROPERTY = "os.name";
private static final String JAVA_HOME_SYSTEM_PROPERTY = "java.home";
private static final String JAVA_VERSION_SYSTEM_PROPERTY = "java.version";
private static final String JAVA_HOME_ENV_PROPERTY = "JAVA_HOME";
private static final String OS_NAME_WINDOWS_PREFIX = "Windows";
private static final String OS_NAME_MACOSX_PREFIX = "Mac OS X";
private final Logger logger;
private String pid;
private File jStackExecutable;
public JStackInventoryPrinter() {
this.logger = LoggerFactory.getLogger(this.getClass());
}
@Activate
protected void activate() {
this.pid = JStackInventoryPrinter.getPid();
File javaHome = JStackInventoryPrinter.getJavaHome();
if (javaHome == null || !javaHome.exists() || !javaHome.isDirectory()) {
this.logger.warn("There is no way to access to current Java home, please check `java.home` System Property or `JAVA_HOME` environment variable.");
} else {
this.jStackExecutable = JStackInventoryPrinter.getJStackExecutable(javaHome);
}
}
@Deactivate
protected void deactivate() {
this.pid = null;
this.jStackExecutable = null;
}
public void print(PrintWriter printWriter, Format format, boolean isZip) {
if (this.pid == null) {
this.logger.warn("There is no way to access to this current process PID, `jstack` cannot be executed.");
return;
}
if (this.jStackExecutable == null || !this.jStackExecutable.exists() || !this.jStackExecutable.isFile()) {
this.logger.warn("There is no way to access to the `jstack` command, please check it is correctly installed in the JDK");
return;
}
try {
Process process = Runtime.getRuntime().exec(new String[]{this.jStackExecutable.getAbsolutePath(), this.pid});
Thread inputStreamGlobber = StreamGobbler.redirect(process.getInputStream(), printWriter);
Thread errorStreamGlobber = StreamGobbler.redirect(process.getErrorStream(), new LoggerWriter(this.logger));
int exitValue = process.waitFor();
inputStreamGlobber.join();
errorStreamGlobber.join();
if (exitValue != 0) {
this.logger.error("An error occurred while executing {} {}, process exited with code: {}", new Object[]{this.jStackExecutable, this.pid, exitValue});
}
}
catch (Exception e) {
this.logger.error("An error occurred while executing {} {}, see root errors: {}", new Object[]{this.jStackExecutable, this.pid, e});
}
}
private static String getPid() {
String jvm = ManagementFactory.getRuntimeMXBean().getName();
Matcher matcher = JVM_NAME_PATTERN.matcher(jvm);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}
private static File getJavaHome() {
File javaHome = null;
String javaHomeProperty = System.getProperty("java.home");
if (javaHomeProperty != null && javaHomeProperty.length() > 0) {
javaHome = new File(javaHomeProperty);
}
if (!(javaHome != null && javaHome.exists() && javaHome.isDirectory() || (javaHomeProperty = System.getenv("JAVA_HOME")) == null || javaHomeProperty.length() <= 0)) {
javaHome = new File(javaHomeProperty);
}
return javaHome;
}
private static boolean isOs(String namePrefix) {
String osName = System.getProperty("os.name");
if (osName.startsWith(namePrefix)) {
return true;
}
return false;
}
private static boolean isRecentJvmVersion() {
String javaVersion = System.getProperty("java.version");
return JVM_VERSION_PATTERN.matcher(javaVersion).matches();
}
private static /* varargs */ File getFile(File parent, String ... path) {
File tmp = parent;
for (String current : path) {
tmp = new File(tmp, current);
}
return tmp;
}
private static File getJStackExecutable(File javaHome) {
String jstackCommand = "jstack";
if (JStackInventoryPrinter.isOs("Windows")) {
jstackCommand = jstackCommand + ".exe";
}
if (JStackInventoryPrinter.isOs("Mac OS X") && !JStackInventoryPrinter.isRecentJvmVersion()) {
return JStackInventoryPrinter.getFile(javaHome, "bin", jstackCommand);
}
return JStackInventoryPrinter.getFile(javaHome, "..", "bin", jstackCommand);
}
}