add mc command. #373

This commit is contained in:
hengyunabc
2019-02-06 01:33:03 +08:00
parent ad9685f479
commit f3561e9bc8
5 changed files with 181 additions and 2 deletions
+5
View File
@@ -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;
}
@@ -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;
}
}