mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
add mc command. #373
This commit is contained in:
@@ -70,6 +70,11 @@
|
||||
<artifactId>arthas-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.taobao.arthas</groupId>
|
||||
<artifactId>arthas-memorycompiler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.taobao.arthas.core.command.klass100.ClassLoaderCommand;
|
||||
import com.taobao.arthas.core.command.klass100.DumpClassCommand;
|
||||
import com.taobao.arthas.core.command.klass100.GetStaticCommand;
|
||||
import com.taobao.arthas.core.command.klass100.JadCommand;
|
||||
import com.taobao.arthas.core.command.klass100.MemoryCompilerCommand;
|
||||
import com.taobao.arthas.core.command.klass100.OgnlCommand;
|
||||
import com.taobao.arthas.core.command.klass100.RedefineCommand;
|
||||
import com.taobao.arthas.core.command.klass100.SearchClassCommand;
|
||||
@@ -69,6 +70,8 @@ public class BuiltinCommandPack implements CommandResolver {
|
||||
commands.add(Command.create(JvmCommand.class));
|
||||
// commands.add(Command.create(GroovyScriptCommand.class));
|
||||
commands.add(Command.create(OgnlCommand.class));
|
||||
commands.add(Command.create(MemoryCompilerCommand.class));
|
||||
commands.add(Command.create(RedefineCommand.class));
|
||||
commands.add(Command.create(DashboardCommand.class));
|
||||
commands.add(Command.create(DumpClassCommand.class));
|
||||
commands.add(Command.create(JulyCommand.class));
|
||||
@@ -81,7 +84,6 @@ public class BuiltinCommandPack implements CommandResolver {
|
||||
commands.add(Command.create(SessionCommand.class));
|
||||
commands.add(Command.create(SystemPropertyCommand.class));
|
||||
commands.add(Command.create(SystemEnvCommand.class));
|
||||
commands.add(Command.create(RedefineCommand.class));
|
||||
commands.add(Command.create(HistoryCommand.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
||||
}
|
||||
|
||||
@Option(shortName = "c", longName = "classloader")
|
||||
@Description("Display ClassLoader urls")
|
||||
@Description("The hash code of the special ClassLoader")
|
||||
public void setHashCode(String hashCode) {
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package com.taobao.arthas.core.command.klass100;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.taobao.arthas.compiler.DynamicCompiler;
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.util.ClassLoaderUtils;
|
||||
import com.taobao.arthas.core.util.FileUtils;
|
||||
import com.taobao.arthas.core.util.LogUtil;
|
||||
import com.taobao.arthas.core.util.affect.RowAffect;
|
||||
import com.taobao.middleware.cli.annotations.Argument;
|
||||
import com.taobao.middleware.cli.annotations.Description;
|
||||
import com.taobao.middleware.cli.annotations.Name;
|
||||
import com.taobao.middleware.cli.annotations.Option;
|
||||
import com.taobao.middleware.cli.annotations.Summary;
|
||||
import com.taobao.middleware.logger.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-02-05
|
||||
*
|
||||
*/
|
||||
@Name("mc")
|
||||
@Summary("Memory compiler, compiles java files into bytecode and class files in memory.")
|
||||
@Description(Constants.EXAMPLE + " mc /tmp/Test.java\n" + " mc -c 327a647b /tmp/Test.java\n"
|
||||
+ " mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java\n" + Constants.WIKI + Constants.WIKI_HOME
|
||||
+ "mc")
|
||||
public class MemoryCompilerCommand extends AnnotatedCommand {
|
||||
|
||||
private static final Logger logger = LogUtil.getArthasLogger();
|
||||
|
||||
private String directory;
|
||||
private String hashCode;
|
||||
private String encoding;
|
||||
|
||||
private List<String> sourcefiles;
|
||||
|
||||
@Argument(argName = "sourcefiles", index = 0)
|
||||
@Description("source files")
|
||||
public void setClassPattern(List<String> sourcefiles) {
|
||||
this.sourcefiles = sourcefiles;
|
||||
}
|
||||
|
||||
@Option(shortName = "c", longName = "classloader")
|
||||
@Description("The hash code of the special ClassLoader")
|
||||
public void setHashCode(String hashCode) {
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
@Option(longName = "encoding")
|
||||
@Description("Source file encoding")
|
||||
public void setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
@Option(shortName = "d", longName = "directory")
|
||||
@Description("Sets the destination directory for class files")
|
||||
public void setDirectory(String directory) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(CommandProcess process) {
|
||||
int exitCode = 0;
|
||||
RowAffect affect = new RowAffect();
|
||||
|
||||
try {
|
||||
Instrumentation inst = process.session().getInstrumentation();
|
||||
ClassLoader classloader = null;
|
||||
if (hashCode == null) {
|
||||
classloader = ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
classloader = ClassLoaderUtils.getClassLoader(inst, hashCode);
|
||||
if (classloader == null) {
|
||||
process.write("Can not find classloader with hashCode: " + hashCode + ".\n");
|
||||
exitCode = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicCompiler dynamicCompiler = new DynamicCompiler(classloader);
|
||||
|
||||
Charset charset = Charset.defaultCharset();
|
||||
if (encoding != null) {
|
||||
charset = Charset.forName(encoding);
|
||||
}
|
||||
|
||||
for (String sourceFile : sourcefiles) {
|
||||
String sourceCode = FileUtils.readFileToString(new File(sourceFile), charset);
|
||||
String name = new File(sourceFile).getName();
|
||||
if (name.endsWith(".java")) {
|
||||
name = name.substring(0, name.length() - ".java".length());
|
||||
}
|
||||
dynamicCompiler.addSource(name, sourceCode);
|
||||
}
|
||||
|
||||
Map<String, byte[]> byteCodes = dynamicCompiler.buildByteCodes();
|
||||
|
||||
File outputDir = null;
|
||||
if (this.directory != null) {
|
||||
outputDir = new File(this.directory);
|
||||
} else {
|
||||
outputDir = new File("").getAbsoluteFile();
|
||||
}
|
||||
|
||||
process.write("Memory compiler output:\n");
|
||||
for (Entry<String, byte[]> entry : byteCodes.entrySet()) {
|
||||
File byteCodeFile = new File(outputDir, entry.getKey().replace('.', '/') + ".class");
|
||||
FileUtils.writeByteArrayToFile(byteCodeFile, entry.getValue());
|
||||
process.write(byteCodeFile.getAbsolutePath() + '\n');
|
||||
affect.rCnt(1);
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
logger.warn("Memory compiler error", e);
|
||||
process.write("Memory compiler error, exception message: " + e.getMessage()
|
||||
+ ", please check $HOME/logs/arthas/arthas.log for more details. \n");
|
||||
exitCode = -1;
|
||||
} finally {
|
||||
process.write(affect + "\n");
|
||||
process.end(exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.taobao.arthas.core.util;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-02-05
|
||||
*
|
||||
*/
|
||||
public class ClassLoaderUtils {
|
||||
|
||||
public static Set<ClassLoader> getAllClassLoader(Instrumentation inst) {
|
||||
Set<ClassLoader> classLoaderSet = new HashSet<ClassLoader>();
|
||||
|
||||
for (Class<?> clazz : inst.getAllLoadedClasses()) {
|
||||
ClassLoader classLoader = clazz.getClassLoader();
|
||||
if (classLoader != null) {
|
||||
classLoaderSet.add(classLoader);
|
||||
}
|
||||
}
|
||||
return classLoaderSet;
|
||||
}
|
||||
|
||||
public static ClassLoader getClassLoader(Instrumentation inst, String hashCode) {
|
||||
if (hashCode == null || hashCode.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Class<?> clazz : inst.getAllLoadedClasses()) {
|
||||
ClassLoader classLoader = clazz.getClassLoader();
|
||||
if (classLoader != null) {
|
||||
if (Integer.toHexString(classLoader.hashCode()).equals(hashCode)) {
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user