From 853e9b60070434cd136212a798cd03d2bd430905 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Mon, 29 Jun 2020 21:09:47 +0800 Subject: [PATCH] Transform commands of pkg basic1000 (#1274) --- .../core/command/basic1000/CatCommand.java | 7 +- .../core/command/basic1000/ClsCommand.java | 4 + .../core/command/basic1000/GrepCommand.java | 3 +- .../command/basic1000/HistoryCommand.java | 10 +- .../core/command/basic1000/KeymapCommand.java | 5 + .../command/basic1000/OptionsCommand.java | 100 +++++++++--------- .../core/command/basic1000/PwdCommand.java | 4 +- .../core/command/basic1000/ResetCommand.java | 6 +- .../command/basic1000/SessionCommand.java | 37 +++---- .../command/basic1000/ShutdownCommand.java | 31 ++++-- .../command/basic1000/SystemEnvCommand.java | 27 ++--- .../basic1000/SystemPropertyCommand.java | 40 +++---- .../core/command/basic1000/TeeCommand.java | 3 +- .../command/basic1000/VMOptionCommand.java | 39 +++---- .../core/command/model/ChangeResultVO.java | 44 ++++++++ .../core/command/model/EnhancerAffectVO.java | 89 ++++++++++++++++ .../arthas/core/command/model/OptionVO.java | 61 +++++++++++ .../core/command/model/OptionsModel.java | 43 ++++++++ .../arthas/core/command/model/PwdModel.java | 28 +++++ .../arthas/core/command/model/ResetModel.java | 33 ++++++ .../core/command/model/SessionModel.java | 60 +++++++++++ .../core/command/model/ShutdownModel.java | 29 +++++ .../core/command/model/StatusModel.java | 11 ++ .../core/command/model/SystemEnvModel.java | 41 +++++++ .../command/model/SystemPropertyModel.java | 41 +++++++ .../core/command/model/VMOptionModel.java | 47 ++++++++ .../arthas/core/command/view/OptionsView.java | 50 +++++++++ .../arthas/core/command/view/PwdView.java | 14 +++ .../arthas/core/command/view/ResetView.java | 16 +++ .../core/command/view/ResultViewResolver.java | 50 +++++---- .../arthas/core/command/view/SessionView.java | 36 +++++++ .../core/command/view/ShutdownView.java | 14 +++ .../core/command/view/SystemEnvView.java | 16 +++ .../core/command/view/SystemPropertyView.java | 16 +++ .../core/command/view/VMOptionView.java | 42 ++++++++ .../core/command/view/ViewRenderUtil.java | 88 +++++++++++++++ .../impl/TermResultDistributorImpl.java | 4 +- .../arthas/core/server/ArthasBootstrap.java | 36 ++++++- .../history/impl/HistoryManagerImpl.java | 13 +-- .../core/shell/system/impl/ProcessImpl.java | 2 +- .../term/impl/http/HttpRequestHandler.java | 3 +- .../term/impl/http/api/HttpApiHandler.java | 21 +--- .../core/util/affect/EnhancerAffect.java | 9 ++ 43 files changed, 1051 insertions(+), 222 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ChangeResultVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/EnhancerAffectVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/OptionVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/OptionsModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/PwdModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ResetModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/SessionModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ShutdownModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/SystemEnvModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/SystemPropertyModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/VMOptionModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/OptionsView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/PwdView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/ResetView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/SessionView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/ShutdownView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/SystemEnvView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/SystemPropertyView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/VMOptionView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/ViewRenderUtil.java diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java index 9cb3c7fcb..54149a60e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java @@ -91,10 +91,9 @@ public class CatCommand extends AnnotatedCommand { } //目前不支持过滤,限制http请求执行的文件大小 - int maxSizeLimitOfHttp = 128 * 1024; - boolean isHttpApiRequest = !process.session().isTty(); - if (isHttpApiRequest && sizeLimit > maxSizeLimitOfHttp) { - process.end(-1, "When executing commands with http, sizeLimit cannot be large than: " + maxSizeLimitOfHttp); + int maxSizeLimitOfNonTty = 128 * 1024; + if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { + process.end(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); return false; } return true; diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java index f9ee183ee..6ad72ed08 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java @@ -11,6 +11,10 @@ import com.taobao.text.util.RenderUtil; public class ClsCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { + if (!process.session().isTty()) { + process.end(-1, "Command 'cls' is only support tty session."); + return; + } process.write(RenderUtil.cls()).write("\n"); process.end(); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java index 15dbfd3b1..d1db00b0f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java @@ -168,7 +168,6 @@ public class GrepCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { - process.write("The grep command only for pipes. See 'grep --help'\n"); - process.end(); + process.end(-1, "The grep command only for pipes. See 'grep --help'\n"); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java index a0a407a10..407970edc 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java @@ -5,10 +5,10 @@ import java.util.List; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.HistoryModel; +import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.history.HistoryManager; -import com.taobao.arthas.core.shell.history.impl.HistoryManagerImpl; import com.taobao.arthas.core.shell.session.Session; import com.taobao.arthas.core.shell.term.impl.TermImpl; import com.taobao.middleware.cli.annotations.Argument; @@ -47,6 +47,7 @@ public class HistoryCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { Session session = process.session(); + //TODO 修改term history实现方式,统一使用HistoryManager Object termObject = session.get(Session.TTY); if (termObject != null && termObject instanceof TermImpl) { TermImpl term = (TermImpl) termObject; @@ -73,11 +74,12 @@ public class HistoryCommand extends AnnotatedCommand { process.write(sb.toString()); } } else { + //http api + HistoryManager historyManager = ArthasBootstrap.getInstance().getHistoryManager(); if (clear) { - HistoryManagerImpl.getInstance().clearHistory(); + historyManager.clearHistory(); } else { - //http api - List history = HistoryManagerImpl.getInstance().getHistory(); + List history = historyManager.getHistory(); process.appendResult(new HistoryModel(new ArrayList(history))); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java index 4765bb846..7bb044d68 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java @@ -35,6 +35,11 @@ public class KeymapCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { + if (!process.session().isTty()) { + process.end(-1, "Command 'keymap' is only support tty session."); + return; + } + InputStream inputrc = Helper.loadInputRcFile(); try { TableElement table = new TableElement(1, 1, 2).leftCellPadding(1).rightCellPadding(1); diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index fb1790df4..07960f710 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -3,6 +3,10 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.GlobalOptions; import com.taobao.arthas.core.Option; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ChangeResultVO; +import com.taobao.arthas.core.command.model.OptionVO; +import com.taobao.arthas.core.command.model.OptionsModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -18,10 +22,8 @@ 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.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.util.ArrayList; @@ -29,7 +31,6 @@ import java.util.Collection; import java.util.List; import static com.taobao.arthas.core.util.ArthasCheckUtils.isIn; -import static com.taobao.text.ui.Element.label; import static java.lang.String.format; /** @@ -48,6 +49,9 @@ import static java.lang.String.format; Constants.WIKI + Constants.WIKI_HOME + "options") //@formatter:on public class OptionsCommand extends AnnotatedCommand { + + private static final Logger logger = LoggerFactory.getLogger(OptionsCommand.class); + private String optionName; private String optionValue; @@ -66,17 +70,23 @@ public class OptionsCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { try { + StatusModel statusModel = null; if (isShow()) { - processShow(process); + statusModel = processShow(process); } else if (isShowName()) { - processShowName(process); + statusModel = processShowName(process); } else { - processChangeNameValue(process); + statusModel = processChangeNameValue(process); + } + + if (statusModel != null) { + process.end(statusModel.getStatusCode(), statusModel.getMessage()); + } else { + process.end(-1, "command was not processed"); } } catch (Throwable t) { - // ignore - } finally { - process.end(); + logger.error("process options command error", t); + process.end(-1, "process options command error"); } } @@ -100,23 +110,24 @@ public class OptionsCommand extends AnnotatedCommand { } } - private void processShow(CommandProcess process) throws IllegalAccessException { + private StatusModel processShow(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new RegexMatcher(".*")); - process.write(RenderUtil.render(drawShowTable(fields), process.width())); + process.appendResult(new OptionsModel(convertToOptionVOs(fields))); + return StatusModel.success(); } - private void processShowName(CommandProcess process) throws IllegalAccessException { + private StatusModel processShowName(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); - process.write(RenderUtil.render(drawShowTable(fields), process.width())); + process.appendResult(new OptionsModel(convertToOptionVOs(fields))); + return StatusModel.success(); } - private void processChangeNameValue(CommandProcess process) throws IllegalAccessException { + private StatusModel processChangeNameValue(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); // name not exists if (fields.isEmpty()) { - process.write(format("options[%s] not found.\n", optionName)); - return; + return StatusModel.failure(-1, format("options[%s] not found.", optionName)); } Field field = fields.iterator().next(); @@ -144,22 +155,16 @@ public class OptionsCommand extends AnnotatedCommand { } else if (isIn(type, short.class, String.class)) { FieldUtils.writeStaticField(field, afterValue = optionValue); } else { - process.write(format("Options[%s] type[%s] desupported.\n", optionName, type.getSimpleName())); - return; + return StatusModel.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); } } catch (Throwable t) { - process.write(format("Cannot cast option value[%s] to type[%s].\n", optionValue, type.getSimpleName())); - return; + return StatusModel.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); } - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(true, label("NAME").style(Decoration.bold.bold()), - label("BEFORE-VALUE").style(Decoration.bold.bold()), - label("AFTER-VALUE").style(Decoration.bold.bold())); - table.row(optionAnnotation.name(), StringUtils.objectToString(beforeValue), - StringUtils.objectToString(afterValue)); - process.write(RenderUtil.render(table, process.width())); + ChangeResultVO changeResultVO = new ChangeResultVO(optionAnnotation.name(), beforeValue, afterValue); + process.appendResult(new OptionsModel(changeResultVO)); + return StatusModel.success(); } @@ -207,25 +212,24 @@ public class OptionsCommand extends AnnotatedCommand { return optionAnnotation != null && optionNameMatcher.matching(optionAnnotation.name()); } - private Element drawShowTable(Collection optionFields) throws IllegalAccessException { - TableElement table = new TableElement(1, 1, 2, 1, 3, 6) - .leftCellPadding(1).rightCellPadding(1); - table.row(true, label("LEVEL").style(Decoration.bold.bold()), - label("TYPE").style(Decoration.bold.bold()), - label("NAME").style(Decoration.bold.bold()), - label("VALUE").style(Decoration.bold.bold()), - label("SUMMARY").style(Decoration.bold.bold()), - label("DESCRIPTION").style(Decoration.bold.bold())); - - for (final Field optionField : optionFields) { - final Option optionAnnotation = optionField.getAnnotation(Option.class); - table.row("" + optionAnnotation.level(), - optionField.getType().getSimpleName(), - optionAnnotation.name(), - "" + optionField.get(null), - optionAnnotation.summary(), - optionAnnotation.description()); + private List convertToOptionVOs(Collection fields) throws IllegalAccessException { + List list = new ArrayList(); + for (Field field : fields) { + list.add(convertToOptionVO(field)); } - return table; + return list; } + + private OptionVO convertToOptionVO(Field optionField) throws IllegalAccessException { + Option optionAnnotation = optionField.getAnnotation(Option.class); + OptionVO optionVO = new OptionVO(); + optionVO.setLevel(optionAnnotation.level()); + optionVO.setName(optionAnnotation.name()); + optionVO.setSummary(optionAnnotation.summary()); + optionVO.setDescription(optionAnnotation.description()); + optionVO.setType(optionField.getType().getSimpleName()); + optionVO.setValue(""+optionField.get(null)); + return optionVO; + } + } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java index d5a59e726..718624c43 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java @@ -2,6 +2,7 @@ package com.taobao.arthas.core.command.basic1000; import java.io.File; +import com.taobao.arthas.core.command.model.PwdModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -12,7 +13,8 @@ import com.taobao.middleware.cli.annotations.Summary; public class PwdCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { - process.write(new File("").getAbsolutePath()).write("\n"); + String path = new File("").getAbsolutePath(); + process.appendResult(new PwdModel(path)); process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java index 9080e7a23..834c2de6d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java @@ -2,6 +2,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ResetModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.matcher.Matcher; @@ -47,10 +48,9 @@ public class ResetCommand extends AnnotatedCommand { public void process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx); - EnhancerAffect enhancerAffect = null; try { - enhancerAffect = Enhancer.reset(inst, matcher); - process.write(enhancerAffect.toString()).write("\n"); + EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher); + process.appendResult(new ResetModel(enhancerAffect)); } catch (UnmodifiableClassException e) { // ignore } finally { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java index 8b74b4d4c..e532d6c9b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.command.basic1000; +import com.taobao.arthas.core.command.model.SessionModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -7,12 +8,6 @@ import com.taobao.arthas.core.shell.session.Session; import com.taobao.arthas.core.util.UserStatUtil; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; - -import static com.taobao.text.ui.Element.label; import com.alibaba.arthas.tunnel.client.TunnelClient; @@ -24,30 +19,30 @@ import com.alibaba.arthas.tunnel.client.TunnelClient; @Name("session") @Summary("Display current session information") public class SessionCommand extends AnnotatedCommand { + @Override public void process(CommandProcess process) { - process.write(RenderUtil.render(sessionTable(process.session()), process.width())).end(); - } + SessionModel result = new SessionModel(); + Session session = process.session(); + result.setJavaPid(session.getPid()); + result.setSessionId(session.getSessionId()); - /* - * 会话详情 - */ - private Element sessionTable(Session session) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(true, label("Name").style(Decoration.bold.bold()), label("Value").style(Decoration.bold.bold())); - table.row("JAVA_PID", "" + session.getPid()).row("SESSION_ID", "" + session.getSessionId()); + //tunnel TunnelClient tunnelClient = ArthasBootstrap.getInstance().getTunnelClient(); if (tunnelClient != null) { String id = tunnelClient.getId(); if (id != null) { - table.row("AGENT_ID", "" + id); + result.setAgentId(id); } - table.row("TUNNEL_SERVER", "" + tunnelClient.getTunnelServerUrl()); + result.setTunnelServer(tunnelClient.getTunnelServerUrl()); } + + //statUrl String statUrl = UserStatUtil.getStatUrl(); - if (statUrl != null) { - table.row("STAT_URL", statUrl); - } - return table; + result.setStatUrl(statUrl); + + process.appendResult(result); + process.end(); } + } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java index 7c2faf452..e98067442 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java @@ -1,6 +1,11 @@ package com.taobao.arthas.core.command.basic1000; +import com.alibaba.arthas.deps.org.slf4j.Logger; +import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.advisor.Enhancer; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.ResetModel; +import com.taobao.arthas.core.command.model.ShutdownModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.ShellServer; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -13,7 +18,6 @@ import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Summary; import java.lang.instrument.Instrumentation; -import java.lang.instrument.UnmodifiableClassException; /** * 关闭命令 @@ -25,6 +29,9 @@ import java.lang.instrument.UnmodifiableClassException; @Summary("Shutdown Arthas server and exit the console") @Hidden public class ShutdownCommand extends AnnotatedCommand { + + private static final Logger logger = LoggerFactory.getLogger(ShutdownCommand.class); + @Override public void process(CommandProcess process) { shutdown(process); @@ -33,22 +40,32 @@ public class ShutdownCommand extends AnnotatedCommand { public static void shutdown(CommandProcess process) { try { // 退出之前需要重置所有的增强类 + process.appendResult(new MessageModel("Resetting all enhanced classes ...")); Instrumentation inst = process.session().getInstrumentation(); EnhancerAffect enhancerAffect = Enhancer.reset(inst, new WildcardMatcher("*")); - process.write(enhancerAffect.toString()).write("\n"); - process.write("Arthas Server is going to shut down...\n"); - } catch (UnmodifiableClassException e) { - // ignore + process.appendResult(new ResetModel(enhancerAffect)); + process.appendResult(new ShutdownModel(true, "Arthas Server is going to shut down...")); + } catch (Throwable e) { + logger.error("An error occurred when stopping arthas server.", e); + process.appendResult(new ShutdownModel(false, "An error occurred when stopping arthas server.")); } finally { process.end(); ShellServer server = ArthasBootstrap.getInstance().getShellServer(); if (server != null) { - server.close(); + try { + server.close(); + } catch (Throwable e) { + logger.error("close shell server failure", e); + } } SessionManager sessionManager = ArthasBootstrap.getInstance().getSessionManager(); if (sessionManager != null){ - sessionManager.close(); + try { + sessionManager.close(); + } catch (Throwable e) { + logger.error("close session manager failure", e); + } } } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java index 0335dbe73..c2191094c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java @@ -1,11 +1,7 @@ package com.taobao.arthas.core.command.basic1000; -import static com.taobao.text.ui.Element.label; - -import java.util.Map; -import java.util.Map.Entry; - import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.SystemEnvModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -15,9 +11,6 @@ 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.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; /** * @author hengyunabc 2018-11-09 @@ -39,14 +32,18 @@ public class SystemEnvCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { try { + SystemEnvModel result = new SystemEnvModel(); if (StringUtils.isBlank(envName)) { // show all system env - process.write(renderEnv(System.getenv(), process.width())); + result.putAll(System.getenv()); } else { // view the specified system env String value = System.getenv(envName); - process.write(envName + "=" + value + "\n"); + result.put(envName, value); } + process.appendResult(result); + } catch (Throwable t) { + process.end(-1, "Error during setting system env: " + t.getMessage()); } finally { process.end(); } @@ -64,14 +61,4 @@ public class SystemEnvCommand extends AnnotatedCommand { CompletionUtils.complete(completion, System.getenv().keySet()); } - private String renderEnv(Map envMap, int width) { - TableElement table = new TableElement(1, 4).leftCellPadding(1).rightCellPadding(1); - table.row(true, label("KEY").style(Decoration.bold.bold()), label("VALUE").style(Decoration.bold.bold())); - - for (Entry entry : envMap.entrySet()) { - table.row(entry.getKey(), entry.getValue()); - } - - return RenderUtil.render(table, width); - } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java index 61ef7bb4d..cca75a2e8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java @@ -1,6 +1,9 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.command.model.SystemPropertyModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -10,13 +13,6 @@ 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.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; - -import java.util.Properties; - -import static com.taobao.text.ui.Element.label; /** * @author ralf0131 2017-01-09 14:03. @@ -44,30 +40,30 @@ public class SystemPropertyCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { - int status = 0; try { + if (StringUtils.isBlank(propertyName) && StringUtils.isBlank(propertyValue)) { // show all system properties - process.write(renderSystemProperties(System.getProperties(), process.width())); + process.appendResult(new SystemPropertyModel(System.getProperties())); } else if (StringUtils.isBlank(propertyValue)) { // view the specified system property String value = System.getProperty(propertyName); if (value == null) { - process.write("There is no property with the key " + propertyName + ".\n"); + process.end(1, "There is no property with the key " + propertyName); + return; } else { - process.write(propertyName + "=" + value + "\n"); + process.appendResult(new SystemPropertyModel(propertyName, value)); } } else { // change system property System.setProperty(propertyName, propertyValue); - process.write("Successfully changed the system property.\n"); - process.write(propertyName + "=" + System.getProperty(propertyName) + "\n"); + process.appendResult(new MessageModel("Successfully changed the system property.")); + process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName))); } } catch (Throwable t) { - process.write("Error during setting system property: " + t.getMessage() + "\n"); - status = 1; + process.end(-1, "Error during setting system property: " + t.getMessage()); } finally { - process.end(status); + process.end(); } } @@ -80,16 +76,4 @@ public class SystemPropertyCommand extends AnnotatedCommand { public void complete(Completion completion) { CompletionUtils.complete(completion, System.getProperties().stringPropertyNames()); } - - private String renderSystemProperties(Properties properties, int width) { - TableElement table = new TableElement(1, 4).leftCellPadding(1).rightCellPadding(1); - table.row(true, label("KEY").style(Decoration.bold.bold()), - label("VALUE").style(Decoration.bold.bold())); - - for (String name: properties.stringPropertyNames()) { - table.row(name, properties.getProperty(name)); - } - - return RenderUtil.render(table, width); - } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java index 113beec4d..3c8868c5a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java @@ -34,8 +34,7 @@ public class TeeCommand extends AnnotatedCommand { @Override public void process(CommandProcess process) { - process.write("The tee command only for pipes. See 'tee --help'\n"); - process.end(); + process.end(-1, "The tee command only for pipes. See 'tee --help'"); } public String getFilePath() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java index cefbacd85..9ae903133 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java @@ -1,7 +1,5 @@ package com.taobao.arthas.core.command.basic1000; -import static com.taobao.text.ui.Element.label; - import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Arrays; @@ -12,7 +10,9 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.express.OgnlExpress; +import com.taobao.arthas.core.command.model.ChangeResultVO; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.VMOptionModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -22,9 +22,6 @@ 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.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; /** * vmoption command @@ -66,41 +63,31 @@ public class VMOptionCommand extends AnnotatedCommand { if (StringUtils.isBlank(name) && StringUtils.isBlank(value)) { // show all options - process.write(renderVMOptions(hotSpotDiagnosticMXBean.getDiagnosticOptions(), process.width())); + process.appendResult(new VMOptionModel(hotSpotDiagnosticMXBean.getDiagnosticOptions())); } else if (StringUtils.isBlank(value)) { // view the specified option VMOption option = hotSpotDiagnosticMXBean.getVMOption(name); if (option == null) { - process.write("In order to change the system properties, you must specify the property value.\n"); + process.end(-1, "In order to change the system properties, you must specify the property value."); } else { - process.write(renderVMOptions(Arrays.asList(option), process.width())); + process.appendResult(new VMOptionModel(Arrays.asList(option))); } } else { + VMOption vmOption = hotSpotDiagnosticMXBean.getVMOption(name); + String originValue = vmOption.getValue(); + // change vm option hotSpotDiagnosticMXBean.setVMOption(name, value); - process.write("Successfully updated the vm option.\n"); - process.write(name + "=" + hotSpotDiagnosticMXBean.getVMOption(name).getValue() + "\n"); + process.appendResult(new MessageModel("Successfully updated the vm option.")); + process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue, + hotSpotDiagnosticMXBean.getVMOption(name).getValue()))); } } catch (Throwable t) { - process.write("Error during setting vm option: " + t.getMessage() + "\n"); logger.error("Error during setting vm option", t); + process.end(-1, "Error during setting vm option: " + t.getMessage()); } finally { process.end(); } - - } - - private static String renderVMOptions(List diagnosticOptions, int width) { - TableElement table = new TableElement(1, 1, 1, 1).leftCellPadding(1).rightCellPadding(1); - table.row(true, label("KEY").style(Decoration.bold.bold()), label("VALUE").style(Decoration.bold.bold()), - label("ORIGIN").style(Decoration.bold.bold()), - label("WRITEABLE").style(Decoration.bold.bold())); - - for (VMOption option : diagnosticOptions) { - table.row(option.getName(), option.getValue(), "" + option.getOrigin(), "" + option.isWriteable()); - } - - return RenderUtil.render(table, width); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ChangeResultVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ChangeResultVO.java new file mode 100644 index 000000000..26626884a --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ChangeResultVO.java @@ -0,0 +1,44 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/16 + */ +public class ChangeResultVO { + private String name; + private Object beforeValue; + private Object afterValue; + + public ChangeResultVO() { + } + + public ChangeResultVO(String name, Object beforeValue, Object afterValue) { + this.name = name; + this.beforeValue = beforeValue; + this.afterValue = afterValue; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Object getBeforeValue() { + return beforeValue; + } + + public void setBeforeValue(Object beforeValue) { + this.beforeValue = beforeValue; + } + + public Object getAfterValue() { + return afterValue; + } + + public void setAfterValue(Object afterValue) { + this.afterValue = afterValue; + } +} + diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/EnhancerAffectVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/EnhancerAffectVO.java new file mode 100644 index 000000000..84efb2542 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/EnhancerAffectVO.java @@ -0,0 +1,89 @@ +package com.taobao.arthas.core.command.model; + +import com.taobao.arthas.core.GlobalOptions; +import com.taobao.arthas.core.util.affect.EnhancerAffect; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author gongdewei 2020/6/22 + */ +public class EnhancerAffectVO { + + private final long cost; + private final int methodCount; + private final int classCount; + private final long listenerId; + private Throwable throwable; + private List classDumpFiles; + private List methods; + + public EnhancerAffectVO(EnhancerAffect affect) { + this.cost = affect.cost(); + this.classCount = affect.cCnt(); + this.methodCount = affect.mCnt(); + this.listenerId = affect.getListenerId(); + this.throwable = affect.getThrowable(); + + if (GlobalOptions.isDump) { + classDumpFiles = new ArrayList(); + for (File classDumpFile : affect.getClassDumpFiles()) { + classDumpFiles.add(classDumpFile.getAbsolutePath()); + } + } + + if (GlobalOptions.verbose) { + methods = new ArrayList(); + methods.addAll(affect.getMethods()); + } + } + + public EnhancerAffectVO(long cost, int methodCount, int classCount, long listenerId) { + this.cost = cost; + this.methodCount = methodCount; + this.classCount = classCount; + this.listenerId = listenerId; + } + + public long getCost() { + return cost; + } + + public int getClassCount() { + return classCount; + } + + public int getMethodCount() { + return methodCount; + } + + public long getListenerId() { + return listenerId; + } + + public Throwable getThrowable() { + return throwable; + } + + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } + + public List getClassDumpFiles() { + return classDumpFiles; + } + + public void setClassDumpFiles(List classDumpFiles) { + this.classDumpFiles = classDumpFiles; + } + + public List getMethods() { + return methods; + } + + public void setMethods(List methods) { + this.methods = methods; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/OptionVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/OptionVO.java new file mode 100644 index 000000000..730a37bef --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/OptionVO.java @@ -0,0 +1,61 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/15 + */ +public class OptionVO { + private int level; + private String type; + private String name; + private String value; + private String summary; + private String description; + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/OptionsModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/OptionsModel.java new file mode 100644 index 000000000..49baac121 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/OptionsModel.java @@ -0,0 +1,43 @@ +package com.taobao.arthas.core.command.model; + +import java.util.List; + +/** + * @author gongdewei 2020/4/15 + */ +public class OptionsModel extends ResultModel{ + private List options; + private ChangeResultVO changeResult; + + public OptionsModel() { + } + + public OptionsModel(List options) { + this.options = options; + } + + public OptionsModel(ChangeResultVO changeResult) { + this.changeResult = changeResult; + } + + @Override + public String getType() { + return "options"; + } + + public List getOptions() { + return options; + } + + public void setOptions(List options) { + this.options = options; + } + + public ChangeResultVO getChangeResult() { + return changeResult; + } + + public void setChangeResult(ChangeResultVO changeResult) { + this.changeResult = changeResult; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/PwdModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/PwdModel.java new file mode 100644 index 000000000..f310f61da --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/PwdModel.java @@ -0,0 +1,28 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/5/11 + */ +public class PwdModel extends ResultModel { + private String workingDir; + + public PwdModel() { + } + + public PwdModel(String workingDir) { + this.workingDir = workingDir; + } + + @Override + public String getType() { + return "pwd"; + } + + public String getWorkingDir() { + return workingDir; + } + + public void setWorkingDir(String workingDir) { + this.workingDir = workingDir; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ResetModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/ResetModel.java new file mode 100644 index 000000000..b2e95ac77 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ResetModel.java @@ -0,0 +1,33 @@ +package com.taobao.arthas.core.command.model; + +import com.taobao.arthas.core.util.affect.EnhancerAffect; + +/** + * @author gongdewei 2020/6/22 + */ +public class ResetModel extends ResultModel { + + private EnhancerAffectVO affect; + + public ResetModel(EnhancerAffectVO affect) { + this.affect = affect; + } + + public ResetModel(EnhancerAffect affect) { + this.affect = new EnhancerAffectVO(affect); + } + + @Override + public String getType() { + return "reset"; + } + + public ResetModel affect(EnhancerAffect affect) { + this.affect = new EnhancerAffectVO(affect); + return this; + } + + public EnhancerAffectVO getAffect() { + return affect; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SessionModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SessionModel.java new file mode 100644 index 000000000..0652f991c --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SessionModel.java @@ -0,0 +1,60 @@ +package com.taobao.arthas.core.command.model; + +/** + * Session command result model + * + * @author gongdewei 2020/03/27 + */ +public class SessionModel extends ResultModel { + + private long javaPid; + private String sessionId; + private String agentId; + private String tunnelServer; + private String statUrl; + + @Override + public String getType() { + return "session"; + } + + public long getJavaPid() { + return javaPid; + } + + public void setJavaPid(long javaPid) { + this.javaPid = javaPid; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public String getTunnelServer() { + return tunnelServer; + } + + public void setTunnelServer(String tunnelServer) { + this.tunnelServer = tunnelServer; + } + + public String getStatUrl() { + return statUrl; + } + + public void setStatUrl(String statUrl) { + this.statUrl = statUrl; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ShutdownModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/ShutdownModel.java new file mode 100644 index 000000000..09a101fb7 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ShutdownModel.java @@ -0,0 +1,29 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/6/22 + */ +public class ShutdownModel extends ResultModel { + + private boolean graceful; + + private String message; + + public ShutdownModel(boolean graceful, String message) { + this.graceful = graceful; + this.message = message; + } + + @Override + public String getType() { + return "shutdown"; + } + + public boolean isGraceful() { + return graceful; + } + + public String getMessage() { + return message; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java index 9af2439a0..4b43baf7c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java @@ -1,6 +1,17 @@ package com.taobao.arthas.core.command.model; public class StatusModel extends ResultModel { + public static StatusModel success() { + return new StatusModel(0); + } + + public static StatusModel failure(int statusCode, String message) { + if (statusCode == 0) { + throw new IllegalArgumentException("failure status code cannot be 0"); + } + return new StatusModel(statusCode, message); + } + private int statusCode; private String message; diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SystemEnvModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SystemEnvModel.java new file mode 100644 index 000000000..4fcabefe3 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SystemEnvModel.java @@ -0,0 +1,41 @@ +package com.taobao.arthas.core.command.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * sysenv KV Result + * @author gongdewei 2020/4/2 + */ +public class SystemEnvModel extends ResultModel { + + private Map env = new HashMap(); + + public SystemEnvModel() { + } + + public SystemEnvModel(Map env) { + this.putAll(env); + } + + public SystemEnvModel(String name, String value) { + this.put(name, value); + } + + public Map getEnv() { + return env; + } + + public String put(String key, String value) { + return env.put(key, value); + } + + public void putAll(Map m) { + env.putAll(m); + } + + @Override + public String getType() { + return "sysenv"; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SystemPropertyModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SystemPropertyModel.java new file mode 100644 index 000000000..5ede5cb87 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SystemPropertyModel.java @@ -0,0 +1,41 @@ +package com.taobao.arthas.core.command.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * Property KV Result + * @author gongdewei 2020/4/2 + */ +public class SystemPropertyModel extends ResultModel { + + private Map props = new HashMap(); + + public SystemPropertyModel() { + } + + public SystemPropertyModel(Map props) { + this.putAll(props); + } + + public SystemPropertyModel(String name, String value) { + this.put(name, value); + } + + public Map getProps() { + return props; + } + + public String put(String key, String value) { + return props.put(key, value); + } + + public void putAll(Map m) { + props.putAll(m); + } + + @Override + public String getType() { + return "sysprop"; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/VMOptionModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/VMOptionModel.java new file mode 100644 index 000000000..7f795a462 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/VMOptionModel.java @@ -0,0 +1,47 @@ +package com.taobao.arthas.core.command.model; + +import com.sun.management.VMOption; + +import java.util.List; + +/** + * @author gongdewei 2020/4/15 + */ +public class VMOptionModel extends ResultModel { + + private List vmOptions; + + private ChangeResultVO changeResult; + + public VMOptionModel() { + } + + public VMOptionModel(List vmOptions) { + this.vmOptions = vmOptions; + } + + public VMOptionModel(ChangeResultVO changeResult) { + this.changeResult = changeResult; + } + + @Override + public String getType() { + return "vmoption"; + } + + public List getVmOptions() { + return vmOptions; + } + + public void setVmOptions(List vmOptions) { + this.vmOptions = vmOptions; + } + + public ChangeResultVO getChangeResult() { + return changeResult; + } + + public void setChangeResult(ChangeResultVO changeResult) { + this.changeResult = changeResult; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/OptionsView.java b/core/src/main/java/com/taobao/arthas/core/command/view/OptionsView.java new file mode 100644 index 000000000..55d5d4407 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/OptionsView.java @@ -0,0 +1,50 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.OptionVO; +import com.taobao.arthas.core.command.model.OptionsModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.text.Decoration; +import com.taobao.text.ui.Element; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + +import java.util.Collection; + +import static com.taobao.text.ui.Element.label; + +/** + * @author gongdewei 2020/4/15 + */ +public class OptionsView extends ResultView { + @Override + public void draw(CommandProcess process, OptionsModel result) { + if (result.getOptions() != null) { + process.write(RenderUtil.render(drawShowTable(result.getOptions()), process.width())); + } else if (result.getChangeResult() != null) { + TableElement table = ViewRenderUtil.renderChangeResult(result.getChangeResult()); + process.write(RenderUtil.render(table, process.width())); + } + } + + private Element drawShowTable(Collection options) { + TableElement table = new TableElement(1, 1, 2, 1, 3, 6) + .leftCellPadding(1).rightCellPadding(1); + table.row(true, label("LEVEL").style(Decoration.bold.bold()), + label("TYPE").style(Decoration.bold.bold()), + label("NAME").style(Decoration.bold.bold()), + label("VALUE").style(Decoration.bold.bold()), + label("SUMMARY").style(Decoration.bold.bold()), + label("DESCRIPTION").style(Decoration.bold.bold())); + + for (final OptionVO optionVO : options) { + table.row("" + optionVO.getLevel(), + optionVO.getType(), + optionVO.getName(), + optionVO.getValue(), + optionVO.getSummary(), + optionVO.getDescription()); + } + return table; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/PwdView.java b/core/src/main/java/com/taobao/arthas/core/command/view/PwdView.java new file mode 100644 index 000000000..fffd46c63 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/PwdView.java @@ -0,0 +1,14 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.PwdModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/5/11 + */ +public class PwdView extends ResultView { + @Override + public void draw(CommandProcess process, PwdModel result) { + process.write(result.getWorkingDir()).write("\n"); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ResetView.java b/core/src/main/java/com/taobao/arthas/core/command/view/ResetView.java new file mode 100644 index 000000000..3d69dada5 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ResetView.java @@ -0,0 +1,16 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.ResetModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/6/22 + */ +public class ResetView extends ResultView { + + @Override + public void draw(CommandProcess process, ResetModel result) { + process.write(ViewRenderUtil.renderEnhancerAffect(result.getAffect())); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java index 6e8c3fce4..6071e71d4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java @@ -2,7 +2,7 @@ package com.taobao.arthas.core.command.view; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; -import com.taobao.arthas.core.command.model.*; +import com.taobao.arthas.core.command.model.ResultModel; import com.taobao.arthas.core.shell.command.CommandProcess; import java.lang.reflect.Method; @@ -20,23 +20,16 @@ public class ResultViewResolver { // modelClass -> view private Map resultViewMap = new ConcurrentHashMap(); - private static ResultViewResolver viewResolver; - - public static ResultViewResolver getInstance() { - if (viewResolver == null) { - synchronized (ResultViewResolver.class) { - viewResolver = new ResultViewResolver(); - } - } - return viewResolver; + public ResultViewResolver() { + initResultViews(); } - static { - getInstance().registerResultViews(); - } - - private void registerResultViews() { + /** + * 需要调用此方法初始化注册ResultView + */ + private void initResultViews() { try { + //basic1000 registerView(StatusView.class); registerView(VersionView.class); registerView(MessageView.class); @@ -44,29 +37,42 @@ public class ResultViewResolver { //registerView(HistoryView.class); registerView(EchoView.class); registerView(CatView.class); + registerView(OptionsView.class); + registerView(SystemPropertyView.class); + registerView(SystemEnvView.class); + registerView(PwdView.class); + registerView(VMOptionView.class); + registerView(SessionView.class); + registerView(ResetView.class); + registerView(ShutdownView.class); + + //klass100 + + //logger + + //monitor2000 + } catch (Throwable e) { logger.error("register result view failed", e); } } - private ResultViewResolver() { - } - public ResultView getResultView(ResultModel model) { return resultViewMap.get(model.getClass()); } - public void registerView(Class modelClass, ResultView view) { - //TODO 检查model的type是否重复,减少复制代码带来的bug + public ResultViewResolver registerView(Class modelClass, ResultView view) { + //TODO 检查model的type是否重复,避免复制代码带来的bug this.resultViewMap.put(modelClass, view); + return this; } - public void registerView(ResultView view) { + public ResultViewResolver registerView(ResultView view) { Class modelClass = getModelClass(view); if (modelClass == null) { throw new NullPointerException("model class is null"); } - this.registerView(modelClass, view); + return this.registerView(modelClass, view); } public void registerView(Class viewClass) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SessionView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SessionView.java new file mode 100644 index 000000000..9f55fceb5 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SessionView.java @@ -0,0 +1,36 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.SessionModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.text.Decoration; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + +import static com.taobao.text.ui.Element.label; + +/** + * Term / Tty view for session result + * + * @author gongdewei 2020/3/27 + */ +public class SessionView extends ResultView { + + @Override + public void draw(CommandProcess process, SessionModel result) { + //会话详情 + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(true, label("Name").style(Decoration.bold.bold()), label("Value").style(Decoration.bold.bold())); + table.row("JAVA_PID", "" + result.getJavaPid()).row("SESSION_ID", "" + result.getSessionId()); + if (result.getAgentId() != null) { + table.row("AGENT_ID", "" + result.getAgentId()); + } + if (result.getTunnelServer() != null) { + table.row("TUNNEL_SERVER", "" + result.getTunnelServer()); + } + if (result.getStatUrl() != null) { + table.row("STAT_URL", result.getStatUrl()); + } + process.write(RenderUtil.render(table, process.width())); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ShutdownView.java b/core/src/main/java/com/taobao/arthas/core/command/view/ShutdownView.java new file mode 100644 index 000000000..1f6f59e1e --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ShutdownView.java @@ -0,0 +1,14 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.ShutdownModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/6/22 + */ +public class ShutdownView extends ResultView { + @Override + public void draw(CommandProcess process, ShutdownModel result) { + process.write(result.getMessage()).write("\n"); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SystemEnvView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SystemEnvView.java new file mode 100644 index 000000000..8ca24db93 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SystemEnvView.java @@ -0,0 +1,16 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.SystemEnvModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/4/2 + */ +public class SystemEnvView extends ResultView { + + @Override + public void draw(CommandProcess process, SystemEnvModel result) { + process.write(ViewRenderUtil.renderKeyValueTable(result.getEnv(), process.width())); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SystemPropertyView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SystemPropertyView.java new file mode 100644 index 000000000..ad82ac803 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SystemPropertyView.java @@ -0,0 +1,16 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.SystemPropertyModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/4/2 + */ +public class SystemPropertyView extends ResultView { + + @Override + public void draw(CommandProcess process, SystemPropertyModel result) { + process.write(ViewRenderUtil.renderKeyValueTable(result.getProps(), process.width())); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/VMOptionView.java b/core/src/main/java/com/taobao/arthas/core/command/view/VMOptionView.java new file mode 100644 index 000000000..0ca8da71c --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/VMOptionView.java @@ -0,0 +1,42 @@ +package com.taobao.arthas.core.command.view; + +import com.sun.management.VMOption; +import com.taobao.arthas.core.command.model.VMOptionModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.text.Decoration; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + +import java.util.List; + +import static com.taobao.text.ui.Element.label; + +/** + * @author gongdewei 2020/4/15 + */ +public class VMOptionView extends ResultView { + + @Override + public void draw(CommandProcess process, VMOptionModel result) { + if (result.getVmOptions() != null) { + process.write(renderVMOptions(result.getVmOptions(), process.width())); + } else if (result.getChangeResult() != null) { + TableElement table = ViewRenderUtil.renderChangeResult(result.getChangeResult()); + process.write(RenderUtil.render(table, process.width())); + } + } + + private static String renderVMOptions(List diagnosticOptions, int width) { + TableElement table = new TableElement(1, 1, 1, 1).leftCellPadding(1).rightCellPadding(1); + table.row(true, label("KEY").style(Decoration.bold.bold()), + label("VALUE").style(Decoration.bold.bold()), + label("ORIGIN").style(Decoration.bold.bold()), + label("WRITEABLE").style(Decoration.bold.bold())); + + for (VMOption option : diagnosticOptions) { + table.row(option.getName(), option.getValue(), "" + option.getOrigin(), "" + option.isWriteable()); + } + + return RenderUtil.render(table, width); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ViewRenderUtil.java b/core/src/main/java/com/taobao/arthas/core/command/view/ViewRenderUtil.java new file mode 100644 index 000000000..4676d50c2 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ViewRenderUtil.java @@ -0,0 +1,88 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.ChangeResultVO; +import com.taobao.arthas.core.command.model.EnhancerAffectVO; +import com.taobao.arthas.core.util.StringUtils; +import com.taobao.text.Decoration; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + +import java.util.List; +import java.util.Map; + +import static com.taobao.text.ui.Element.label; +import static java.lang.String.format; + +/** + * view render util for term/tty + * @author gongdewei 2020/6/22 + */ +public class ViewRenderUtil { + + /** + * Render key-value table + * @param map + * @param width + * @return + */ + public static String renderKeyValueTable(Map map, int width) { + TableElement table = new TableElement(1, 4).leftCellPadding(1).rightCellPadding(1); + table.row(true, label("KEY").style(Decoration.bold.bold()), label("VALUE").style(Decoration.bold.bold())); + + for (Map.Entry entry : map.entrySet()) { + table.row(entry.getKey(), entry.getValue()); + } + + return RenderUtil.render(table, width); + } + + /** + * Render change result vo + * @param result + * @return + */ + public static TableElement renderChangeResult(ChangeResultVO result) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(true, label("NAME").style(Decoration.bold.bold()), + label("BEFORE-VALUE").style(Decoration.bold.bold()), + label("AFTER-VALUE").style(Decoration.bold.bold())); + table.row(result.getName(), StringUtils.objectToString(result.getBeforeValue()), + StringUtils.objectToString(result.getAfterValue())); + return table; + } + + /** + * Render EnhancerAffectVO + * @param affectVO + * @return + */ + public static String renderEnhancerAffect(EnhancerAffectVO affectVO) { + final StringBuilder infoSB = new StringBuilder(); + List classDumpFiles = affectVO.getClassDumpFiles(); + if (classDumpFiles != null) { + for (String classDumpFile : classDumpFiles) { + infoSB.append("[dump: ").append(classDumpFile).append("]\n"); + } + } + + List methods = affectVO.getMethods(); + if (methods != null) { + for (String method : methods) { + infoSB.append("[Affect method: ").append(method).append("]\n"); + } + } + + infoSB.append(format("Affect(class count: %d , method count: %d) cost in %s ms, listenerId: %d", + affectVO.getClassCount(), + affectVO.getMethodCount(), + affectVO.getCost(), + affectVO.getListenerId())); + + if (affectVO.getThrowable() != null) { + infoSB.append("\nEnhance error! exception: " + affectVO.getThrowable()); + } + infoSB.append("\n"); + + return infoSB.toString(); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/distribution/impl/TermResultDistributorImpl.java b/core/src/main/java/com/taobao/arthas/core/distribution/impl/TermResultDistributorImpl.java index cc460a4fe..a8ac596fe 100644 --- a/core/src/main/java/com/taobao/arthas/core/distribution/impl/TermResultDistributorImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/distribution/impl/TermResultDistributorImpl.java @@ -16,9 +16,9 @@ public class TermResultDistributorImpl implements ResultDistributor { private final CommandProcess commandProcess; private final ResultViewResolver resultViewResolver; - public TermResultDistributorImpl(CommandProcess commandProcess) { + public TermResultDistributorImpl(CommandProcess commandProcess, ResultViewResolver resultViewResolver) { this.commandProcess = commandProcess; - this.resultViewResolver = ResultViewResolver.getInstance(); + this.resultViewResolver = resultViewResolver; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java index a92290e2f..3afa2c6a4 100644 --- a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java +++ b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java @@ -29,6 +29,7 @@ import com.taobao.arthas.common.AnsiLog; import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.core.advisor.TransformerManager; import com.taobao.arthas.core.command.BuiltinCommandPack; +import com.taobao.arthas.core.command.view.ResultViewResolver; import com.taobao.arthas.core.config.BinderUtils; import com.taobao.arthas.core.config.Configure; import com.taobao.arthas.core.config.FeatureCodec; @@ -40,10 +41,13 @@ import com.taobao.arthas.core.shell.ShellServer; import com.taobao.arthas.core.shell.ShellServerOptions; import com.taobao.arthas.core.shell.command.CommandResolver; import com.taobao.arthas.core.shell.handlers.BindHandler; +import com.taobao.arthas.core.shell.history.HistoryManager; +import com.taobao.arthas.core.shell.history.impl.HistoryManagerImpl; import com.taobao.arthas.core.shell.impl.ShellServerImpl; import com.taobao.arthas.core.shell.session.SessionManager; import com.taobao.arthas.core.shell.session.impl.SessionManagerImpl; import com.taobao.arthas.core.shell.term.impl.HttpTermServer; +import com.taobao.arthas.core.shell.term.impl.http.api.HttpApiHandler; import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer; import com.taobao.arthas.core.util.ArthasBanner; import com.taobao.arthas.core.util.FileUtils; @@ -56,7 +60,6 @@ import io.netty.util.concurrent.EventExecutorGroup; /** * @author vlinux on 15/5/2. - * @author gongdewei 2020-03-25 */ public class ArthasBootstrap { private static final String ARTHAS_SPY_JAR = "arthas-spy.jar"; @@ -89,6 +92,12 @@ public class ArthasBootstrap { private TransformerManager transformerManager; + private ResultViewResolver resultViewResolver; + + private HistoryManager historyManager; + + private HttpApiHandler httpApiHandler; + private ArthasBootstrap(Instrumentation instrumentation, Map args) throws Throwable { this.instrumentation = instrumentation; @@ -103,7 +112,10 @@ public class ArthasBootstrap { // 3. init logger loggerContext = LogUtil.initLooger(arthasEnvironment); - // 4. start agent server + // 4. init beans + initBeans(); + + // 5. start agent server bind(configure); executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() { @@ -127,6 +139,12 @@ public class ArthasBootstrap { Runtime.getRuntime().addShutdownHook(shutdown); } + private void initBeans() { + this.resultViewResolver = new ResultViewResolver(); + + this.historyManager = new HistoryManagerImpl(); + } + private static void initSpy(Instrumentation instrumentation) throws Throwable { // TODO init SpyImpl ? @@ -320,6 +338,8 @@ public class ArthasBootstrap { //http api session manager sessionManager = new SessionManagerImpl(options, this, shellServer.getCommandManager(), shellServer.getJobController()); + //http api handler + httpApiHandler = new HttpApiHandler(historyManager, sessionManager); logger().info("as-server listening on network={};telnet={};http={};timeout={};", configure.getIp(), configure.getTelnetPort(), configure.getHttpPort(), options.getConnectionTimeout()); @@ -495,4 +515,16 @@ public class ArthasBootstrap { private Logger logger() { return LoggerFactory.getLogger(this.getClass()); } + + public ResultViewResolver getResultViewResolver() { + return resultViewResolver; + } + + public HistoryManager getHistoryManager() { + return historyManager; + } + + public HttpApiHandler getHttpApiHandler() { + return httpApiHandler; + } } diff --git a/core/src/main/java/com/taobao/arthas/core/shell/history/impl/HistoryManagerImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/history/impl/HistoryManagerImpl.java index 26f6dabd1..5b22f79bd 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/history/impl/HistoryManagerImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/history/impl/HistoryManagerImpl.java @@ -19,18 +19,7 @@ public class HistoryManagerImpl implements HistoryManager { private List history = new ArrayList(); - private static HistoryManager instance; - - public static HistoryManager getInstance() { - if (instance == null) { - synchronized (HistoryManagerImpl.class) { - instance = new HistoryManagerImpl(); - } - } - return instance; - } - - private HistoryManagerImpl() { + public HistoryManagerImpl() { } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/shell/system/impl/ProcessImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/system/impl/ProcessImpl.java index 249bcf7ad..5180f4179 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/system/impl/ProcessImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/system/impl/ProcessImpl.java @@ -335,7 +335,7 @@ public class ProcessImpl implements Process { process = new CommandProcessImpl(this, tty); if (resultDistributor == null) { - resultDistributor = new TermResultDistributorImpl(process); + resultDistributor = new TermResultDistributorImpl(process, ArthasBootstrap.getInstance().getResultViewResolver()); } final List args2 = new LinkedList(); diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java index d417e3518..b38cba88b 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java @@ -9,6 +9,7 @@ import java.net.URL; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.IOUtils; +import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.term.impl.http.api.HttpApiHandler; import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer; @@ -49,7 +50,7 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler charsBufPool = new ArrayBlockingQueue(poolSize); private ArrayBlockingQueue bytesPool = new ArrayBlockingQueue(poolSize); - public static HttpApiHandler getInstance() { - if (instance == null) { - synchronized (HttpApiHandler.class) { - instance = new HttpApiHandler(); - } - } - return instance; - } - - private HttpApiHandler() { - sessionManager = ArthasBootstrap.getInstance().getSessionManager(); - commandManager = sessionManager.getCommandManager(); - jobController = sessionManager.getJobController(); - historyManager = HistoryManagerImpl.getInstance(); + public HttpApiHandler(HistoryManager historyManager, SessionManager sessionManager) { + this.historyManager = historyManager; + this.sessionManager = sessionManager; + commandManager = this.sessionManager.getCommandManager(); + jobController = this.sessionManager.getJobController(); //init buf pool JsonUtils.setSerializeWriterBufferThreshold(jsonBufferSize); diff --git a/core/src/main/java/com/taobao/arthas/core/util/affect/EnhancerAffect.java b/core/src/main/java/com/taobao/arthas/core/util/affect/EnhancerAffect.java index e67997d2b..b0b3b3789 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/affect/EnhancerAffect.java +++ b/core/src/main/java/com/taobao/arthas/core/util/affect/EnhancerAffect.java @@ -113,8 +113,17 @@ public final class EnhancerAffect extends Affect { this.throwable = throwable; } + public Collection getClassDumpFiles() { + return classDumpFiles; + } + + public List getMethods() { + return methods; + } + @Override public String toString() { + //TODO removing EnhancerAffect.toString(), replace with ViewRenderUtil.renderEnhancerAffect() final StringBuilder infoSB = new StringBuilder(); if (GlobalOptions.isDump && !classDumpFiles.isEmpty()) {