Merge remote-tracking branch 'origin/master' into channel-server

pull/1490/merge^2
gongdewei 4 years ago
commit f01b41fdd5

@ -4,7 +4,7 @@ on: [push]
jobs:
linux:
runs-on: ubuntu-latest
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
@ -18,10 +18,10 @@ jobs:
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/classes/lib*
path: arthas-vmtool/target/lib*
mac:
runs-on: macos-latest
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
@ -35,10 +35,10 @@ jobs:
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/classes/lib*
path: arthas-vmtool/target/lib*
windows:
runs-on: windows-latest
runs-on: windows-2016
steps:
- uses: actions/checkout@v2
@ -52,4 +52,4 @@ jobs:
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/classes/*.dll
path: arthas-vmtool/target/*.dll

@ -0,0 +1,34 @@
name: release
on:
push:
tags:
- "arthas-all-*"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [8]
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn clean package -P full
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
packaging/target/*.zip
packaging/target/*.deb
packaging/target/*.rpm
tunnel-server/target/*fatjar.jar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -1,6 +1,6 @@
FROM openjdk:8-jdk-alpine
ARG ARTHAS_VERSION="3.5.1"
ARG ARTHAS_VERSION="3.5.2"
ARG MIRROR=false
ENV MAVEN_HOST=https://repo1.maven.org/maven2 \

@ -1,6 +1,6 @@
FROM alpine
ARG ARTHAS_VERSION="3.5.1"
ARG ARTHAS_VERSION="3.5.2"
ARG MIRROR=false
ENV MAVEN_HOST=https://repo1.maven.org/maven2 \

@ -183,7 +183,7 @@ public interface Servlet {
Memory compiler, compiles `.java` files into `.class` files in memory.
```bash
mc /tmp/Test.java
$ mc /tmp/Test.java
```
#### retransform

@ -176,7 +176,7 @@ mc /tmp/Test.java
```
#### retransform
* https://arthas.aliyun.com/doc/rretransform
* https://arthas.aliyun.com/doc/retransform
加载外部的`.class`文件retransform 热更新jvm已加载的类。

@ -127,6 +127,7 @@ Welcome to register the company name in this issue: https://github.com/alibaba/a
![qdama](static/qdm_logo.png)
![有赞](static/youzan.png)
![中原银行](static/zhongyuanbank.png)
![CVTE](static/cvte.png)
* 网易云
* 派迩信息技术

@ -29,6 +29,12 @@ public class ArthasConfiguration {
@Autowired
ConfigurableEnvironment environment;
/**
* <pre>
* 1. arthas.* Arthas
* 2. ArthasProperties
* </pre>
*/
@ConfigurationProperties(prefix = "arthas")
@ConditionalOnMissingBean
@Bean
@ -41,7 +47,7 @@ public class ArthasConfiguration {
public ArthasAgent arthasAgent(@Autowired Map<String, String> arthasConfigMap,
@Autowired ArthasProperties arthasProperties) throws Throwable {
arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap);
ArthasProperties.updateArthasConfigMapDefaultValue(arthasConfigMap);
/**
* @see org.springframework.boot.context.ContextIdApplicationContextInitializer#getApplicationId(ConfigurableEnvironment)
*/

@ -1,5 +1,7 @@
package com.alibaba.arthas.spring;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@ -34,6 +36,20 @@ public class ArthasProperties {
* when arthas agent init error will throw exception by default.
*/
private boolean slientInit = false;
/**
* disabled commandsdefault disable stop command
*/
private String disabledCommands;
private static final String DEFAULT_DISABLEDCOMMANDS = "stop";
/**
* arthasConfigMap
*/
public static void updateArthasConfigMapDefaultValue(Map<String, String> arthasConfigMap) {
if (!arthasConfigMap.containsKey("disabledCommands")) {
arthasConfigMap.put("disabledCommands", DEFAULT_DISABLEDCOMMANDS);
}
}
public String getHome() {
return home;
@ -115,4 +131,11 @@ public class ArthasProperties {
this.appName = appName;
}
public String getDisabledCommands() {
return disabledCommands;
}
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
}

@ -60,6 +60,69 @@
<os_arch_option>-m64</os_arch_option>
<lib_name>libArthasJniLibrary-x64.dll</lib_name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>1.0-alpha-11</version>
<extensions>true</extensions>
<configuration>
<javahIncludes>
<javahInclude>
<className>arthas.VmTool</className>
</javahInclude>
</javahIncludes>
<jdkIncludePath>${project.basedir}/src/main/native/head</jdkIncludePath>
<javahOS>${os_name}</javahOS>
<sources>
<source>
<directory>src/main/native/src</directory>
<fileNames>
<fileName>jni-library.cpp</fileName>
</fileNames>
</source>
</sources>
<compilerProvider>generic-classic</compilerProvider>
<compilerExecutable>g++</compilerExecutable>
<compilerStartOptions>
<compilerStartOption>${os_arch_option}</compilerStartOption>
<compilerStartOption>-fpic</compilerStartOption>
<compilerStartOption>-shared</compilerStartOption>
<compilerStartOption>-o</compilerStartOption>
</compilerStartOptions>
<linkerOutputDirectory>target</linkerOutputDirectory>
<linkerExecutable>g++</linkerExecutable>
<linkerStartOptions>
<linkerStartOption>${os_arch_option}</linkerStartOption>
<linkerStartOption>-fpic</linkerStartOption>
<linkerStartOption>-shared</linkerStartOption>
<linkerStartOption>-o</linkerStartOption>
<!-- for windows #1833 -->
<linkerStartOption>-static-libstdc++</linkerStartOption>
<linkerStartOption>-static</linkerStartOption>
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOption>-o ${project.build.directory}/${lib_name}</linkerEndOption>
</linkerEndOptions>
</configuration>
<executions>
<execution>
<id>javah</id>
<phase>compile</phase>
<goals>
<goal>javah</goal>
<goal>initialize</goal>
<goal>compile</goal>
<goal>link</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

@ -8,10 +8,10 @@
# program : Arthas
# author : Core Engine @ Taobao.com
# date : 2021-05-13
# date : 2021-06-10
# current arthas script version
ARTHAS_SCRIPT_VERSION=3.5.1
ARTHAS_SCRIPT_VERSION=3.5.2
# SYNOPSIS
# rreadlink <fileOrDirPath>
@ -83,7 +83,9 @@ DIR=$(dirname -- "$(rreadlink "${BASH_SOURCE[0]}")")
ARTHAS_HOME=
# define arthas's lib
ARTHAS_LIB_DIR=${HOME}/.arthas/lib
if [ -z "${ARTHAS_LIB_DIR}" ]; then
ARTHAS_LIB_DIR=${HOME}/.arthas/lib
fi
# target process id to attach
TARGET_PID=
@ -158,6 +160,9 @@ USERNAME=
# password
PASSWORD=
# disabledCommands
DISABLED_COMMANDS=
############ Command Arguments ############
# if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true
@ -413,6 +418,7 @@ Usage:
[--tunnel-server <value>] [--agent-id <value>] [--stat-url <value>]
[--app-name <value>]
[--username <value>] [--password <value>]
[--disabled-commands <value>]
[--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
[--attach-only] [-c <value>] [-f <value>] [-v] [pid]
@ -437,6 +443,7 @@ Options and Arguments:
--app-name Special app name
--username Special username
--password Special password
--disabled-commands Disable special commands
--select select target process by classname or JARfilename
-c,--command <value> Command to execute, multiple commands separated
by ;
@ -459,9 +466,10 @@ EXAMPLES:
./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'
./as.sh -c 'sysprop; thread' <pid>
./as.sh -f batch.as <pid>
./as.sh --use-version 3.5.1
./as.sh --use-version 3.5.2
./as.sh --session-timeout 3600
./as.sh --attach-only
./as.sh --disabled-commands stop,dump
./as.sh --select math-game
./as.sh --repo-mirror aliyun --use-http
WIKI:
@ -648,6 +656,11 @@ parse_arguments()
shift # past argument
shift # past value
;;
--disabled-commands)
DISABLED_COMMANDS="$2"
shift # past argument
shift # past value
;;
--use-http)
USE_HTTP=true
shift # past argument
@ -865,6 +878,11 @@ attach_jvm()
tempArgs+=("${PASSWORD}")
fi
if [ "${DISABLED_COMMANDS}" ]; then
tempArgs+=("-disabled-commands")
tempArgs+=("${DISABLED_COMMANDS}")
fi
if [ "${TARGET_IP}" ]; then
tempArgs+=("-target-ip")
tempArgs+=("${TARGET_IP}")

@ -1,5 +1,8 @@
package com.taobao.arthas.boot;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@ -11,12 +14,12 @@ import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.InputMismatchException;
import javax.xml.parsers.ParserConfigurationException;
@ -37,9 +40,6 @@ import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Option;
import com.taobao.middleware.cli.annotations.Summary;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
/**
* @author hengyunabc 2018-10-26
*
@ -57,10 +57,11 @@ import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
+ " java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'\n"
+ " java -jar arthas-boot.jar -c 'sysprop; thread' <pid>\n"
+ " java -jar arthas-boot.jar -f batch.as <pid>\n"
+ " java -jar arthas-boot.jar --use-version 3.5.1\n"
+ " java -jar arthas-boot.jar --use-version 3.5.2\n"
+ " java -jar arthas-boot.jar --versions\n"
+ " java -jar arthas-boot.jar --select math-game\n"
+ " java -jar arthas-boot.jar --session-timeout 3600\n" + " java -jar arthas-boot.jar --attach-only\n"
+ " java -jar arthas-boot.jar --disabled-commands stop,dump\n"
+ " java -jar arthas-boot.jar --repo-mirror aliyun --use-http\n" + "WIKI:\n"
+ " https://arthas.aliyun.com/doc\n")
public class Bootstrap {
@ -135,9 +136,17 @@ public class Bootstrap {
private String select;
private String disabledCommands;
static {
ARTHAS_LIB_DIR = new File(
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib");
String arthasLibDirEnv = System.getenv("ARTHAS_LIB_DIR");
if (arthasLibDirEnv != null) {
ARTHAS_LIB_DIR = new File(arthasLibDirEnv);
} else {
ARTHAS_LIB_DIR = new File(
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib");
}
try {
ARTHAS_LIB_DIR.mkdirs();
} catch (Throwable t) {
@ -313,6 +322,12 @@ public class Bootstrap {
this.select = select;
}
@Option(longName = "disabled-commands")
@Description("disable some commands ")
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException,
ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
@ -573,6 +588,11 @@ public class Bootstrap {
attachArgs.add(bootstrap.getStatUrl());
}
if (bootstrap.getDisabledCommands() != null){
attachArgs.add("-disabled-commands");
attachArgs.add(bootstrap.getDisabledCommands());
}
AnsiLog.info("Try to attach process " + pid);
AnsiLog.debug("Start arthas-core.jar args: " + attachArgs);
ProcessUtils.startArthasCore(pid, attachArgs);
@ -883,4 +903,8 @@ public class Bootstrap {
public String getPassword() {
return password;
}
public String getDisabledCommands() {
return disabledCommands;
}
}

@ -313,8 +313,8 @@ public class ProcessUtils {
// find arthas-client.jar
URLClassLoader classLoader = new URLClassLoader(
new URL[]{new File(arthasHomeDir, "arthas-client.jar").toURI().toURL()});
Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method processMethod = telnetConsoleClas.getMethod("process", String[].class);
Class<?> telnetConsoleClass = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method processMethod = telnetConsoleClass.getMethod("process", String[].class);
//redirect System.out/System.err
PrintStream originSysOut = System.out;

@ -24,5 +24,6 @@ arthas.sessionTimeout=1800
# channel server address
#arthas.channelServer=127.0.0.1:7700
#arthas.disabledCommands=stop,dump
#arthas.outputPath=arthas-output

@ -46,12 +46,13 @@ public class Arthas {
Option appName = createOption(String.class, ArthasConstants.APP_NAME);
Option statUrl = createOption(String.class, "stat-url");
Option disabledCommands = createOption(String.class,"disabled-commands");
CLI cli = CLIs.create("arthas").addOption(pid).addOption(core).addOption(agent).addOption(target)
.addOption(telnetPort).addOption(httpPort).addOption(sessionTimeout)
.addOption(username).addOption(password)
.addOption(channelServer).addOption(heartbeatInterval)
.addOption(tunnelServer).addOption(agentId).addOption(appName).addOption(statUrl);
.addOption(tunnelServer).addOption(agentId).addOption(appName).addOption(statUrl).addOption(disabledCommands);
CommandLine commandLine = cli.parse(Arrays.asList(args));
Configure configure = new Configure();
@ -82,6 +83,7 @@ public class Arthas {
configure.setTunnelServer((String) commandLine.getOptionValue("tunnel-server"));
configure.setAgentId((String) commandLine.getOptionValue("agent-id"));
configure.setStatUrl((String) commandLine.getOptionValue("stat-url"));
configure.setDisabledCommands((String) commandLine.getOptionValue("disabled-commands"));
configure.setAppName((String) commandLine.getOptionValue(ArthasConstants.APP_NAME));
return configure;
}

@ -2,12 +2,12 @@ package com.taobao.arthas.core.advisor;
import java.arthas.SpyAPI.AbstractSpy;
import java.util.List;
import java.util.regex.Pattern;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.shell.system.ExecStatus;
import com.taobao.arthas.core.shell.system.ProcessAware;
import com.taobao.arthas.core.util.StringUtils;
/**
* <pre>
@ -27,7 +27,7 @@ public class SpyImpl extends AbstractSpy {
public void atEnter(Class<?> clazz, String methodInfo, Object target, Object[] args) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitMethodInfo(methodInfo);
String[] info = StringUtils.splitMethodInfo(methodInfo);
String methodName = info[0];
String methodDesc = info[1];
// TODO listener 只用查一次,放到 thread local里保存起来就可以了
@ -52,7 +52,7 @@ public class SpyImpl extends AbstractSpy {
public void atExit(Class<?> clazz, String methodInfo, Object target, Object[] args, Object returnObject) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitMethodInfo(methodInfo);
String[] info = StringUtils.splitMethodInfo(methodInfo);
String methodName = info[0];
String methodDesc = info[1];
@ -76,7 +76,7 @@ public class SpyImpl extends AbstractSpy {
public void atExceptionExit(Class<?> clazz, String methodInfo, Object target, Object[] args, Throwable throwable) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitMethodInfo(methodInfo);
String[] info = StringUtils.splitMethodInfo(methodInfo);
String methodName = info[0];
String methodDesc = info[1];
@ -99,7 +99,7 @@ public class SpyImpl extends AbstractSpy {
@Override
public void atBeforeInvoke(Class<?> clazz, String invokeInfo, Object target) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitInvokeInfo(invokeInfo);
String[] info = StringUtils.splitInvokeInfo(invokeInfo);
String owner = info[0];
String methodName = info[1];
String methodDesc = info[2];
@ -125,7 +125,7 @@ public class SpyImpl extends AbstractSpy {
@Override
public void atAfterInvoke(Class<?> clazz, String invokeInfo, Object target) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitInvokeInfo(invokeInfo);
String[] info = StringUtils.splitInvokeInfo(invokeInfo);
String owner = info[0];
String methodName = info[1];
String methodDesc = info[2];
@ -151,7 +151,7 @@ public class SpyImpl extends AbstractSpy {
@Override
public void atInvokeException(Class<?> clazz, String invokeInfo, Object target, Throwable throwable) {
ClassLoader classLoader = clazz.getClassLoader();
String[] info = splitInvokeInfo(invokeInfo);
String[] info = StringUtils.splitInvokeInfo(invokeInfo);
String owner = info[0];
String methodName = info[1];
String methodDesc = info[2];
@ -174,15 +174,7 @@ public class SpyImpl extends AbstractSpy {
}
}
private String[] splitMethodInfo(String methodInfo) {
return methodInfo.split(Pattern.quote("|"));
}
private String[] splitInvokeInfo(String invokeInfo) {
return invokeInfo.split(Pattern.quote("|"));
}
private boolean skipAdviceListener(AdviceListener adviceListener) {
private static boolean skipAdviceListener(AdviceListener adviceListener) {
if (adviceListener instanceof ProcessAware) {
ProcessAware processAware = (ProcessAware) adviceListener;
ExecStatus status = processAware.getProcess().status();

@ -1,5 +1,9 @@
package com.taobao.arthas.core.command;
import java.util.ArrayList;
import java.util.List;
import com.taobao.arthas.core.command.basic1000.AuthCommand;
import com.taobao.arthas.core.command.basic1000.Base64Command;
import com.taobao.arthas.core.command.basic1000.CatCommand;
import com.taobao.arthas.core.command.basic1000.ClsCommand;
@ -9,11 +13,9 @@ import com.taobao.arthas.core.command.basic1000.HelpCommand;
import com.taobao.arthas.core.command.basic1000.HistoryCommand;
import com.taobao.arthas.core.command.basic1000.KeymapCommand;
import com.taobao.arthas.core.command.basic1000.OptionsCommand;
import com.taobao.arthas.core.command.basic1000.AuthCommand;
import com.taobao.arthas.core.command.basic1000.PwdCommand;
import com.taobao.arthas.core.command.basic1000.ResetCommand;
import com.taobao.arthas.core.command.basic1000.SessionCommand;
import com.taobao.arthas.core.command.basic1000.ShutdownCommand;
import com.taobao.arthas.core.command.basic1000.StopCommand;
import com.taobao.arthas.core.command.basic1000.SystemEnvCommand;
import com.taobao.arthas.core.command.basic1000.SystemPropertyCommand;
@ -46,11 +48,10 @@ import com.taobao.arthas.core.command.monitor200.TimeTunnelCommand;
import com.taobao.arthas.core.command.monitor200.TraceCommand;
import com.taobao.arthas.core.command.monitor200.VmToolCommand;
import com.taobao.arthas.core.command.monitor200.WatchCommand;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.Command;
import com.taobao.arthas.core.shell.command.CommandResolver;
import java.util.ArrayList;
import java.util.List;
import com.taobao.middleware.cli.annotations.Name;
/**
* TODO automatically discover the built-in commands.
@ -58,10 +59,10 @@ import java.util.List;
*/
public class BuiltinCommandPack implements CommandResolver {
private static List<Command> commands = new ArrayList<Command>();
private List<Command> commands = new ArrayList<Command>();
static {
initCommands();
public BuiltinCommandPack(List<String> disabledCommands) {
initCommands(disabledCommands);
}
@Override
@ -69,53 +70,63 @@ public class BuiltinCommandPack implements CommandResolver {
return commands;
}
private static void initCommands() {
commands.add(Command.create(HelpCommand.class));
commands.add(Command.create(AuthCommand.class));
commands.add(Command.create(KeymapCommand.class));
commands.add(Command.create(SearchClassCommand.class));
commands.add(Command.create(SearchMethodCommand.class));
commands.add(Command.create(ClassLoaderCommand.class));
commands.add(Command.create(JadCommand.class));
commands.add(Command.create(GetStaticCommand.class));
commands.add(Command.create(MonitorCommand.class));
commands.add(Command.create(StackCommand.class));
commands.add(Command.create(ThreadCommand.class));
commands.add(Command.create(TraceCommand.class));
commands.add(Command.create(WatchCommand.class));
commands.add(Command.create(TimeTunnelCommand.class));
commands.add(Command.create(JvmCommand.class));
commands.add(Command.create(PerfCounterCommand.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(RetransformCommand.class));
commands.add(Command.create(DashboardCommand.class));
commands.add(Command.create(DumpClassCommand.class));
commands.add(Command.create(HeapDumpCommand.class));
commands.add(Command.create(JulyCommand.class));
commands.add(Command.create(ThanksCommand.class));
commands.add(Command.create(OptionsCommand.class));
commands.add(Command.create(ClsCommand.class));
commands.add(Command.create(ResetCommand.class));
commands.add(Command.create(VersionCommand.class));
commands.add(Command.create(SessionCommand.class));
commands.add(Command.create(SystemPropertyCommand.class));
commands.add(Command.create(SystemEnvCommand.class));
commands.add(Command.create(VMOptionCommand.class));
commands.add(Command.create(LoggerCommand.class));
commands.add(Command.create(HistoryCommand.class));
commands.add(Command.create(CatCommand.class));
commands.add(Command.create(Base64Command.class));
commands.add(Command.create(EchoCommand.class));
commands.add(Command.create(PwdCommand.class));
commands.add(Command.create(MBeanCommand.class));
commands.add(Command.create(GrepCommand.class));
commands.add(Command.create(TeeCommand.class));
commands.add(Command.create(ProfilerCommand.class));
commands.add(Command.create(VmToolCommand.class));
commands.add(Command.create(ShutdownCommand.class));
commands.add(Command.create(StopCommand.class));
private void initCommands(List<String> disabledCommands) {
List<Class<? extends AnnotatedCommand>> commandClassList = new ArrayList<Class<? extends AnnotatedCommand>>(32);
commandClassList.add(HelpCommand.class);
commandClassList.add(AuthCommand.class);
commandClassList.add(KeymapCommand.class);
commandClassList.add(SearchClassCommand.class);
commandClassList.add(SearchMethodCommand.class);
commandClassList.add(ClassLoaderCommand.class);
commandClassList.add(JadCommand.class);
commandClassList.add(GetStaticCommand.class);
commandClassList.add(MonitorCommand.class);
commandClassList.add(StackCommand.class);
commandClassList.add(ThreadCommand.class);
commandClassList.add(TraceCommand.class);
commandClassList.add(WatchCommand.class);
commandClassList.add(TimeTunnelCommand.class);
commandClassList.add(JvmCommand.class);
commandClassList.add(PerfCounterCommand.class);
// commandClassList.add(GroovyScriptCommand.class);
commandClassList.add(OgnlCommand.class);
commandClassList.add(MemoryCompilerCommand.class);
commandClassList.add(RedefineCommand.class);
commandClassList.add(RetransformCommand.class);
commandClassList.add(DashboardCommand.class);
commandClassList.add(DumpClassCommand.class);
commandClassList.add(HeapDumpCommand.class);
commandClassList.add(JulyCommand.class);
commandClassList.add(ThanksCommand.class);
commandClassList.add(OptionsCommand.class);
commandClassList.add(ClsCommand.class);
commandClassList.add(ResetCommand.class);
commandClassList.add(VersionCommand.class);
commandClassList.add(SessionCommand.class);
commandClassList.add(SystemPropertyCommand.class);
commandClassList.add(SystemEnvCommand.class);
commandClassList.add(VMOptionCommand.class);
commandClassList.add(LoggerCommand.class);
commandClassList.add(HistoryCommand.class);
commandClassList.add(CatCommand.class);
commandClassList.add(Base64Command.class);
commandClassList.add(EchoCommand.class);
commandClassList.add(PwdCommand.class);
commandClassList.add(MBeanCommand.class);
commandClassList.add(GrepCommand.class);
commandClassList.add(TeeCommand.class);
commandClassList.add(ProfilerCommand.class);
commandClassList.add(VmToolCommand.class);
commandClassList.add(StopCommand.class);
for (Class<? extends AnnotatedCommand> clazz : commandClassList) {
Name name = clazz.getAnnotation(Name.class);
if (name != null && name.value() != null) {
if (disabledCommands.contains(name.value())) {
continue;
}
}
commands.add(Command.create(clazz));
}
}
}

@ -1,50 +0,0 @@
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.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.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.middleware.cli.annotations.Hidden;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
*
*
* @author vlinux on 14/10/23.
* @see StopCommand
*/
@Name("shutdown")
@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);
}
public static void shutdown(CommandProcess process) {
ArthasBootstrap arthasBootstrap = ArthasBootstrap.getInstance();
try {
// 退出之前需要重置所有的增强类
process.appendResult(new MessageModel("Resetting all enhanced classes ..."));
EnhancerAffect enhancerAffect = arthasBootstrap.reset();
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();
arthasBootstrap.destroy();
}
}
}

@ -1,20 +1,42 @@
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.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.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* Alias for ShutdownCommand
* @author hengyunabc 2019-07-05
* @see ShutdownCommand
*/
@Name("stop")
@Summary("Stop/Shutdown Arthas server and exit the console.")
public class StopCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(StopCommand.class);
@Override
public void process(CommandProcess process) {
ShutdownCommand.shutdown(process);
shutdown(process);
}
private static void shutdown(CommandProcess process) {
ArthasBootstrap arthasBootstrap = ArthasBootstrap.getInstance();
try {
// 退出之前需要重置所有的增强类
process.appendResult(new MessageModel("Resetting all enhanced classes ..."));
EnhancerAffect enhancerAffect = arthasBootstrap.reset();
process.appendResult(new ResetModel(enhancerAffect));
process.appendResult(new ShutdownModel(true, "Arthas Server is going to shutdown..."));
} 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();
arthasBootstrap.destroy();
}
}
}

@ -119,7 +119,7 @@ public class LoggerCommand extends AnnotatedCommand {
if (this.name != null && this.level != null) {
level(process);
} else {
loggers(process, name);
loggers(process);
}
}
@ -160,7 +160,7 @@ public class LoggerCommand extends AnnotatedCommand {
}
}
public void loggers(CommandProcess process, String name) {
public void loggers(CommandProcess process) {
Map<ClassLoader, LoggerTypes> classLoaderLoggerMap = new LinkedHashMap<ClassLoader, LoggerTypes>();
for (Class<?> clazz : process.session().getInstrumentation().getAllLoadedClasses()) {

@ -81,8 +81,11 @@ public class AbstractTraceAdviceListener extends AdviceListenerAdapter {
private void finishing(ClassLoader loader, Advice advice) {
// 本次调用的耗时
TraceEntity traceEntity = threadLocalTraceEntity(loader);
double cost = threadLocalWatch.costInMillis();
if (--traceEntity.deep == 0) {
if (traceEntity.deep >= 1) { // #1817 防止deep为负数
traceEntity.deep--;
}
if (traceEntity.deep == 0) {
double cost = threadLocalWatch.costInMillis();
try {
boolean conditionResult = isConditionMet(command.getConditionExpress(), advice, cost);
if (this.isVerbose()) {

@ -18,14 +18,6 @@ public class TraceEntity {
this.deep = 0;
}
public int getDeep() {
return deep;
}
public void setDeep(int deep) {
this.deep = deep;
}
private TraceTree createTraceTree(ClassLoader loader) {
return new TraceTree(ThreadUtil.getThreadNode(loader, Thread.currentThread()));
}

@ -69,6 +69,11 @@ public class Configure {
*/
private Long sessionTimeout;
/**
* disabled commands
*/
private String disabledCommands;
public String getIp() {
return ip;
}
@ -205,6 +210,14 @@ public class Configure {
this.password = password;
}
public String getDisabledCommands() {
return disabledCommands;
}
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
/**
*
*

@ -298,24 +298,25 @@ public class ArthasBootstrap {
return ARTHAS_HOME;
}
static String reslove(ArthasEnvironment arthasEnvironment, String key, String defaultValue) {
String value = arthasEnvironment.getProperty(key);
if (value == null) {
return defaultValue;
}
return arthasEnvironment.resolvePlaceholders(value);
}
// try to load arthas.properties
private void tryToLoadArthasProperties() throws IOException {
this.arthasEnvironment.resolvePlaceholders(CONFIG_LOCATION_PROPERTY);
String location = null;
if (arthasEnvironment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
location = arthasEnvironment.resolvePlaceholders(CONFIG_LOCATION_PROPERTY);
}
String location = reslove(arthasEnvironment, CONFIG_LOCATION_PROPERTY, null);
if (location == null) {
location = arthasHome();
}
String configName = "arthas";
if (arthasEnvironment.containsProperty(CONFIG_NAME_PROPERTY)) {
configName = arthasEnvironment.resolvePlaceholders(CONFIG_NAME_PROPERTY);
}
String configName = reslove(arthasEnvironment, CONFIG_NAME_PROPERTY, "arthas");
if (location != null) {
if (!location.endsWith(".properties")) {
@ -407,7 +408,17 @@ public class ArthasBootstrap {
this.securityAuthenticator = new SecurityAuthenticatorImpl(configure.getUsername(), configure.getPassword());
shellServer = new ShellServerImpl(options);
BuiltinCommandPack builtinCommands = new BuiltinCommandPack();
List<String> disabledCommands = new ArrayList<String>();
if (configure.getDisabledCommands() != null) {
String[] strings = StringUtils.tokenizeToStringArray(configure.getDisabledCommands(), ",");
if (strings != null) {
for (String s : strings) {
disabledCommands.add(s);
}
}
}
BuiltinCommandPack builtinCommands = new BuiltinCommandPack(disabledCommands);
List<CommandResolver> resolvers = new ArrayList<CommandResolver>();
resolvers.add(builtinCommands);
for (CommandResolver resolver : resolvers) {

@ -31,6 +31,9 @@ public class SearchUtils {
}
final Set<Class<?>> matches = new HashSet<Class<?>>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
if (clazz == null) {
continue;
}
if (classNameMatcher.matching(clazz.getName())) {
matches.add(clazz);
}
@ -107,6 +110,9 @@ public class SearchUtils {
public static Set<Class<?>> searchSubClass(Instrumentation inst, Set<Class<?>> classSet) {
final Set<Class<?>> matches = new HashSet<Class<?>>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
if (clazz == null) {
continue;
}
for (Class<?> superClass : classSet) {
if (superClass.isAssignableFrom(clazz)) {
matches.add(clazz);

@ -956,4 +956,16 @@ public abstract class StringUtils {
}
return text.substring(pos + after.length());
}
public static String[] splitMethodInfo(String methodInfo) {
int index = methodInfo.indexOf('|');
return new String[] { methodInfo.substring(0, index), methodInfo.substring(index + 1, methodInfo.length()) };
}
public static String[] splitInvokeInfo(String invokeInfo) {
int index1 = invokeInfo.indexOf('|');
int index2 = invokeInfo.indexOf('|', index1 + 1);
return new String[] { invokeInfo.substring(0, index1), invokeInfo.substring(index1 + 1, index2),
invokeInfo.substring(index2 + 1, invokeInfo.length()) };
}
}

@ -0,0 +1,28 @@
package com.taobao.arthas.core.advisor;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import com.taobao.arthas.core.util.StringUtils;
/**
*
* @author hengyunabc 2021-07-14
*
*/
public class SpyImplTest {
@Test
public void testSplitMethodInfo() throws Throwable {
Assertions.assertThat(StringUtils.splitMethodInfo("a|b")).containsExactly("a", "b");
Assertions.assertThat(StringUtils.splitMethodInfo("xxxxxxxxxx|fffffffffff")).containsExactly("xxxxxxxxxx",
"fffffffffff");
}
@Test
public void testSplitInvokeInfo() throws Throwable {
Assertions.assertThat(StringUtils.splitInvokeInfo("a|b|c")).containsExactly("a", "b", "c");
Assertions.assertThat(StringUtils.splitInvokeInfo("xxxxxxxxxx|fffffffffff|yyy")).containsExactly("xxxxxxxxxx",
"fffffffffff", "yyy");
}
}

@ -13,6 +13,7 @@ import org.mockito.internal.util.reflection.FieldSetter;
import com.taobao.arthas.common.JavaVersionUtils;
import com.taobao.arthas.core.bytecode.TestHelper;
import com.taobao.arthas.core.config.Configure;
import com.taobao.arthas.core.env.ArthasEnvironment;
import net.bytebuddy.agent.ByteBuddyAgent;
@ -60,4 +61,43 @@ public class ArthasBootstrapTest {
System.err.println(loadClass);
}
@Test
public void testConfigLocationNull() throws Exception {
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
String location = ArthasBootstrap.reslove(arthasEnvironment, ArthasBootstrap.CONFIG_LOCATION_PROPERTY, null);
assertThat(location).isEqualTo(null);
}
@Test
public void testConfigLocation() throws Exception {
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
System.setProperty("hhhh", "fff");
System.setProperty(ArthasBootstrap.CONFIG_LOCATION_PROPERTY, "test${hhhh}");
String location = ArthasBootstrap.reslove(arthasEnvironment, ArthasBootstrap.CONFIG_LOCATION_PROPERTY, null);
System.clearProperty("hhhh");
System.clearProperty(ArthasBootstrap.CONFIG_LOCATION_PROPERTY);
assertThat(location).isEqualTo("test" + "fff");
}
@Test
public void testConfigNameDefault() throws Exception {
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
String configName = ArthasBootstrap.reslove(arthasEnvironment, ArthasBootstrap.CONFIG_NAME_PROPERTY, "arthas");
assertThat(configName).isEqualTo("arthas");
}
@Test
public void testConfigName() throws Exception {
ArthasEnvironment arthasEnvironment = new ArthasEnvironment();
System.setProperty(ArthasBootstrap.CONFIG_NAME_PROPERTY, "testName");
String configName = ArthasBootstrap.reslove(arthasEnvironment, ArthasBootstrap.CONFIG_NAME_PROPERTY, "arthas");
System.clearProperty(ArthasBootstrap.CONFIG_NAME_PROPERTY);
assertThat(configName).isEqualTo("testName");
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -77,7 +77,7 @@
</modules>
<properties>
<revision>3.5.1</revision>
<revision>3.5.2</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.source>1.6</maven.compiler.source>
@ -95,7 +95,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>bytekit-core</artifactId>
<version>0.0.5</version>
<version>0.0.7</version>
</dependency>
<dependency>
<groupId>org.benf</groupId>
@ -115,7 +115,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
<version>1.7.31</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
@ -130,7 +130,7 @@
<dependency>
<groupId>com.alibaba.arthas</groupId>
<artifactId>arthas-repackage-logger</artifactId>
<version>0.0.8</version>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
@ -206,13 +206,13 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.10.18</version>
<version>1.11.6</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.10.18</version>
<version>1.11.6</version>
</dependency>
<dependency>

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@ -32,6 +32,21 @@ arthas.sessionTimeout=1800
> 如果是防止一个机器上启动多个 arthas端口冲突。可以配置为随机端口或者配置为 -1并且通过tunnel server来使用arthas。
### 禁止指定命令
> since 3.5.2
比如配置:
```
arthas.disabledCommands=stop,dump
```
也可以在命令行配置: `--disabled-commands stop,dump`
> 默认情况下arthas-spring-boot-starter会禁掉`stop`命令。
## 配置的优先级
配置的优先级是:命令行参数 > System Env > System Properties > arthas.properties 。

@ -0,0 +1,7 @@
cls
===
清空当前屏幕区域。
> 非终端模式下使用cls指令会提示"Command 'cls' is only support tty session."。

@ -45,12 +45,12 @@
### Arthas 基础命令
* help——查看命令帮助信息
* cls——清空当前屏幕区域
* session——查看当前会话的信息
* [reset](reset.md)——重置增强类,将被 Arthas 增强过的类全部还原Arthas 服务端关闭时会重置所有增强过的类
* version——输出当前目标 Java 进程所加载的 Arthas 版本号
* history——打印命令历史
* quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
* stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
* [keymap](keymap.md)——Arthas快捷键列表及自定义快捷键
* [help](help.md)
* [cls](cls.md)
* [session](session.md)
* [reset](reset.md)
* [version](version.md)
* [history](history.md)
* [quit](quit.md)
* [stop](stop.md)
* [keymap](keymap.md)

@ -5,14 +5,18 @@
## 招聘
* [期待你的加入](https://mp.weixin.qq.com/s/k5jozrSgmyH0tcQfrDkxUQ)
* [期待你的加入](https://mp.weixin.qq.com/s/XQv8GnqGT3pzceVwzeiy-A)
### Issues
使用疑问意见可以直接在Issues里提出 [https://github.com/alibaba/arthas/issues](https://github.com/alibaba/arthas/issues)
使用疑问意见可以直接在Issues里提出 [https://github.com/alibaba/arthas/issues](https://github.com/alibaba/arthas/issues)
### 微信公众号
欢迎关注公众号获取Arthas项目的信息、源码分析、案例实践。
![](_static/qrcode_gongzhonghao.jpg)
### 钉钉群

@ -30,6 +30,22 @@ arthas.sessionTimeout=1800
> If you want to prevent multiple arthas port conflicts on a machine. It can be configured as a random port, or configured as -1, and use arthas through the tunnel server.
### disable specify commands
> since 3.5.2
Such as configuration:
```
arthas.disabledCommands=stop,dump
```
It can also be configured on the command line: `--disabled-commands stop,dump`.
> By default, arthas-spring-boot-starter will disable the `stop` command.
## Configured order
The order of configuration is: command line parameters > System Env > System Properties > arthas.properties.

@ -0,0 +1,7 @@
cls
===
clear current console.
> if not in tty mode,it will warn "Command 'cls' is only support tty session.".

@ -48,7 +48,8 @@ No.
##### Can arthas view the value of a variable in memory?
No. But you can use some tricks to intercept the object with the `tt` command, or fetch it from a static method.
1. You can use [`vmtool`](vmtool.md) command.
2. You can use some tricks to intercept the object with the [`tt`](tt.md) command, or fetch it from a static method.
##### How to filter method with the same name?
@ -60,13 +61,13 @@ You can use `-v` to view the condition express result [https://github.com/alibab
example [math-game](quick-start.md)
```bash
watch demo.MathGame primeFactors traceE '{params,returnObj,throwExp}' -v -n 5 -x 3 'params.length >0 && returnObj instanceof java.util.List'
watch demo.MathGame primeFactors '{params,returnObj,throwExp}' 'params.length >0 && returnObj instanceof java.util.List' -v
```
##### How to watch or trace constructor?
```bash
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v -n 5 -x 3 '1==1'
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v
```
@ -83,4 +84,11 @@ Yes. Just download the full size package and unzip it, refer to: [Download](down
##### Attach the process with pid 1 in docker/k8s failed
Reference: [https://github.com/alibaba/arthas/issues/362#issuecomment-448185416](https://github.com/alibaba/arthas/issues/362#issuecomment-448185416)
Reference: [https://github.com/alibaba/arthas/issues/362#issuecomment-448185416](https://github.com/alibaba/arthas/issues/362#issuecomment-448185416)
##### Why is the new version of Arthas downloaded, but the old version is connected?
For example, the started version of `as.sh/arthas-boot.jar` is 3.5.*, but after connecting, the printed arthas version is 3.4.*.
It may be that the target process has been diagnosed with the old version of arthas before. You can execute `stop` to stop the old version of arthas, and then reuse the new version to attach.

@ -0,0 +1,87 @@
help
===
show help message, the command can show all the commands that current Arthas server supports,or you can use the command to show the detail usage of another command.
> [help command] equals [command -help],both is to show the detail usage of one command.
### Options
| Name | Specification |
| ------: | :-------------------------------------------------------- |
| | show all the commands that current Arthas server supports |
| [name:] | show the detail usage of one command |
### Usage
```bash
$ help
NAME DESCRIPTION
help Display Arthas Help
auth Authenticates the current session
keymap Display all the available keymap for the specified connection.
sc Search all the classes loaded by JVM
sm Search the method of classes loaded by JVM
classloader Show classloader info
jad Decompile class
getstatic Show the static field of a class
monitor Monitor method execution statistics, e.g. total/success/failure count, average rt, fail rate, etc.
stack Display the stack trace for the specified class and method
thread Display thread info, thread stack
trace Trace the execution time of specified method invocation.
watch Display the input/output parameter, return object, and thrown exception of specified method invocation
tt Time Tunnel
jvm Display the target JVM information
perfcounter Display the perf counter information.
ognl Execute ognl expression.
mc Memory compiler, compiles java files into bytecode and class files in memory.
redefine Redefine classes. @see Instrumentation#redefineClasses(ClassDefinition...)
retransform Retransform classes. @see Instrumentation#retransformClasses(Class...)
dashboard Overview of target jvm's thread, memory, gc, vm, tomcat info.
dump Dump class byte array from JVM
heapdump Heap dump
options View and change various Arthas options
cls Clear the screen
reset Reset all the enhanced classes
version Display Arthas version
session Display current session information
sysprop Display, and change the system properties.
sysenv Display the system env.
vmoption Display, and update the vm diagnostic options.
logger Print logger info, and update the logger level
history Display command history
cat Concatenate and print files
base64 Encode and decode using Base64 representation
echo write arguments to the standard output
pwd Return working directory name
mbean Display the mbean information
grep grep command for pipes.
tee tee command for pipes.
profiler Async Profiler. https://github.com/jvm-profiling-tools/async-profiler
stop Stop/Shutdown Arthas server and exit the console.
```
```bash
$ help dashboard
USAGE:
dashboard [-h] [-i <value>] [-n <value>]
SUMMARY:
Overview of target jvm's thread, memory, gc, vm, tomcat info.
EXAMPLES:
dashboard
dashboard -n 10
dashboard -i 2000
WIKI:
https://arthas.aliyun.com/doc/dashboard
OPTIONS:
-h, --help this help
-i, --interval <value> The interval (in ms) between two executions, default is 5000 ms.
-n, --number-of-execution <value> The number of times this command will be executed.
```

@ -0,0 +1,31 @@
history
===
view command history.
> history of commands will persisted in a file named history, so the history command can show all the history commands of current Arthas server ,but not only history in current session.
### Options
| Name | Specification |
| ---: | :----------------------------- |
| [c:] | clear all the history commands |
| [n:] | view the nearest 5 commands |
### 使用参考
```bash
#view the nearest 3 commands
$ history 3
269 thread
270 cls
271 history 3
```
```bash
#clear all the history commands
$ history -c
$ history 3
1 history 3
```

@ -5,7 +5,7 @@ IDEA Plugin
* Jetbrains Plugin [https://plugins.jetbrains.com/plugin/13581-arthas-idea](https://plugins.jetbrains.com/plugin/13581-arthas-idea)
* Plugin Doc[https://www.yuque.com/docs/share/fa77c7b4-c016-4de6-9fa3-58ef25a97948?#](https://www.yuque.com/docs/share/fa77c7b4-c016-4de6-9fa3-58ef25a97948?#)
* Plugin Doc[https://www.yuque.com/arthas-idea-plugin](https://www.yuque.com/arthas-idea-plugin)
* Plugin Github [https://github.com/WangJi92/arthas-idea-plugin](https://github.com/WangJi92/arthas-idea-plugin)

@ -10,7 +10,7 @@ java -jar math-game.jar
`math-game` is a simple program that generates a random number every second, then it finds all prime factors of that number.
The source code of `math-game`: [View](https://github.com/alibaba/arthas/blob/master/demo/src/main/java/demo/MathGame.java)
The source code of `math-game`: [View](https://github.com/alibaba/arthas/blob/master/math-game/src/main/java/demo/MathGame.java)
## 2. Start Arthas

@ -0,0 +1,7 @@
quit
===
exit the current Arthas client without affecting other clients. equals **exit**、**logout**、**q** command.
> just exit Arthas client,it means Arthas server is not closed,so the changes you do will not be reseted.

@ -0,0 +1,21 @@
session
===
examines the current session,show the current binded processId and the sessionId.
> if exits tunnel serverit will also show agentId、tunnelServerUrl、connected status.
>
> if exits statUrlit will also show statUrl.
### Usage
```bash
$ session
Name Value
--------------------------------------------------
JAVA_PID 14584
SESSION_ID c2073d3b-443a-4a9b-9249-0c5d24a5756c
```

@ -29,6 +29,8 @@ arthas.tunnel-server=ws://47.75.156.201:7777/ws
All supported configuration: [Reference](https://github.com/alibaba/arthas/blob/master/arthas-spring-boot-starter/src/main/java/com/alibaba/arthas/spring/ArthasProperties.java)
> By default, arthas-spring-boot-starter will disable the `stop` command.
Reference: [Arthas Properties](arthas-properties.md)
### View Endpoint Information

@ -0,0 +1,7 @@
Stop
===
terminates the Arthas server, all the Arthas clients connecting to this server will be disconnected.
> the class redefined by redefine command will not be reset.

@ -0,0 +1,12 @@
version
===
prints out Arthas's version.
### Usage
```bash
$ version
3.5.1
```

@ -15,6 +15,8 @@ The user can fill in the IP and connect the remote arthas on other machines.
If you have suggestions for the Web Console, please leave a message here: [https://github.com/alibaba/arthas/issues/15](https://github.com/alibaba/arthas/issues/15)
* Copy and paste shortcut keys in Web Console: [https://github.com/alibaba/arthas/issues/1056](https://github.com/alibaba/arthas/issues/1056)
### Connect remote arthas through arthas tunnel server
[Arthas Tunnel](tunnel.md)

@ -47,7 +47,8 @@ options json-format true
##### 能不能查看内存里某个变量的值
不能。但可以用一些技巧,用`tt`命令拦截到对象,或者从静态函数里取到对象。
1. 可以使用[`vmtool`](vmtool.md)命令。
2. 可以用一些技巧,用[`tt`](tt.md)命令拦截到对象,或者从静态函数里取到对象。
##### 方法同名过滤
@ -59,13 +60,13 @@ options json-format true
例子[math-game](quick-start.md)
```bash
watch demo.MathGame primeFactors traceE '{params,returnObj,throwExp}' -v -n 5 -x 3 'params.length >0 && returnObj instanceof java.util.List'
watch demo.MathGame primeFactors '{params,returnObj,throwExp}' 'params.length >0 && returnObj instanceof java.util.List' -v
```
##### 怎么watch、trace 构造函数
```bash
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v -n 5 -x 3 '1==1'
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v
```
@ -82,4 +83,10 @@ watch demo.MathGame <init> '{params,returnObj,throwExp}' -v -n 5 -x 3 '1==1'
##### Attach docker/k8s 里的 pid 为 1 的进程失败
参考: [https://github.com/alibaba/arthas/issues/362#issuecomment-448185416](https://github.com/alibaba/arthas/issues/362#issuecomment-448185416)
参考: [https://github.com/alibaba/arthas/issues/362#issuecomment-448185416](https://github.com/alibaba/arthas/issues/362#issuecomment-448185416)
##### 为什么下载了新版本的Arthas连接的却是旧版本
比如启动的 `as.sh/arthas-boot.jar` 版本是3.5.* 的但是连接上之后打印的arthas版本是 3.4.* 的。
可能是之前使用旧版本的arthas诊断过目标进程。可以先执行`stop`停止掉旧版本的arthas再重新使用新版本attach。

@ -0,0 +1,87 @@
help
===
查看命令帮助信息可以查看当前arthas版本支持的指令或者查看具体指令的使用说明。
> [help 指令]的等同于[指令 -help],都是查看具体指令的使用说明。
### 参数说明
| 参数名称 | 参数说明 |
| -------: | :--------------------------------------- |
| 不接参数 | 查询当前arthas版本支持的指令以及指令描述 |
| [name:] | 查询具体指令的使用说明 |
### 使用参考
```
$ help
NAME DESCRIPTION
help Display Arthas Help
auth Authenticates the current session
keymap Display all the available keymap for the specified connection.
sc Search all the classes loaded by JVM
sm Search the method of classes loaded by JVM
classloader Show classloader info
jad Decompile class
getstatic Show the static field of a class
monitor Monitor method execution statistics, e.g. total/success/failure count, average rt, fail rate, etc.
stack Display the stack trace for the specified class and method
thread Display thread info, thread stack
trace Trace the execution time of specified method invocation.
watch Display the input/output parameter, return object, and thrown exception of specified method invocation
tt Time Tunnel
jvm Display the target JVM information
perfcounter Display the perf counter information.
ognl Execute ognl expression.
mc Memory compiler, compiles java files into bytecode and class files in memory.
redefine Redefine classes. @see Instrumentation#redefineClasses(ClassDefinition...)
retransform Retransform classes. @see Instrumentation#retransformClasses(Class...)
dashboard Overview of target jvm's thread, memory, gc, vm, tomcat info.
dump Dump class byte array from JVM
heapdump Heap dump
options View and change various Arthas options
cls Clear the screen
reset Reset all the enhanced classes
version Display Arthas version
session Display current session information
sysprop Display, and change the system properties.
sysenv Display the system env.
vmoption Display, and update the vm diagnostic options.
logger Print logger info, and update the logger level
history Display command history
cat Concatenate and print files
base64 Encode and decode using Base64 representation
echo write arguments to the standard output
pwd Return working directory name
mbean Display the mbean information
grep grep command for pipes.
tee tee command for pipes.
profiler Async Profiler. https://github.com/jvm-profiling-tools/async-profiler
stop Stop/Shutdown Arthas server and exit the console.
```
```
$ help dashboard
USAGE:
dashboard [-h] [-i <value>] [-n <value>]
SUMMARY:
Overview of target jvm's thread, memory, gc, vm, tomcat info.
EXAMPLES:
dashboard
dashboard -n 10
dashboard -i 2000
WIKI:
https://arthas.aliyun.com/doc/dashboard
OPTIONS:
-h, --help this help
-i, --interval <value> The interval (in ms) between two executions, default is 5000 ms.
-n, --number-of-execution <value> The number of times this command will be executed.
```

@ -0,0 +1,31 @@
history
===
打印命令历史。
> 历史指令会通过一个名叫history的文件持久化所以history指令可以查看当前arthas服务器的所有历史命令而不仅只是当前次会话使用过的命令。
### 参数说明
| 参数名称 | 参数说明 |
| -------: | :-------------------- |
| [c:] | 清空历史指令 |
| [n:] | 显示最近执行的n条指令 |
### 使用参考
```
#查看最近执行的3条指令
$ history 3
269 thread
270 cls
271 history 3
```
```
#清空指令
$ history -c
$ history 3
1 history 3
```

@ -5,7 +5,7 @@ IDEA Plugin
* Jetbrains 插件获取地址: [https://plugins.jetbrains.com/plugin/13581-arthas-idea](https://plugins.jetbrains.com/plugin/13581-arthas-idea)
* 使用文档:[https://www.yuque.com/docs/share/fa77c7b4-c016-4de6-9fa3-58ef25a97948?#](https://www.yuque.com/docs/share/fa77c7b4-c016-4de6-9fa3-58ef25a97948?#)
* 使用文档:[https://www.yuque.com/arthas-idea-plugin](https://www.yuque.com/arthas-idea-plugin)
* 源码地址: [https://github.com/WangJi92/arthas-idea-plugin](https://github.com/WangJi92/arthas-idea-plugin)

@ -10,7 +10,7 @@ java -jar math-game.jar
`math-game`是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。
`math-game`源代码:[查看](https://github.com/alibaba/arthas/blob/master/demo/src/main/java/demo/MathGame.java)
`math-game`源代码:[查看](https://github.com/alibaba/arthas/blob/master/math-game/src/main/java/demo/MathGame.java)
## 2. 启动arthas

@ -0,0 +1,7 @@
quit
===
退出当前 Arthas 客户端,其他 Arthas 客户端不受影响。等同于**exit**、**logout**、**q**三个指令。
> 只是退出当前Arthas客户端Arthas的服务器端并没有关闭所做的修改也不会被重置。

@ -0,0 +1,22 @@
session
===
查看当前会话的信息显示当前绑定的pid以及会话id。
> 如果配置了tunnel server会追加打印 代理id、tunnel服务器的url以及连接状态。
>
> 如果使用了staturl做统计会追加显示statUrl地址。
### 使用参考
```
$ session
Name Value
--------------------------------------------------
JAVA_PID 14584
SESSION_ID c2073d3b-443a-4a9b-9249-0c5d24a5756c
```

@ -31,6 +31,8 @@ arthas.tunnel-server=ws://47.75.156.201:7777/ws
全部支持的配置项:[参考](https://github.com/alibaba/arthas/blob/master/arthas-spring-boot-starter/src/main/java/com/alibaba/arthas/spring/ArthasProperties.java)
> 默认情况下arthas-spring-boot-starter会禁掉`stop`命令。
参考:[Arthas Properties](arthas-properties.md)
### 查看Endpoint信息

@ -0,0 +1,7 @@
Stop
===
关闭 Arthas 服务端,所有 Arthas 客户端全部退出。
> 关闭Arthas服务器之前会重置掉所有做过的增强类。但是用redefine重加载的类内容不会被重置。

@ -0,0 +1,12 @@
version
===
输出当前目标 Java 进程所加载的 Arthas 版本号
### 使用参考
```
$ version
3.5.1
```

@ -16,9 +16,7 @@ Arthas目前支持Web Console用户在attach成功之后可以直接访问
> 默认情况下arthas只listen 127.0.0.1,所以如果想从远程连接,则可以使用 `--target-ip`参数指定listen的IP更多参考`-h`的帮助说明。
> 注意会有安全风险考虑下面的tunnel server的方案。
后续更多Web Console功能支持请到issue下留言[https://github.com/alibaba/arthas/issues/15](https://github.com/alibaba/arthas/issues/15)
* 在Web Console复制粘贴快捷键参考 [https://github.com/alibaba/arthas/issues/1056](https://github.com/alibaba/arthas/issues/1056)
### 使用arthas tunnel server连接远程arthas
[Arthas Tunnel](tunnel.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -25,7 +25,7 @@ public class ArthasProperties {
/**
* supoort apps.html/agents.html
*/
private boolean enableDetatilPages = false;
private boolean enableDetailPages = false;
public Server getServer() {
return server;
@ -43,12 +43,12 @@ public class ArthasProperties {
this.embeddedRedis = embeddedRedis;
}
public boolean isEnableDetatilPages() {
return enableDetatilPages;
public boolean isEnableDetailPages() {
return enableDetailPages;
}
public void setEnableDetatilPages(boolean enableDetatilPages) {
this.enableDetatilPages = enableDetatilPages;
public void setEnableDetailPages(boolean enableDetailPages) {
this.enableDetailPages = enableDetailPages;
}
public static class Server {

@ -2,6 +2,7 @@ package com.alibaba.arthas.tunnel.server.app.web;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -40,7 +41,7 @@ public class DetailAPIController {
@RequestMapping("/api/tunnelApps")
@ResponseBody
public Set<String> tunnelApps(HttpServletRequest request, Model model) {
if (!arthasProperties.isEnableDetatilPages()) {
if (!arthasProperties.isEnableDetailPages()) {
throw new IllegalAccessError("not allow");
}
@ -67,7 +68,7 @@ public class DetailAPIController {
@ResponseBody
public Map<String, AgentClusterInfo> tunnelAgentIds(@RequestParam(value = "app", required = true) String appName,
HttpServletRequest request, Model model) {
if (!arthasProperties.isEnableDetatilPages()) {
if (!arthasProperties.isEnableDetailPages()) {
throw new IllegalAccessError("not allow");
}
@ -80,6 +81,28 @@ public class DetailAPIController {
return Collections.emptyMap();
}
/**
* check if agentId exists
* @param agentId
* @return
*/
@RequestMapping("/api/tunnelAgents")
@ResponseBody
public Map<String, Object> tunnelAgentIds(@RequestParam(value = "agentId", required = true) String agentId) {
Map<String, Object> result = new HashMap<String, Object>();
boolean success = false;
try {
AgentClusterInfo info = tunnelClusterStore.findAgent(agentId);
if (info != null) {
success = true;
}
} catch (Throwable e) {
logger.error("try to find agentId error, id: {}", agentId, e);
}
result.put("success", success);
return result;
}
private static String findAppNameFromAgentId(String id) {
int index = id.indexOf('_');
if (index < 0 || index >= id.length()) {

@ -10,7 +10,7 @@ management.endpoints.web.exposure.include=*
spring.security.user.name=arthas
arthas.enable-detatil-pages=true
arthas.enable-detail-pages=true
spring.cache.type=caffeine
spring.cache.cache-names=inMemoryClusterCache
spring.cache.caffeine.spec=maximumSize=3000,expireAfterAccess=3600s

@ -0,0 +1,22 @@
package com.alibaba.arthas.tunnel.server.app;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* @author hengyunabc 2021-07-12
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { ArthasTunnelApplication.class })
public class ArthasTunnelApplicationTest {
@Test
public void contextLoads() {
System.out.println("hello");
}
}

@ -31,6 +31,10 @@
"title": "Watch",
"text": "watch.md"
},
{
"title": "Vmtool",
"text": "vmtool.md"
},
{
"title": "Exit/Stop",
"text": "exit.md"

@ -0,0 +1,20 @@
通过`vmtool`命令,可以搜索内存对象。
`vmtool --action getInstances --className java.lang.String --limit 10`{{execute T2}}
```bash
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
@String[com/taobao/arthas/core/shell/session/Session],
@String[com.taobao.arthas.core.shell.session.Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/],
@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
@String[java/util/concurrent/locks/LockSupport],
]
```

@ -31,6 +31,10 @@
"title": "Watch",
"text": "watch.md"
},
{
"title": "Vmtool",
"text": "vmtool.md"
},
{
"title": "Exit/Stop",
"text": "exit.md"

@ -0,0 +1,20 @@
The `vmtool` command can search object in JVM.
`vmtool --action getInstances --className java.lang.String --limit 10`{{execute T2}}
```bash
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
@String[com/taobao/arthas/core/shell/session/Session],
@String[com.taobao.arthas.core.shell.session.Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/],
@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
@String[java/util/concurrent/locks/LockSupport],
]
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

@ -2,3 +2,8 @@
* Issues: https://github.com/alibaba/arthas/issues
* 文档: https://arthas.aliyun.com/doc
* Documentation: https://arthas.aliyun.com/doc/en
欢迎关注公众号获取Arthas项目的信息、源码分析、案例实践。
![Arthas公众号](./assets/qrcode_gongzhonghao.jpg)

Loading…
Cancel
Save