Merge tag 'arthas-all-3.5.6' into channel-server

pull/1490/head
gongdewei 3 years ago
commit 6a8c7acd11

@ -21,7 +21,7 @@ jobs:
path: arthas-vmtool/target/lib*
mac:
runs-on: macos-10.15
runs-on: macos-latest
steps:
- uses: actions/checkout@v2

@ -26,6 +26,10 @@ Please refer to [README.MD at tutorials/katacoda](tutorials/katacoda/README.md#c
Recommend to use [`as-package.sh`](as-package.sh) to package, which will auto-install the latest Arthas to local `~/.arthas` and when debugging, Arthas will auto-load the latest version.
* To support jni, cpp compiling environment support is required
* mac needs to install xcode
* windows need to install gcc
F.Y.I
1. when using [`as.sh`](https://github.com/alibaba/arthas/blob/master/bin/as.sh) to start Arthas, it will get the latest version under `~/.arthas/lib`;
2. when [`as-package.sh`](as-package.sh) packaging, it will get the version from `pom.xml` and suffix it with the current timestamp e.g. `3.0.5.20180917161808`.
@ -91,6 +95,11 @@ Tip: you can use `--versions` to list all available versions.
本地开发时,推荐执行`as-package.sh`来打包会自动安装最新版本的arthas到`~/.arthas`目录里。debug时会自动使用最新版本。
* 代码里要编译jni需要cpp编译环境支持
* mac需要安装xcode
* windows需要安装gcc
`as.sh`在启动时,会对`~/.arthas/lib`下面的目录排序,取最新的版本。`as-package.sh`在打包时,会取`pom.xml`里的版本号,再拼接上当前时间,比如: `3.0.5.20180917161808`,这样子排序时取的就是最新的版本。
也可以直接 `./mvnw clean package -DskipTests`打包生成的zip在 `packaging/target/` 下面。但是注意`as.sh`启动加载的是`~/.arthas/lib`下面的版本。
@ -150,6 +159,8 @@ chmod +x /tmp/sphinx.osx-x86_64
* 发布完maven仓库之后需要到阿里云的仓库里检查是否同步有可能有延时
比如下载地址: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.x.x/arthas-packaging-3.x.x-bin.zip
版本号信息地址: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/maven-metadata.xml
* 打上tagpush tag到仓库上
* 需要更新 gh-pages 分支下面的 arthas-boot.jar/math-game.jar/as.sh ,下载 doc.zip解压覆盖掉文档的更新

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

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

@ -10,3 +10,18 @@ The greys-anatomy Project
=================
Please visit Github for more information:
* https://github.com/oldmanpushcart/greys-anatomy
-------------------------------------------------------------------------------
This product contains a modified portion of 'Apache Commons Lang':
* LICENSE:
* Apache License 2.0
* HOMEPAGE:
* https://commons.apache.org/proper/commons-lang/
This product contains a modified portion of 'Apache Commons Net':
* LICENSE:
* Apache License 2.0
* HOMEPAGE:
* https://commons.apache.org/proper/commons-net/

@ -2,7 +2,7 @@
![arthas](site/src/site/sphinx/arthas.png)
[![Build Status](https://travis-ci.org/alibaba/arthas.svg?branch=master)](https://travis-ci.org/alibaba/arthas)
[![Build Status](https://github.com/alibaba/arthas/workflows/JavaCI/badge.svg)](https://github.com/alibaba/arthas/actions)
[![codecov](https://codecov.io/gh/alibaba/arthas/branch/master/graph/badge.svg)](https://codecov.io/gh/alibaba/arthas)
[![maven](https://img.shields.io/maven-central/v/com.taobao.arthas/arthas-packaging.svg)](https://search.maven.org/search?q=g:com.taobao.arthas)
![license](https://img.shields.io/github/license/alibaba/arthas.svg)
@ -402,7 +402,7 @@ Started [cpu] profiling
```
$ profiler stop
profiler output file: /tmp/demo/arthas-output/20191125-135546.svg
profiler output file: /tmp/demo/arthas-output/20211207-111550.html
OK
```
@ -431,6 +431,8 @@ Welcome to register the company name in this issue: https://github.com/alibaba/a
![vipkid](static/vipkid.png)
![百度凤巢](static/baidufengchao.png)
![有赞](static/youzan.png)
![科大讯飞](static/iflytek.png)
![智联招聘](static/zhaopin.png)
### Derivative Projects

@ -4,13 +4,14 @@
![arthas](site/src/site/sphinx/arthas.png)
[![Build Status](https://travis-ci.org/alibaba/arthas.svg?branch=master)](https://travis-ci.org/alibaba/arthas)
[![Build Status](https://github.com/alibaba/arthas/workflows/JavaCI/badge.svg)](https://github.com/alibaba/arthas/actions)
[![codecov](https://codecov.io/gh/alibaba/arthas/branch/master/graph/badge.svg)](https://codecov.io/gh/alibaba/arthas)
[![maven](https://img.shields.io/maven-central/v/com.taobao.arthas/arthas-packaging.svg)](https://search.maven.org/search?q=g:com.taobao.arthas)
![license](https://img.shields.io/github/license/alibaba/arthas.svg)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/alibaba/arthas.svg)](http://isitmaintained.com/project/alibaba/arthas "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/alibaba/arthas.svg)](http://isitmaintained.com/project/alibaba/arthas "Percentage of issues still open")
English version goes [here](README.md).
`Arthas` 是Alibaba开源的Java诊断工具深受开发者喜爱。
@ -389,7 +390,7 @@ Started [cpu] profiling
```
$ profiler stop
profiler output file: /tmp/demo/arthas-output/20191125-135546.svg
profiler output file: /tmp/demo/arthas-output/20211207-111550.html
OK
```
@ -418,6 +419,8 @@ Arthas有超过120家登记用户[查看全部](USERS.md)。
![vipkid](static/vipkid.png)
![百度凤巢](static/baidufengchao.png)
![有赞](static/youzan.png)
![科大讯飞](static/iflytek.png)
![智联招聘](static/zhaopin.png)
### 衍生项目

@ -128,6 +128,8 @@ Welcome to register the company name in this issue: https://github.com/alibaba/a
![有赞](static/youzan.png)
![中原银行](static/zhongyuanbank.png)
![CVTE](static/cvte.png)
![北京喜得国际网络科技有限公司](static/cider.png)
![智联招聘](static/zhaopin.png)
* 网易云
* 派迩信息技术
@ -154,4 +156,5 @@ Welcome to register the company name in this issue: https://github.com/alibaba/a
* 中国有赞
* 车巴达
* 华为
* 云管书
* 云管书
* 智联招聘

@ -7,6 +7,7 @@ import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ -36,7 +37,7 @@ public class ArthasConfiguration {
* </pre>
*/
@ConfigurationProperties(prefix = "arthas")
@ConditionalOnMissingBean
@ConditionalOnMissingBean(name="arthasConfigMap")
@Bean
public HashMap<String, String> arthasConfigMap() {
return new HashMap<String, String>();
@ -44,7 +45,7 @@ public class ArthasConfiguration {
@ConditionalOnMissingBean
@Bean
public ArthasAgent arthasAgent(@Autowired Map<String, String> arthasConfigMap,
public ArthasAgent arthasAgent(@Autowired @Qualifier("arthasConfigMap") Map<String, String> arthasConfigMap,
@Autowired ArthasProperties arthasProperties) throws Throwable {
arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap);
ArthasProperties.updateArthasConfigMapDefaultValue(arthasConfigMap);

@ -12,7 +12,7 @@ import java.util.Map.Entry;
public class StringUtils {
public static Map<String, String> removeDashKey(Map<String, String> map) {
Map<String, String> result = new HashMap<String, String>();
Map<String, String> result = new HashMap<String, String>(map.size());
for (Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();

@ -20,13 +20,12 @@
<activation>
<os>
<family>mac</family>
<arch>x86_64</arch>
</os>
</activation>
<properties>
<os_name>macos</os_name>
<os_arch_option>-m64</os_arch_option>
<lib_name>libArthasJniLibrary-x64.dylib</lib_name>
<os_arch_option>-arch x86_64 -arch arm64</os_arch_option>
<lib_name>libArthasJniLibrary.dylib</lib_name>
</properties>
</profile>
@ -181,7 +180,7 @@
<linkerStartOption>${os_arch_option}</linkerStartOption>
<linkerStartOption>-fpic</linkerStartOption>
<linkerStartOption>-shared</linkerStartOption>
<linkerStartOption>-o</linkerStartOption>
<!-- <linkerStartOption>-o</linkerStartOption> -->
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOption>-o ${project.build.directory}/${lib_name}</linkerEndOption>

@ -8,10 +8,10 @@
# program : Arthas
# author : Core Engine @ Taobao.com
# date : 2021-09-02
# date : 2022-03-03
# current arthas script version
ARTHAS_SCRIPT_VERSION=3.5.4
ARTHAS_SCRIPT_VERSION=3.5.6
# SYNOPSIS
# rreadlink <fileOrDirPath>
@ -191,7 +191,7 @@ case "$(uname -s)" in
*) OS_TYPE="UNKNOWN"
esac
# check curl/grep/awk/telent/unzip command
# check curl/grep/awk/telnet/unzip command
if ! [ -x "$(command -v curl)" ]; then
echo 'Error: curl is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
@ -466,7 +466,7 @@ 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.4
./as.sh --use-version 3.5.6
./as.sh --session-timeout 3600
./as.sh --attach-only
./as.sh --disabled-commands stop,dump

@ -57,7 +57,7 @@ import com.taobao.middleware.cli.annotations.Summary;
+ " 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.4\n"
+ " java -jar arthas-boot.jar --use-version 3.5.6\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"
@ -720,15 +720,19 @@ public class Bootstrap {
result.append("Local versions:\n");
for (String version : versionList) {
result.append(" " + version).append('\n');
result.append(" ").append(version).append('\n');
}
result.append("Remote versions:\n");
List<String> remoteVersions = DownloadUtils.readRemoteVersions();
Collections.reverse(remoteVersions);
for (String version : remoteVersions) {
result.append(" " + version).append('\n');
}
List<String> remoteVersions = DownloadUtils.readRemoteVersions();
if (remoteVersions != null) {
Collections.reverse(remoteVersions);
for (String version : remoteVersions) {
result.append(" " + version).append('\n');
}
} else {
result.append(" unknown\n");
}
return result.toString();
}

@ -285,7 +285,7 @@ public class TelnetConsole {
}
// ctrl + c event callback
consoleReader.getKeys().bind(new Character((char) CTRL_C).toString(), new ActionListener() {
consoleReader.getKeys().bind(Character.toString((char) CTRL_C), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
@ -300,7 +300,7 @@ public class TelnetConsole {
});
// ctrl + d event call back
consoleReader.getKeys().bind(new Character(KeyMap.CTRL_D).toString(), eotEventCallback);
consoleReader.getKeys().bind(Character.toString(KeyMap.CTRL_D), eotEventCallback);
try {
telnet.connect(telnetConsole.getTargetIp(), telnetConsole.getPort());

@ -180,11 +180,9 @@ public class PrintCommandListener implements ProtocolCommandListener
}
int pos = msg.indexOf(SocketClient.NETASCII_EOL);
if (pos > 0) {
StringBuilder sb = new StringBuilder();
sb.append(msg.substring(0,pos));
sb.append(__eolMarker);
sb.append(msg.substring(pos));
return sb.toString();
return msg.substring(0, pos) +
__eolMarker +
msg.substring(pos);
}
return msg;
}

@ -1065,7 +1065,7 @@ class Telnet extends SocketClient
_output_.flush();
}
aytMonitor.wait(timeout);
if (aytFlag == false)
if (!aytFlag)
{
retValue = false;
aytFlag = true;

@ -115,7 +115,7 @@ public class FileUtils {
if (file.isDirectory()) {
throw new IOException("File '" + file + "' exists but is a directory");
}
if (file.canWrite() == false) {
if (!file.canWrite()) {
throw new IOException("File '" + file + "' cannot be written to");
}
} else {

@ -212,7 +212,7 @@ public class ReflectUtils {
while ((index = className.indexOf("[]", index) + 1) > 0) {
dimensions++;
}
StringBuffer brackets = new StringBuffer(className.length() - dimensions);
StringBuilder brackets = new StringBuilder(className.length() - dimensions);
for (int i = 0; i < dimensions; i++) {
brackets.append('[');
}

@ -9,7 +9,7 @@ public class VmToolUtils {
private static String libName = null;
static {
if (OSUtils.isMac()) {
libName = "libArthasJniLibrary-x64.dylib";
libName = "libArthasJniLibrary.dylib";
}
if (OSUtils.isLinux()) {
libName = "libArthasJniLibrary-x64.so";

@ -26,6 +26,7 @@ import java.lang.ref.WeakReference;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Enumeration;
@ -619,10 +620,7 @@ public final class ConcurrentWeakKeyHashMap<K, V> extends AbstractMap<K, V> impl
if (count != 0) {
lock();
try {
HashEntry<K, V>[] tab = table;
for (int i = 0; i < tab.length; i ++) {
tab[i] = null;
}
Arrays.fill(table, null);
++ modCount;
// replace the reference queue to avoid unnecessary stale
// cleanups

@ -66,6 +66,10 @@
<pattern>io.netty</pattern>
<shadedPattern>${arthas.deps.package}.io.netty</shadedPattern>
</relocation>
<relocation>
<pattern>com.alibaba.fastjson</pattern>
<shadedPattern>${arthas.deps.package}.com.alibaba.fastjson</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@ -206,7 +210,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.1</version>
<version>2.12.4</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

@ -12,6 +12,7 @@ import com.taobao.middleware.cli.CommandLine;
import com.taobao.middleware.cli.Option;
import com.taobao.middleware.cli.TypedOption;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
@ -132,8 +133,19 @@ public class Arthas {
//convert jar path to unicode string
configure.setArthasAgent(encodeArg(arthasAgentPath));
configure.setArthasCore(encodeArg(configure.getArthasCore()));
virtualMachine.loadAgent(arthasAgentPath,
configure.getArthasCore() + ";" + configure.toString());
try {
virtualMachine.loadAgent(arthasAgentPath,
configure.getArthasCore() + ";" + configure.toString());
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("Non-numeric value found")) {
AnsiLog.warn(e);
AnsiLog.warn("It seems to use the lower version of JDK to attach the higher version of JDK.");
AnsiLog.warn(
"This error message can be ignored, the attach may have been successful, and it will still try to connect.");
} else {
throw e;
}
}
} finally {
if (null != virtualMachine) {
virtualMachine.detach();

@ -79,7 +79,7 @@ public class GlobalOptions {
summary = "Option to control include default method in interface when class matching",
description = "This option disable to include default method in interface when matching class."
)
public static volatile boolean isSupportDefaultMethod = true && JavaVersionUtils.isGreaterThanJava7();
public static volatile boolean isSupportDefaultMethod = JavaVersionUtils.isGreaterThanJava7();
/**
*

@ -23,8 +23,7 @@ public interface AdviceListener {
/**
*
*
* @param loader
* @param className
* @param clazz
* @param methodName
* @param methodDesc
* @param target
@ -39,8 +38,7 @@ public interface AdviceListener {
/**
*
*
* @param loader
* @param className
* @param clazz
* @param methodName
* @param methodDesc
* @param target
@ -58,8 +56,7 @@ public interface AdviceListener {
/**
*
*
* @param loader
* @param className
* @param clazz
* @param methodName
* @param methodDesc
* @param target

@ -60,32 +60,30 @@ public class AdviceListenerManager {
@Override
public void run() {
try {
if (adviceListenerMap != null) {
for (Entry<ClassLoader, ClassLoaderAdviceListenerManager> entry : adviceListenerMap.entrySet()) {
ClassLoaderAdviceListenerManager adviceListenerManager = entry.getValue();
synchronized (adviceListenerManager) {
for (Entry<String, List<AdviceListener>> eee : adviceListenerManager.map.entrySet()) {
List<AdviceListener> listeners = eee.getValue();
List<AdviceListener> newResult = new ArrayList<AdviceListener>();
for (AdviceListener listener : listeners) {
if (listener instanceof ProcessAware) {
ProcessAware processAware = (ProcessAware) listener;
Process process = processAware.getProcess();
if (process == null) {
continue;
}
ExecStatus status = process.status();
if (!status.equals(ExecStatus.TERMINATED)) {
newResult.add(listener);
}
for (Entry<ClassLoader, ClassLoaderAdviceListenerManager> entry : adviceListenerMap.entrySet()) {
ClassLoaderAdviceListenerManager adviceListenerManager = entry.getValue();
synchronized (adviceListenerManager) {
for (Entry<String, List<AdviceListener>> eee : adviceListenerManager.map.entrySet()) {
List<AdviceListener> listeners = eee.getValue();
List<AdviceListener> newResult = new ArrayList<AdviceListener>();
for (AdviceListener listener : listeners) {
if (listener instanceof ProcessAware) {
ProcessAware processAware = (ProcessAware) listener;
Process process = processAware.getProcess();
if (process == null) {
continue;
}
ExecStatus status = process.status();
if (!status.equals(ExecStatus.TERMINATED)) {
newResult.add(listener);
}
}
}
if (newResult.size() != listeners.size()) {
adviceListenerManager.map.put(eee.getKey(), newResult);
}
if (newResult.size() != listeners.size()) {
adviceListenerManager.map.put(eee.getKey(), newResult);
}
}
}
}

@ -25,7 +25,6 @@ public class AdviceWeaver {
/**
*
*
* @param adviceId ID
* @param listener
*/
public static void reg(AdviceListener listener) {
@ -40,7 +39,7 @@ public class AdviceWeaver {
/**
*
*
* @param adviceId ID
* @param listener
*/
public static void unReg(AdviceListener listener) {
if (null != listener) {

@ -42,6 +42,7 @@ import com.alibaba.bytekit.asm.location.filter.InvokeContainLocationFilter;
import com.alibaba.bytekit.asm.location.filter.LocationFilter;
import com.alibaba.bytekit.utils.AsmOpUtils;
import com.alibaba.bytekit.utils.AsmUtils;
import com.taobao.arthas.common.Pair;
import com.taobao.arthas.core.GlobalOptions;
import com.taobao.arthas.core.advisor.SpyInterceptors.SpyInterceptor1;
import com.taobao.arthas.core.advisor.SpyInterceptors.SpyInterceptor2;
@ -76,6 +77,7 @@ public class Enhancer implements ClassFileTransformer {
private final Matcher methodNameMatcher;
private final EnhancerAffect affect;
private Set<Class<?>> matchingClasses = null;
private static final ClassLoader selfClassLoader = Enhancer.class.getClassLoader();
// 被增强的类的缓存
private final static Map<Class<?>/* Class */, Object> classBytesCache = new WeakHashMap<Class<?>, Object>();
@ -143,7 +145,7 @@ public class Enhancer implements ClassFileTransformer {
interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class));
if (this.isTracing) {
if (this.skipJDKTrace == false) {
if (!this.skipJDKTrace) {
interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class));
interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class));
interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class));
@ -320,14 +322,35 @@ public class Enhancer implements ClassFileTransformer {
*
* @param classes
*/
private void filter(Set<Class<?>> classes) {
private List<Pair<Class<?>, String>> filter(Set<Class<?>> classes) {
List<Pair<Class<?>, String>> filteredClasses = new ArrayList<Pair<Class<?>, String>>();
final Iterator<Class<?>> it = classes.iterator();
while (it.hasNext()) {
final Class<?> clazz = it.next();
if (null == clazz || isSelf(clazz) || isUnsafeClass(clazz) || isUnsupportedClass(clazz) || isExclude(clazz)) {
boolean removeFlag = false;
if (null == clazz) {
removeFlag = true;
} else if (isSelf(clazz)) {
filteredClasses.add(new Pair<Class<?>, String>(clazz, "class loaded by arthas itself"));
removeFlag = true;
} else if (isUnsafeClass(clazz)) {
filteredClasses.add(new Pair<Class<?>, String>(clazz, "class loaded by Bootstrap Classloader, try to execute `options unsafe true`"));
removeFlag = true;
} else if (isExclude(clazz)) {
filteredClasses.add(new Pair<Class<?>, String>(clazz, "class is excluded"));
removeFlag = true;
} else {
Pair<Boolean, String> unsupportedResult = isUnsupportedClass(clazz);
if (unsupportedResult.getFirst()) {
filteredClasses.add(new Pair<Class<?>, String>(clazz, unsupportedResult.getSecond()));
removeFlag = true;
}
}
if (removeFlag) {
it.remove();
}
}
return filteredClasses;
}
private boolean isExclude(Class<?> clazz) {
@ -341,7 +364,7 @@ public class Enhancer implements ClassFileTransformer {
* Arthas
*/
private static boolean isSelf(Class<?> clazz) {
return null != clazz && isEquals(clazz.getClassLoader(), Enhancer.class.getClassLoader());
return null != clazz && isEquals(clazz.getClassLoader(), selfClassLoader);
}
/**
@ -354,9 +377,31 @@ public class Enhancer implements ClassFileTransformer {
/**
*
*/
private static boolean isUnsupportedClass(Class<?> clazz) {
return clazz.isArray() || (clazz.isInterface() && !GlobalOptions.isSupportDefaultMethod) || clazz.isEnum()
|| clazz.equals(Class.class) || clazz.equals(Integer.class) || clazz.equals(Method.class) || ClassUtils.isLambdaClass(clazz);
private static Pair<Boolean, String> isUnsupportedClass(Class<?> clazz) {
if (ClassUtils.isLambdaClass(clazz)) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is lambda");
}
if (clazz.isInterface() && !GlobalOptions.isSupportDefaultMethod) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is interface");
}
if (clazz.equals(Integer.class)) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is java.lang.Integer");
}
if (clazz.equals(Class.class)) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is java.lang.Class");
}
if (clazz.equals(Method.class)) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is java.lang.Method");
}
if (clazz.isArray()) {
return new Pair<Boolean, String>(Boolean.TRUE, "class is array");
}
return new Pair<Boolean, String>(Boolean.FALSE, "");
}
/**
@ -378,7 +423,12 @@ public class Enhancer implements ClassFileTransformer {
: SearchUtils.searchSubClass(inst, SearchUtils.searchClass(inst, classNameMatcher));
// 过滤掉无法被增强的类
filter(matchingClasses);
List<Pair<Class<?>, String>> filtedList = filter(matchingClasses);
if (!filtedList.isEmpty()) {
for (Pair<Class<?>, String> filted : filtedList) {
logger.info("ignore class: {}, reson: {}", filted.getFirst().getName(), filted.getSecond());
}
}
logger.info("enhance matched classes: {}", matchingClasses);

@ -39,6 +39,7 @@ import com.taobao.arthas.core.command.monitor200.DashboardCommand;
import com.taobao.arthas.core.command.monitor200.HeapDumpCommand;
import com.taobao.arthas.core.command.monitor200.JvmCommand;
import com.taobao.arthas.core.command.monitor200.MBeanCommand;
import com.taobao.arthas.core.command.monitor200.MemoryCommand;
import com.taobao.arthas.core.command.monitor200.MonitorCommand;
import com.taobao.arthas.core.command.monitor200.PerfCounterCommand;
import com.taobao.arthas.core.command.monitor200.ProfilerCommand;
@ -87,6 +88,7 @@ public class BuiltinCommandPack implements CommandResolver {
commandClassList.add(WatchCommand.class);
commandClassList.add(TimeTunnelCommand.class);
commandClassList.add(JvmCommand.class);
commandClassList.add(MemoryCommand.class);
commandClassList.add(PerfCounterCommand.class);
// commandClassList.add(GroovyScriptCommand.class);
commandClassList.add(OgnlCommand.class);

@ -42,8 +42,8 @@ import io.netty.util.CharsetUtil;
public class Base64Command extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(Base64Command.class);
private String file;
private Integer sizeLimit = 128 * 1024;
private int maxSizeLimit = 8 * 1024 * 1024;
private int sizeLimit = 128 * 1024;
private static final int MAX_SIZE_LIMIT = 8 * 1024 * 1024;
private boolean decode;
@ -87,8 +87,13 @@ public class Base64Command extends AnnotatedCommand {
}
// 确认输入
if (file == null && this.input != null) {
file = input;
if (file == null) {
if (this.input != null) {
file = input;
} else {
process.end(-1, ": No file, nor input");
return;
}
}
File f = new File(file);
@ -145,8 +150,8 @@ public class Base64Command extends AnnotatedCommand {
return false;
}
if (sizeLimit > maxSizeLimit) {
process.end(-1, "sizeLimit cannot be large than: " + maxSizeLimit);
if (sizeLimit > MAX_SIZE_LIMIT) {
process.end(-1, "sizeLimit cannot be large than: " + MAX_SIZE_LIMIT);
return false;
}

@ -2,7 +2,6 @@ package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.EchoModel;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.middleware.cli.annotations.Argument;

@ -49,7 +49,7 @@ public class HistoryCommand extends AnnotatedCommand {
Session session = process.session();
//TODO 修改term history实现方式统一使用HistoryManager
Object termObject = session.get(Session.TTY);
if (termObject != null && termObject instanceof TermImpl) {
if (termObject instanceof TermImpl) {
TermImpl term = (TermImpl) termObject;
Readline readline = term.getReadline();
List<int[]> history = readline.getHistory();

@ -55,7 +55,7 @@ public class KeymapCommand extends AnnotatedCommand {
continue;
}
String[] strings = line.split(":");
if (strings != null && strings.length == 2) {
if (strings.length == 2) {
table.row(strings[0], translate(strings[0]), strings[1]);
} else {
table.row(line);

@ -2,7 +2,7 @@ package com.taobao.arthas.core.command.basic1000;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.alibaba.arthas.deps.org.slf4j.Logger;
@ -77,7 +77,7 @@ public class VMOptionCommand extends AnnotatedCommand {
process.end(-1, "In order to change the system properties, you must specify the property value.");
return;
} else {
process.appendResult(new VMOptionModel(Arrays.asList(option)));
process.appendResult(new VMOptionModel(Collections.singletonList(option)));
}
} else {
VMOption vmOption = hotSpotDiagnosticMXBean.getVMOption(name);

@ -44,7 +44,7 @@ public class OgnlExpress implements Express {
@Override
public boolean is(String express) throws ExpressException {
final Object ret = get(express);
return null != ret && ret instanceof Boolean && (Boolean) ret;
return ret instanceof Boolean && (Boolean) ret;
}
@Override

@ -24,6 +24,8 @@ import com.taobao.middleware.cli.annotations.Summary;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -51,6 +53,7 @@ import java.util.TreeSet;
" classloader -a\n" +
" classloader -a -c 327a647b\n" +
" classloader -c 659e0bfd --load demo.MathGame\n" +
" classloader -u # url statistics\n" +
Constants.WIKI + Constants.WIKI_HOME + "classloader")
public class ClassLoaderCommand extends AnnotatedCommand {
@ -63,6 +66,8 @@ public class ClassLoaderCommand extends AnnotatedCommand {
private boolean includeReflectionClassLoader = true;
private boolean listClassLoader = false;
private boolean urlStat = false;
private String loadClass = null;
private volatile boolean isInterrupted = false;
@ -115,6 +120,12 @@ public class ClassLoaderCommand extends AnnotatedCommand {
this.loadClass = className;
}
@Option(shortName = "u", longName = "url-stat", flag = true)
@Description("Display classloader url statistics")
public void setUrlStat(boolean urlStat) {
this.urlStat = urlStat;
}
@Override
public void process(CommandProcess process) {
// ctrl-C support
@ -123,6 +134,15 @@ public class ClassLoaderCommand extends AnnotatedCommand {
boolean classLoaderSpecified = false;
Instrumentation inst = process.session().getInstrumentation();
if (urlStat) {
Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats = this.urlStats(inst);
ClassLoaderModel model = new ClassLoaderModel();
model.setUrlStats(urlStats);
process.appendResult(model);
process.end();
return;
}
if (hashCode != null || classLoaderClass != null) {
classLoaderSpecified = true;
@ -136,7 +156,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
break;
}
}
} else if (targetClassLoader == null && classLoaderClass != null) {
} else if (classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
targetClassLoader = matchedClassLoaders.get(0);
@ -396,6 +416,42 @@ public class ClassLoaderCommand extends AnnotatedCommand {
}
return urlStrs;
}
private Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats(Instrumentation inst) {
Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats = new HashMap<ClassLoaderVO, ClassLoaderUrlStat>();
Map<ClassLoader, Set<String>> usedUrlsMap = new HashMap<ClassLoader, Set<String>>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader != null) {
ProtectionDomain protectionDomain = clazz.getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
if (codeSource != null) {
URL location = codeSource.getLocation();
if (location != null) {
Set<String> urls = usedUrlsMap.get(classLoader);
if (urls == null) {
urls = new HashSet<String>();
usedUrlsMap.put(classLoader, urls);
}
urls.add(location.toString());
}
}
}
}
for (Entry<ClassLoader, Set<String>> entry : usedUrlsMap.entrySet()) {
ClassLoader loader = entry.getKey();
Set<String> usedUrls = entry.getValue();
List<String> allUrls = getClassLoaderUrls(loader);
List<String> unusedUrls = new ArrayList<String>();
for (String url : allUrls) {
if (!usedUrls.contains(url)) {
unusedUrls.add(url);
}
}
urlStats.put(ClassUtils.createClassLoaderVO(loader), new ClassLoaderUrlStat(usedUrls, unusedUrls));
}
return urlStats;
}
// 以树状列出ClassLoader的继承结构
private static List<ClassLoaderVO> processClassLoaderTree(List<ClassLoaderVO> classLoaders) {
@ -583,6 +639,36 @@ public class ClassLoaderCommand extends AnnotatedCommand {
}
}
public static class ClassLoaderUrlStat {
private Collection<String> usedUrls;
private Collection<String> unUsedUrls;
public ClassLoaderUrlStat() {
}
public ClassLoaderUrlStat(Collection<String> usedUrls, Collection<String> unUsedUrls) {
super();
this.usedUrls = usedUrls;
this.unUsedUrls = unUsedUrls;
}
public Collection<String> getUsedUrls() {
return usedUrls;
}
public void setUsedUrls(Collection<String> usedUrls) {
this.usedUrls = usedUrls;
}
public Collection<String> getUnUsedUrls() {
return unUsedUrls;
}
public void setUnUsedUrls(Collection<String> unUsedUrls) {
this.unUsedUrls = unUsedUrls;
}
}
public static class ClassLoaderStat {
private int loadedCount;
private int numberOfInstance;
@ -627,7 +713,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
}
}
private class ClassLoaderInterruptHandler implements Handler<Void> {
private static class ClassLoaderInterruptHandler implements Handler<Void> {
private ClassLoaderCommand command;

@ -92,7 +92,7 @@ public class DumpClassCommand extends AnnotatedCommand {
}
@Option(shortName = "l", longName = "limit")
@Description("The limit of dump classes size, default value is 5")
@Description("The limit of dump classes size, default value is 50")
@DefaultValue("50")
public void setLimit(int limit) {
this.limit = limit;

@ -20,7 +20,6 @@ import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.FileUtils;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;

@ -31,7 +31,7 @@ import java.util.List;
@Name("ognl")
@Summary("Execute ognl expression.")
@Description(Constants.EXAMPLE
+ " ognl '@java.lang.System@out.println(\"hello\")' \n"
+ " ognl '@java.lang.System@out.println(\"hello \\u4e2d\\u6587\")' \n"
+ " ognl -x 2 '@Singleton@getInstance()' \n"
+ " ognl '@Demo@staticFiled' \n"
+ " ognl '#value1=@System@getProperty(\"java.home\"), #value2=@System@getProperty(\"java.runtime.name\"), {#value1, #value2}'\n"

@ -124,7 +124,7 @@ public class RetransformCommand extends AnnotatedCommand {
}
@Option(longName = "limit")
@Description("The limit of dump classes size, default value is 5")
@Description("The limit of dump classes size, default value is 50")
@DefaultValue("50")
public void setLimit(int limit) {
this.limit = limit;

@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.model;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderUrlStat;
import java.util.List;
import java.util.Map;
@ -24,6 +25,9 @@ public class ClassLoaderModel extends ResultModel {
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
//urls stat
private Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats;
public ClassLoaderModel() {
}
@ -112,4 +116,13 @@ public class ClassLoaderModel extends ResultModel {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
public Map<ClassLoaderVO, ClassLoaderUrlStat> getUrlStats() {
return urlStats;
}
public void setUrlStats(Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats) {
this.urlStats = urlStats;
}
}

@ -1,7 +1,6 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**

@ -0,0 +1,25 @@
package com.taobao.arthas.core.command.model;
import java.util.List;
import java.util.Map;
/**
* Model of 'memory' command
* @author hengyunabc 2022-03-01
*/
public class MemoryModel extends ResultModel {
private Map<String, List<MemoryEntryVO>> memoryInfo;
@Override
public String getType() {
return "memory";
}
public Map<String, List<MemoryEntryVO>> getMemoryInfo() {
return memoryInfo;
}
public void setMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
this.memoryInfo = memoryInfo;
}
}

@ -5,7 +5,6 @@ import java.util.Collection;
import java.util.List;
import com.taobao.arthas.core.command.klass100.RetransformCommand.RetransformEntry;
import com.taobao.arthas.core.util.ClassUtils;
/**
*

@ -1,5 +1,13 @@
package com.taobao.arthas.core.command.monitor200;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
@ -7,7 +15,6 @@ import com.alibaba.fastjson.JSONObject;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.DashboardModel;
import com.taobao.arthas.core.command.model.GcInfoVO;
import com.taobao.arthas.core.command.model.MemoryEntryVO;
import com.taobao.arthas.core.command.model.RuntimeInfoVO;
import com.taobao.arthas.core.command.model.ThreadVO;
import com.taobao.arthas.core.command.model.TomcatInfoVO;
@ -18,6 +25,7 @@ import com.taobao.arthas.core.shell.handlers.shell.QExitHandler;
import com.taobao.arthas.core.shell.session.Session;
import com.taobao.arthas.core.util.NetUtils;
import com.taobao.arthas.core.util.NetUtils.Response;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.util.ThreadUtil;
import com.taobao.arthas.core.util.metrics.SumRateCounter;
import com.taobao.middleware.cli.annotations.Description;
@ -25,24 +33,6 @@ import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Option;
import com.taobao.middleware.cli.annotations.Summary;
import java.lang.management.BufferPoolMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_BUFFER_POOL;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_HEAP;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_NON_HEAP;
/**
* @author hengyunabc 20151119 11:57:21
*/
@ -66,7 +56,7 @@ public class DashboardCommand extends AnnotatedCommand {
private long interval = 5000;
private volatile long count = 0;
private final AtomicLong count = new AtomicLong(0);
private volatile Timer timer;
@Option(shortName = "n", longName = "number-of-execution")
@ -142,62 +132,6 @@ public class DashboardCommand extends AnnotatedCommand {
return interval;
}
private static String beautifyName(String name) {
return name.replace(' ', '_').toLowerCase();
}
private static void addMemoryInfo(DashboardModel dashboardModel) {
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
Map<String, List<MemoryEntryVO>> memoryInfoMap = new LinkedHashMap<String, List<MemoryEntryVO>>();
dashboardModel.setMemoryInfo(memoryInfoMap);
//heap
MemoryUsage heapMemoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
List<MemoryEntryVO> heapMemEntries = new ArrayList<MemoryEntryVO>();
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, TYPE_HEAP, heapMemoryUsage));
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
if (MemoryType.HEAP.equals(poolMXBean.getType())) {
MemoryUsage usage = poolMXBean.getUsage();
String poolName = beautifyName(poolMXBean.getName());
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, poolName, usage));
}
}
memoryInfoMap.put(TYPE_HEAP, heapMemEntries);
//non-heap
MemoryUsage nonHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
List<MemoryEntryVO> nonheapMemEntries = new ArrayList<MemoryEntryVO>();
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, TYPE_NON_HEAP, nonHeapMemoryUsage));
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
if (MemoryType.NON_HEAP.equals(poolMXBean.getType())) {
MemoryUsage usage = poolMXBean.getUsage();
String poolName = beautifyName(poolMXBean.getName());
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, poolName, usage));
}
}
memoryInfoMap.put(TYPE_NON_HEAP, nonheapMemEntries);
addBufferPoolMemoryInfo(memoryInfoMap);
}
private static void addBufferPoolMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfoMap) {
try {
List<MemoryEntryVO> bufferPoolMemEntries = new ArrayList<MemoryEntryVO>();
@SuppressWarnings("rawtypes")
Class bufferPoolMXBeanClass = Class.forName("java.lang.management.BufferPoolMXBean");
@SuppressWarnings("unchecked")
List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(bufferPoolMXBeanClass);
for (BufferPoolMXBean mbean : bufferPoolMXBeans) {
long used = mbean.getMemoryUsed();
long total = mbean.getTotalCapacity();
bufferPoolMemEntries.add(new MemoryEntryVO(TYPE_BUFFER_POOL, mbean.getName(), used, total, Long.MIN_VALUE));
}
memoryInfoMap.put(TYPE_BUFFER_POOL, bufferPoolMemEntries);
} catch (ClassNotFoundException e) {
// ignore
}
}
private static void addRuntimeInfo(DashboardModel dashboardModel) {
RuntimeInfoVO runtimeInfo = new RuntimeInfoVO();
runtimeInfo.setOsName(System.getProperty("os.name"));
@ -207,14 +141,10 @@ public class DashboardCommand extends AnnotatedCommand {
runtimeInfo.setSystemLoadAverage(ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage());
runtimeInfo.setProcessors(Runtime.getRuntime().availableProcessors());
runtimeInfo.setUptime(ManagementFactory.getRuntimeMXBean().getUptime() / 1000);
runtimeInfo.setTimestamp(new Date().getTime());
runtimeInfo.setTimestamp(System.currentTimeMillis());
dashboardModel.setRuntimeInfo(runtimeInfo);
}
private static MemoryEntryVO createMemoryEntryVO(String type, String name, MemoryUsage memoryUsage) {
return new MemoryEntryVO(type, name, memoryUsage.getUsed(), memoryUsage.getCommitted(), memoryUsage.getMax());
}
private static void addGcInfo(DashboardModel dashboardModel) {
List<GcInfoVO> gcInfos = new ArrayList<GcInfoVO>();
dashboardModel.setGcInfos(gcInfos);
@ -222,7 +152,7 @@ public class DashboardCommand extends AnnotatedCommand {
List<GarbageCollectorMXBean> garbageCollectorMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcMXBean : garbageCollectorMxBeans) {
String name = gcMXBean.getName();
gcInfos.add(new GcInfoVO(beautifyName(name), gcMXBean.getCollectionCount(), gcMXBean.getCollectionTime()));
gcInfos.add(new GcInfoVO(StringUtils.beautifyName(name), gcMXBean.getCollectionCount(), gcMXBean.getCollectionTime()));
}
}
@ -256,8 +186,8 @@ public class DashboardCommand extends AnnotatedCommand {
double qps = tomcatRequestCounter.rate();
double rt = processingTime / (double) requestCount;
double errorRate = tomcatErrorCounter.rate();
long receivedBytesRate = new Double(tomcatReceivedBytesCounter.rate()).longValue();
long sentBytesRate = new Double(tomcatSentBytesCounter.rate()).longValue();
long receivedBytesRate = Double.valueOf(tomcatReceivedBytesCounter.rate()).longValue();
long sentBytesRate = Double.valueOf(tomcatSentBytesCounter.rate()).longValue();
TomcatInfoVO.ConnectorStats connectorStat = new TomcatInfoVO.ConnectorStats();
connectorStat.setName(connectorName);
@ -297,7 +227,7 @@ public class DashboardCommand extends AnnotatedCommand {
@Override
public void run() {
try {
if (count >= getNumOfExecutions()) {
if (count.get() >= getNumOfExecutions()) {
// stop the timer
timer.cancel();
timer.purge();
@ -312,7 +242,7 @@ public class DashboardCommand extends AnnotatedCommand {
dashboardModel.setThreads(threadSampler.sample(threads));
//memory
addMemoryInfo(dashboardModel);
dashboardModel.setMemoryInfo(MemoryCommand.memoryInfo());
//gc
addGcInfo(dashboardModel);
@ -329,7 +259,7 @@ public class DashboardCommand extends AnnotatedCommand {
process.appendResult(dashboardModel);
count++;
count.getAndIncrement();
process.times().incrementAndGet();
} catch (Throwable e) {
String msg = "process dashboard failed: " + e.getMessage();

@ -20,17 +20,11 @@ import com.taobao.arthas.core.shell.handlers.shell.QExitHandler;
import com.taobao.arthas.core.shell.session.Session;
import com.taobao.arthas.core.util.Constants;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.arthas.core.util.matcher.Matcher;
import com.taobao.arthas.core.view.Ansi;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Option;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.ui.LabelElement;
import com.taobao.text.util.RenderUtil;
/**
* @author beiwei30 on 29/11/2016.
@ -189,8 +183,9 @@ public abstract class EnhancerCommand extends AnnotatedCommand {
+ "1. Execute `" + smCommand + "` to make sure the method you are tracing actually exists (it might be in your parent class).\n"
+ "2. Execute `" + optionsCommand + "`, if you want to enhance the classes under the `" + javaPackage + "` package.\n"
+ "3. Execute `" + resetCommand + "` and try again, your method body might be too large.\n"
+ "4. Check arthas log: " + logStr + "\n"
+ "5. Visit " + issueStr + " for more details.";
+ "4. Match the constructor, use `<init>`, for example: `watch demo.MathGame <init>`\n"
+ "5. Check arthas log: " + logStr + "\n"
+ "6. Visit " + issueStr + " for more details.";
process.end(-1, msg);
return;
}

@ -349,7 +349,7 @@ public class MBeanCommand extends AnnotatedCommand {
}
public class MBeanInterruptHandler extends CommandInterruptHandler {
public static class MBeanInterruptHandler extends CommandInterruptHandler {
private volatile Timer timer;
@ -417,7 +417,7 @@ public class MBeanCommand extends AnnotatedCommand {
logger.error("read mbean attribute failed: objectName={}, attributeName={}", objectName, attributeName, e);
String errorStr;
Throwable cause = e.getCause();
if (cause != null && cause instanceof UnsupportedOperationException) {
if (cause instanceof UnsupportedOperationException) {
errorStr = "Unsupported";
} else {
errorStr = "Failure";

@ -0,0 +1,112 @@
package com.taobao.arthas.core.command.monitor200;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_BUFFER_POOL;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_HEAP;
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_NON_HEAP;
import java.lang.management.BufferPoolMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.MemoryEntryVO;
import com.taobao.arthas.core.command.model.MemoryModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author hengyunabc 2022-03-01
*/
@Name("memory")
@Summary("Display jvm memory info.")
@Description(Constants.EXAMPLE + " memory\n" + Constants.WIKI + Constants.WIKI_HOME + "memory")
public class MemoryCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
MemoryModel result = new MemoryModel();
result.setMemoryInfo(memoryInfo());
process.appendResult(result);
process.end();
}
static Map<String, List<MemoryEntryVO>> memoryInfo() {
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
Map<String, List<MemoryEntryVO>> memoryInfoMap = new LinkedHashMap<String, List<MemoryEntryVO>>();
// heap
MemoryUsage heapMemoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
List<MemoryEntryVO> heapMemEntries = new ArrayList<MemoryEntryVO>();
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, TYPE_HEAP, heapMemoryUsage));
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
if (MemoryType.HEAP.equals(poolMXBean.getType())) {
MemoryUsage usage = getUsage(poolMXBean);
if (usage != null) {
String poolName = StringUtils.beautifyName(poolMXBean.getName());
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, poolName, usage));
}
}
}
memoryInfoMap.put(TYPE_HEAP, heapMemEntries);
// non-heap
MemoryUsage nonHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
List<MemoryEntryVO> nonheapMemEntries = new ArrayList<MemoryEntryVO>();
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, TYPE_NON_HEAP, nonHeapMemoryUsage));
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
if (MemoryType.NON_HEAP.equals(poolMXBean.getType())) {
MemoryUsage usage = getUsage(poolMXBean);
if (usage != null) {
String poolName = StringUtils.beautifyName(poolMXBean.getName());
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, poolName, usage));
}
}
}
memoryInfoMap.put(TYPE_NON_HEAP, nonheapMemEntries);
addBufferPoolMemoryInfo(memoryInfoMap);
return memoryInfoMap;
}
private static MemoryUsage getUsage(MemoryPoolMXBean memoryPoolMXBean) {
try {
return memoryPoolMXBean.getUsage();
} catch (InternalError e) {
// Defensive for potential InternalError with some specific JVM options. Based on its Javadoc,
// MemoryPoolMXBean.getUsage() should return null, not throwing InternalError, so it seems to be a JVM bug.
return null;
}
}
private static void addBufferPoolMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfoMap) {
try {
List<MemoryEntryVO> bufferPoolMemEntries = new ArrayList<MemoryEntryVO>();
@SuppressWarnings("rawtypes")
Class bufferPoolMXBeanClass = Class.forName("java.lang.management.BufferPoolMXBean");
@SuppressWarnings("unchecked")
List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(bufferPoolMXBeanClass);
for (BufferPoolMXBean mbean : bufferPoolMXBeans) {
long used = mbean.getMemoryUsed();
long total = mbean.getTotalCapacity();
bufferPoolMemEntries
.add(new MemoryEntryVO(TYPE_BUFFER_POOL, mbean.getName(), used, total, Long.MIN_VALUE));
}
memoryInfoMap.put(TYPE_BUFFER_POOL, bufferPoolMemEntries);
} catch (ClassNotFoundException e) {
// ignore
}
}
private static MemoryEntryVO createMemoryEntryVO(String type, String name, MemoryUsage memoryUsage) {
return new MemoryEntryVO(type, name, memoryUsage.getUsed(), memoryUsage.getCommitted(), memoryUsage.getMax());
}
}

@ -94,7 +94,7 @@ class MonitorAdviceListener extends AdviceListenerAdapter {
if (timer == null) {
timer = new Timer("Timer-for-arthas-monitor-" + process.session().getSessionId(), true);
timer.scheduleAtFixedRate(new MonitorTimer(monitorData, process, command.getNumberOfLimit()),
0, command.getCycle() * 1000);
0, command.getCycle() * 1000L);
}
}
@ -256,8 +256,7 @@ class MonitorAdviceListener extends AdviceListenerAdapter {
@Override
public boolean equals(Object obj) {
if (null == obj
|| !(obj instanceof Key)) {
if (!(obj instanceof Key)) {
return false;
}
Key okey = (Key) obj;

@ -51,7 +51,7 @@ import one.profiler.Counter;
+ " profiler list # list all supported events\n"
+ " profiler actions # list all supported actions\n"
+ " profiler start --event alloc\n"
+ " profiler stop --format svg # output file format, support svg,html,jfr\n"
+ " profiler stop --format html # output file format, support html,jfr\n"
+ " profiler stop --file /tmp/result.html\n"
+ " profiler stop --threads \n"
+ " profiler start --include 'java/*' --include 'demo/*' --exclude '*Unsafe.park*'\n"
@ -62,7 +62,7 @@ import one.profiler.Counter;
+ " profiler dumpCollapsed # Dump profile in 'collapsed stacktraces' format\n"
+ " profiler dumpTraces # Dump collected stack traces\n"
+ " profiler execute 'start,framebuf=5000000' # Execute an agent-compatible profiling command\n"
+ " profiler execute 'stop,file=/tmp/result.svg' # Execute an agent-compatible profiling command\n"
+ " profiler execute 'stop,file=/tmp/result.html' # Execute an agent-compatible profiling command\n"
+ Constants.WIKI + Constants.WIKI_HOME + "profiler")
//@formatter:on
public class ProfilerCommand extends AnnotatedCommand {
@ -75,7 +75,7 @@ public class ProfilerCommand extends AnnotatedCommand {
private String file;
/**
* output file format, default value is svg.
* output file format, default value is html.
*/
private String format;
@ -125,14 +125,13 @@ public class ProfilerCommand extends AnnotatedCommand {
static {
String profierSoPath = null;
if (OSUtils.isMac()) {
profierSoPath = "async-profiler/libasyncProfiler-mac-x64.so";
// FAT_BINARY support both x86_64/arm64
profierSoPath = "async-profiler/libasyncProfiler-mac.so";
}
if (OSUtils.isLinux()) {
profierSoPath = "async-profiler/libasyncProfiler-linux-x64.so";
if (OSUtils.isArm32()) {
profierSoPath = "async-profiler/libasyncProfiler-linux-arm.so";
} else if (OSUtils.isArm64()) {
profierSoPath = "async-profiler/libasyncProfiler-linux-aarch64.so";
if (OSUtils.isArm64()) {
profierSoPath = "async-profiler/libasyncProfiler-linux-arm64.so";
}
}
@ -186,8 +185,8 @@ public class ProfilerCommand extends AnnotatedCommand {
}
@Option(longName = "format")
@Description("dump output file format(svg, html, jfr), default valut is svg")
@DefaultValue("svg")
@Description("dump output file format(html, jfr), default valut is html")
@DefaultValue("html")
public void setFormat(String format) {
this.format = format;
}
@ -253,7 +252,7 @@ public class ProfilerCommand extends AnnotatedCommand {
try {
File tmpLibFile = File.createTempFile(VmTool.JNI_LIBRARY_NAME, null);
tmpLibOutputStream = new FileOutputStream(tmpLibFile);
libInputStream = new FileInputStream(new File(libPath));
libInputStream = new FileInputStream(libPath);
IOUtils.copy(libInputStream, tmpLibOutputStream);
libPath = tmpLibFile.getAbsolutePath();
@ -277,7 +276,7 @@ public class ProfilerCommand extends AnnotatedCommand {
}
/**
* https://github.com/jvm-profiling-tools/async-profiler/blob/v1.8.1/src/arguments.cpp#L50
* https://github.com/jvm-profiling-tools/async-profiler/blob/v2.5/src/arguments.cpp#L50
*
*/
public enum ProfilerAction {
@ -503,11 +502,9 @@ public class ProfilerCommand extends AnnotatedCommand {
}
String lines[] = execute.split("\\r?\\n");
if (lines != null) {
for (String line : lines) {
if (line.startsWith(" ")) {
result.add(line.trim());
}
for (String line : lines) {
if (line.startsWith(" ")) {
result.add(line.trim());
}
}
return result;
@ -535,7 +532,7 @@ public class ProfilerCommand extends AnnotatedCommand {
CompletionUtils.complete(completion, events());
return;
} else if (token_2.equals("-f") || token_2.equals("--format")) {
CompletionUtils.complete(completion, Arrays.asList("svg", "html", "jfr"));
CompletionUtils.complete(completion, Arrays.asList("html", "jfr"));
return;
}
}

@ -118,7 +118,7 @@ public class ThreadSampler {
// Compute cpu usage
final HashMap<ThreadVO, Double> cpuUsages = new HashMap<ThreadVO, Double>(threads.size());
for (ThreadVO thread : threads) {
double cpu = sampleIntervalNanos == 0 ? 0 : (deltas.get(thread) * 10000 / sampleIntervalNanos / 100.0);
double cpu = sampleIntervalNanos == 0 ? 0 : (Math.rint(deltas.get(thread) * 10000.0 / sampleIntervalNanos) / 100.0);
cpuUsages.put(thread, cpu);
}

@ -12,7 +12,7 @@ import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.ThreadLocalWatch;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
/**
@ -90,7 +90,7 @@ public class TimeTunnelAdviceListener extends AdviceListenerAdapter {
TimeFragmentVO timeFragmentVO = TimeTunnelCommand.createTimeFragmentVO(index, timeTunnel);
TimeTunnelModel timeTunnelModel = new TimeTunnelModel()
.setTimeFragmentList(Arrays.asList(timeFragmentVO))
.setTimeFragmentList(Collections.singletonList(timeFragmentVO))
.setFirst(isFirst);
process.appendResult(timeTunnelModel);

@ -267,7 +267,7 @@ public class VmToolCommand extends AnnotatedCommand {
try {
File tmpLibFile = File.createTempFile(VmTool.JNI_LIBRARY_NAME, null);
tmpLibOutputStream = new FileOutputStream(tmpLibFile);
libInputStream = new FileInputStream(new File(libPath));
libInputStream = new FileInputStream(libPath);
IOUtils.copy(libInputStream, tmpLibOutputStream);
libPath = tmpLibFile.getAbsolutePath();

@ -1,6 +1,7 @@
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderUrlStat;
import com.taobao.arthas.core.command.model.ClassDetailVO;
import com.taobao.arthas.core.command.model.ClassLoaderModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
@ -14,6 +15,7 @@ import com.taobao.text.util.RenderUtil;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @author gongdewei 2020/4/21
@ -46,8 +48,39 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
if (result.getClassLoaderStats() != null){
drawClassLoaderStats(process, result.getClassLoaderStats());
}
if (result.getUrlStats() != null) {
drawUrlStats(process, result.getUrlStats());
}
}
private void drawUrlStats(CommandProcess process, Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats) {
for (Entry<ClassLoaderVO, ClassLoaderUrlStat> entry : urlStats.entrySet()) {
ClassLoaderVO classLoaderVO = entry.getKey();
ClassLoaderUrlStat urlStat = entry.getValue();
// 忽略 sun.reflect.DelegatingClassLoader 等动态ClassLoader
if (urlStat.getUsedUrls().isEmpty() && urlStat.getUnUsedUrls().isEmpty()) {
continue;
}
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.row(new LabelElement(classLoaderVO.getName() + ", hash:" + classLoaderVO.getHash())
.style(Decoration.bold.bold()));
Collection<String> usedUrls = urlStat.getUsedUrls();
table.row(new LabelElement("Used URLs:").style(Decoration.bold.bold()));
for (String url : usedUrls) {
table.row(url);
}
Collection<String> UnnsedUrls = urlStat.getUnUsedUrls();
table.row(new LabelElement("Unused URLs:").style(Decoration.bold.bold()));
for (String url : UnnsedUrls) {
table.row(url);
}
process.write(RenderUtil.render(table, process.width()))
.write("\n");
}
}
private void drawClassLoaderStats(CommandProcess process, Map<String, ClassLoaderStat> classLoaderStats) {
Element element = renderStat(classLoaderStats);
process.write(RenderUtil.render(element, process.width()))

@ -4,12 +4,10 @@ import com.taobao.arthas.core.command.model.*;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.Style;
import com.taobao.text.ui.RowElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.lang.management.MemoryUsage;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -74,46 +72,12 @@ public class DashboardView extends ResultView<DashboardModel> {
static String drawMemoryInfoAndGcInfo(Map<String, List<MemoryEntryVO>> memoryInfo, List<GcInfoVO> gcInfos, int width, int height) {
TableElement table = new TableElement(1, 1);
TableElement memoryInfoTable = drawMemoryInfo(memoryInfo);
TableElement memoryInfoTable = MemoryView.drawMemoryInfo(memoryInfo);
TableElement gcInfoTable = drawGcInfo(gcInfos);
table.row(memoryInfoTable, gcInfoTable);
return RenderUtil.render(table, width, height);
}
private static TableElement drawMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
TableElement table = new TableElement(3, 1, 1, 1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Memory",
"used", "total", "max", "usage"));
List<MemoryEntryVO> heapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_HEAP);
//heap memory
for (MemoryEntryVO memoryEntryVO : heapMemoryEntries) {
if (MemoryEntryVO.TYPE_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//non-heap memory
List<MemoryEntryVO> nonheapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_NON_HEAP);
for (MemoryEntryVO memoryEntryVO : nonheapMemoryEntries) {
if (MemoryEntryVO.TYPE_NON_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//buffer-pool
List<MemoryEntryVO> bufferPoolMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_BUFFER_POOL);
if (bufferPoolMemoryEntries != null) {
for (MemoryEntryVO memoryEntryVO : bufferPoolMemoryEntries) {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
return table;
}
private static int getMemoryInfoHeight(Map<String, List<MemoryEntryVO>> memoryInfo) {
int height = 1;
for (List<MemoryEntryVO> memoryEntryVOS : memoryInfo.values()) {
@ -203,64 +167,4 @@ public class DashboardView extends ResultView<DashboardModel> {
}
return table;
}
static class MemoryEntry {
String name;
long used;
long total;
long max;
int unit;
String unitStr;
public MemoryEntry(String name, long used, long total, long max) {
this.name = name;
this.used = used;
this.total = total;
this.max = max;
unitStr = "K";
unit = 1024;
if (used / 1024 / 1024 > 0) {
unitStr = "M";
unit = 1024 * 1024;
}
}
public MemoryEntry(String name, MemoryUsage usage) {
this(name, usage.getUsed(), usage.getCommitted(), usage.getMax());
}
public MemoryEntry(MemoryEntryVO memoryEntryVO) {
this(memoryEntryVO.getName(), memoryEntryVO.getUsed(), memoryEntryVO.getTotal(), memoryEntryVO.getMax());
}
private String format(long value) {
String valueStr = "-";
if (value == -1) {
return "-1";
}
if (value != Long.MIN_VALUE) {
valueStr = value / unit + unitStr;
}
return valueStr;
}
public void addTableRow(TableElement table) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.row(name, format(used), format(total), format(max), String.format("%.2f%%", usage));
}
public void addTableRow(TableElement table, Style.Composite style) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.add(new RowElement().style(style).add(name, format(used), format(total), format(max),
String.format("%.2f%%", usage)));
}
}
}

@ -3,7 +3,6 @@ package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.logger.LoggerHelper;
import com.taobao.arthas.core.command.model.LoggerModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;

@ -17,7 +17,6 @@ import java.util.Map;
import static com.taobao.text.ui.Element.label;
import static javax.management.MBeanOperationInfo.*;
import static javax.management.MBeanOperationInfo.UNKNOWN;
/**
* View of 'mbean' command

@ -0,0 +1,123 @@
package com.taobao.arthas.core.command.view;
import java.lang.management.MemoryUsage;
import java.util.List;
import java.util.Map;
import com.taobao.arthas.core.command.model.MemoryEntryVO;
import com.taobao.arthas.core.command.model.MemoryModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.Style;
import com.taobao.text.ui.RowElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
/**
* View of 'memory' command
*
* @author hengyunabc 2022-03-01
*/
public class MemoryView extends ResultView<MemoryModel> {
@Override
public void draw(CommandProcess process, MemoryModel result) {
TableElement table = drawMemoryInfo(result.getMemoryInfo());
process.write(RenderUtil.render(table, process.width()));
}
static TableElement drawMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
TableElement table = new TableElement(3, 1, 1, 1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Memory",
"used", "total", "max", "usage"));
List<MemoryEntryVO> heapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_HEAP);
//heap memory
for (MemoryEntryVO memoryEntryVO : heapMemoryEntries) {
if (MemoryEntryVO.TYPE_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//non-heap memory
List<MemoryEntryVO> nonheapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_NON_HEAP);
for (MemoryEntryVO memoryEntryVO : nonheapMemoryEntries) {
if (MemoryEntryVO.TYPE_NON_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//buffer-pool
List<MemoryEntryVO> bufferPoolMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_BUFFER_POOL);
if (bufferPoolMemoryEntries != null) {
for (MemoryEntryVO memoryEntryVO : bufferPoolMemoryEntries) {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
return table;
}
static class MemoryEntry {
String name;
long used;
long total;
long max;
int unit;
String unitStr;
public MemoryEntry(String name, long used, long total, long max) {
this.name = name;
this.used = used;
this.total = total;
this.max = max;
unitStr = "K";
unit = 1024;
if (used / 1024 / 1024 > 0) {
unitStr = "M";
unit = 1024 * 1024;
}
}
public MemoryEntry(String name, MemoryUsage usage) {
this(name, usage.getUsed(), usage.getCommitted(), usage.getMax());
}
public MemoryEntry(MemoryEntryVO memoryEntryVO) {
this(memoryEntryVO.getName(), memoryEntryVO.getUsed(), memoryEntryVO.getTotal(), memoryEntryVO.getMax());
}
private String format(long value) {
String valueStr = "-";
if (value == -1) {
return "-1";
}
if (value != Long.MIN_VALUE) {
valueStr = value / unit + unitStr;
}
return valueStr;
}
public void addTableRow(TableElement table) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.row(name, format(used), format(total), format(max), String.format("%.2f%%", usage));
}
public void addTableRow(TableElement table, Style.Composite style) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.add(new RowElement().style(style).add(name, format(used), format(total), format(max),
String.format("%.2f%%", usage)));
}
}
}

@ -67,6 +67,7 @@ public class ResultViewResolver {
//monitor2000
registerView(DashboardView.class);
registerView(JvmView.class);
registerView(MemoryView.class);
registerView(MBeanView.class);
registerView(PerfCounterView.class);
registerView(ThreadView.class);

@ -98,10 +98,10 @@ public class TraceView extends ResultView<TraceModel> {
//trace_id
if (threadNode.getTraceId() != null) {
sb.append(";trace_id="+threadNode.getTraceId());
sb.append(";trace_id=").append(threadNode.getTraceId());
}
if (threadNode.getRpcId() != null) {
sb.append(";rpc_id="+threadNode.getRpcId());
sb.append(";rpc_id=").append(threadNode.getRpcId());
}
} else if (node instanceof ThrowNode) {
ThrowNode throwNode = (ThrowNode) node;

@ -97,7 +97,7 @@ public class ViewRenderUtil {
affectVO.getListenerId()));
if (affectVO.getThrowable() != null) {
infoSB.append("\nEnhance error! exception: " + affectVO.getThrowable());
infoSB.append("\nEnhance error! exception: ").append(affectVO.getThrowable());
}
infoSB.append("\n");

@ -21,14 +21,13 @@ public class BinderUtils {
}
public static void inject(Environment environment, String parentPrefix, String prefix, Object instance) {
if (prefix == null) {
prefix = "";
}
Class<? extends Object> type = instance.getClass();
try {
Config annotation = type.getAnnotation(Config.class);
if (prefix == null) {
prefix = "";
}
if (annotation == null) {
prefix = parentPrefix + '.' + prefix;
} else {
@ -41,22 +40,19 @@ public class BinderUtils {
}
Method[] declaredMethods = type.getDeclaredMethods();
if (declaredMethods != null) {
// 获取到所有setter方法再提取出field。根据前缀从 properties里取出值再尝试用setter方法注入到对象里
for (Method method : declaredMethods) {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes != null && parameterTypes.length == 1 && methodName.startsWith("set")
&& methodName.length() > "set".length()) {
String field = getFieldNameFromSetterMethod(methodName);
String configKey = prefix + '.' + field;
if (environment.containsProperty(configKey)) {
Object reslovedValue = environment.getProperty(prefix + '.' + field, parameterTypes[0]);
if (reslovedValue != null) {
method.invoke(instance, new Object[] { reslovedValue });
}
// 获取到所有setter方法再提取出field。根据前缀从 properties里取出值再尝试用setter方法注入到对象里
for (Method method : declaredMethods) {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1 && methodName.startsWith("set") && methodName.length() > "set".length()) {
String field = getFieldNameFromSetterMethod(methodName);
String configKey = prefix + '.' + field;
if (environment.containsProperty(configKey)) {
Object reslovedValue = environment.getProperty(prefix + '.' + field, parameterTypes[0]);
if (reslovedValue != null) {
method.invoke(instance, new Object[] { reslovedValue });
}
}
}
@ -68,28 +64,26 @@ public class BinderUtils {
// process @NestedConfig
Field[] fields = type.getDeclaredFields();
if (fields != null) {
for (Field field : fields) {
NestedConfig nestedConfig = field.getAnnotation(NestedConfig.class);
if (nestedConfig != null) {
String prefixForField = field.getName();
if (parentPrefix != null && prefix.length() > 0) {
prefixForField = prefix + '.' + prefixForField;
}
field.setAccessible(true);
try {
Object fieldValue = field.get(instance);
if (fieldValue == null) {
fieldValue = field.getType().newInstance();
}
inject(environment, prefix, prefixForField, fieldValue);
for (Field field : fields) {
NestedConfig nestedConfig = field.getAnnotation(NestedConfig.class);
if (nestedConfig != null) {
String prefixForField = field.getName();
if (parentPrefix != null && prefix.length() > 0) {
prefixForField = prefix + '.' + prefixForField;
}
field.set(instance, fieldValue);
} catch (Exception e) {
throw new RuntimeException("process @NestedConfig error, field: " + field + ", prefix: "
+ prefix + ", instance: " + instance, e);
field.setAccessible(true);
try {
Object fieldValue = field.get(instance);
if (fieldValue == null) {
fieldValue = field.getType().newInstance();
}
inject(environment, prefix, prefixForField, fieldValue);
field.set(instance, fieldValue);
} catch (Exception e) {
throw new RuntimeException("process @NestedConfig error, field: " + field + ", prefix: "
+ prefix + ", instance: " + instance, e);
}
}
}

@ -135,7 +135,7 @@ public class SharingResultDistributorImpl implements SharingResultDistributor {
}
}
private class SharingResultConsumerImpl implements ResultConsumer {
private static class SharingResultConsumerImpl implements ResultConsumer {
private BlockingQueue<ResultModel> resultQueue = new ArrayBlockingQueue<ResultModel>(DistributorOptions.resultQueueSize);
private ReentrantLock queueLock = new ReentrantLock();
private InputStatusModel lastInputStatus;

@ -16,6 +16,7 @@
package com.taobao.arthas.core.env;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
@ -111,9 +112,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
@Override
public void setRequiredProperties(String... requiredProperties) {
for (String key : requiredProperties) {
this.requiredProperties.add(key);
}
this.requiredProperties.addAll(Arrays.asList(requiredProperties));
}
@Override

@ -8,6 +8,7 @@ import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Method;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -150,7 +151,7 @@ public class ArthasBootstrap {
outputPath.mkdirs();
// 3. init logger
loggerContext = LogUtil.initLooger(arthasEnvironment);
loggerContext = LogUtil.initLogger(arthasEnvironment);
// 4. 增强ClassLoader
enhanceClassLoader();
@ -179,6 +180,8 @@ public class ArthasBootstrap {
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteDateUseDateFormat.getMask();
// ignore getter error #1661
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.IgnoreErrorGetter.getMask();
// #2081
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNonStringKeyAsString.getMask();
}
private void initBeans() {
@ -262,16 +265,19 @@ public class ArthasBootstrap {
* https://github.com/alibaba/arthas/issues/986
* </pre>
*/
Map<String, String> copyMap = new HashMap<String, String>();
Map<String, Object> copyMap;
if (argsMap != null) {
copyMap.putAll(argsMap);
}
// 添加 arthas.home
if (!copyMap.containsKey(ARTHAS_HOME_PROPERTY)) {
copyMap = new HashMap<String, Object>(argsMap);
// 添加 arthas.home
if (!copyMap.containsKey(ARTHAS_HOME_PROPERTY)) {
copyMap.put(ARTHAS_HOME_PROPERTY, arthasHome());
}
} else {
copyMap = new HashMap<String, Object>(1);
copyMap.put(ARTHAS_HOME_PROPERTY, arthasHome());
}
MapPropertySource mapPropertySource = new MapPropertySource("args", (Map<String, Object>)(Object)copyMap);
MapPropertySource mapPropertySource = new MapPropertySource("args", copyMap);
arthasEnvironment.addFirst(mapPropertySource);
tryToLoadArthasProperties();
@ -322,25 +328,25 @@ public class ArthasBootstrap {
if (!location.endsWith(".properties")) {
location = new File(location, configName + ".properties").getAbsolutePath();
}
}
if (new File(location).exists()) {
Properties properties = FileUtils.readProperties(location);
boolean overrideAll = false;
if (arthasEnvironment.containsProperty(CONFIG_OVERRIDE_ALL)) {
overrideAll = arthasEnvironment.getRequiredProperty(CONFIG_OVERRIDE_ALL, boolean.class);
} else {
overrideAll = Boolean.parseBoolean(properties.getProperty(CONFIG_OVERRIDE_ALL, "false"));
}
if (new File(location).exists()) {
Properties properties = FileUtils.readProperties(location);
boolean overrideAll = false;
if (arthasEnvironment.containsProperty(CONFIG_OVERRIDE_ALL)) {
overrideAll = arthasEnvironment.getRequiredProperty(CONFIG_OVERRIDE_ALL, boolean.class);
} else {
overrideAll = Boolean.parseBoolean(properties.getProperty(CONFIG_OVERRIDE_ALL, "false"));
}
PropertySource<?> propertySource = new PropertiesPropertySource(location, properties);
if (overrideAll) {
arthasEnvironment.addFirst(propertySource);
} else {
arthasEnvironment.addLast(propertySource);
PropertySource<?> propertySource = new PropertiesPropertySource(location, properties);
if (overrideAll) {
arthasEnvironment.addFirst(propertySource);
} else {
arthasEnvironment.addLast(propertySource);
}
}
}
}
/**
@ -413,9 +419,7 @@ public class ArthasBootstrap {
if (configure.getDisabledCommands() != null) {
String[] strings = StringUtils.tokenizeToStringArray(configure.getDisabledCommands(), ",");
if (strings != null) {
for (String s : strings) {
disabledCommands.add(s);
}
disabledCommands.addAll(Arrays.asList(strings));
}
}
BuiltinCommandPack builtinCommands = new BuiltinCommandPack(disabledCommands);

@ -78,9 +78,8 @@ public abstract class ShellServer {
/**
* Start the shell service, this is an asynchronous start.
*/
@SuppressWarnings("unchecked")
public ShellServer listen() {
return listen(new NoOpHandler());
return listen(new NoOpHandler<Future<Void>>());
}
/**
@ -93,9 +92,8 @@ public abstract class ShellServer {
/**
* Close the shell server, this is an asynchronous close.
*/
@SuppressWarnings("unchecked")
public void close() {
close(new NoOpHandler());
close(new NoOpHandler<Future<Void>>());
}
/**

@ -121,12 +121,14 @@ public class CompletionUtils {
File[] listFiles = dir.listFiles();
ArrayList<String> names = new ArrayList<String>();
for (File child : listFiles) {
if (child.getName().startsWith(partName)) {
if (child.isDirectory()) {
names.add(child.getName() + "/");
} else {
names.add(child.getName());
if (listFiles != null) {
for (File child : listFiles) {
if (child.getName().startsWith(partName)) {
if (child.isDirectory()) {
names.add(child.getName() + "/");
} else {
names.add(child.getName());
}
}
}
}
@ -134,7 +136,7 @@ public class CompletionUtils {
if (names.size() == 1 && names.get(0).endsWith("/")) {
String name = names.get(0);
// 这个函数补全后不会有空格,并且只能传入要补全的内容
completion.complete(name.substring(tokenFileName.length(), name.length()), false);
completion.complete(name.substring(tokenFileName.length()), false);
return true;
}
@ -215,7 +217,7 @@ public class CompletionUtils {
}
Set<Class<?>> results = SearchUtils.searchClassOnly(completion.session().getInstrumentation(), className, 2);
if (results.isEmpty() || results.size() > 1) {
if (results.size() != 1) {
// no class found or multiple class found
completion.complete(Collections.<String>emptyList());
return true;
@ -312,7 +314,7 @@ public class CompletionUtils {
if (commonPrefix.length() == prefix.length()) {
completion.complete(candidates);
} else {
completion.complete(commonPrefix.substring(prefix.length(), commonPrefix.length()), false);
completion.complete(commonPrefix.substring(prefix.length()), false);
}
} else {

@ -120,7 +120,7 @@ public class GrepHandler extends StdoutHandler {
} else {
match = pattern.matcher(line).find();
}
if (invertMatch ? !match : match) {
if (invertMatch != match) {
matchCount++;
if (beforeLines > continueCount) {
int n = lastContinueLineNum == -1 ? (beforeLines >= lineNum ? 1 : lineNum - beforeLines)

@ -6,6 +6,7 @@ import com.taobao.middleware.cli.CommandLine;
import com.taobao.middleware.cli.Option;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author ralf0131 2017-02-23 23:28.
@ -17,14 +18,14 @@ public class WordCountHandler extends StdoutHandler implements StatisticsFunctio
private boolean lineMode;
private String result = null;
private volatile int total = 0;
private final AtomicInteger total = new AtomicInteger(0);
public static StdoutHandler inject(List<CliToken> tokens) {
List<String> args = StdoutHandler.parseArgs(tokens, NAME);
CommandLine commandLine = CLIs.create(NAME)
.addOption(new Option().setShortName("l").setFlag(true))
.parse(args);
Boolean lineMode = commandLine.isFlagEnabled("l");
boolean lineMode = commandLine.isFlagEnabled("l");
return new WordCountHandler(lineMode);
}
@ -39,7 +40,7 @@ public class WordCountHandler extends StdoutHandler implements StatisticsFunctio
result = "wc currently only support wc -l!\n";
} else {
if (input != null && !"".equals(input.trim())) {
total += input.split("\n").length;
total.getAndAdd(input.split("\n").length);
}
}
@ -52,6 +53,6 @@ public class WordCountHandler extends StdoutHandler implements StatisticsFunctio
return result;
}
return total + "\n";
return total.get() + "\n";
}
}

@ -7,12 +7,12 @@ import com.taobao.arthas.core.shell.future.Future;
/**
* @author beiwei30 on 22/11/2016.
*/
public class NoOpHandler implements Handler {
public class NoOpHandler<E> implements Handler<E> {
private static final Logger logger = LoggerFactory.getLogger(NoOpHandler.class);
@Override
public void handle(Object event) {
public void handle(E event) {
if (event instanceof Future && ((Future) event).failed()) {
logger.error("Error listening term server:", ((Future) event).cause());
}

@ -21,7 +21,7 @@ class BuiltinCommandResolver implements CommandResolver {
private Handler<CommandProcess> handler;
public BuiltinCommandResolver() {
this.handler = new NoOpHandler();
this.handler = new NoOpHandler<CommandProcess>();
}
@Override

@ -158,11 +158,9 @@ public class ShellImpl implements Shell {
}
private void setPrompt(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[arthas@");
stringBuilder.append(session.getPid());
stringBuilder.append("]$ ");
this.prompt = stringBuilder.toString();
this.prompt = "[arthas@" +
session.getPid() +
"]$ ";
}
public ShellImpl init() {
@ -229,7 +227,7 @@ public class ShellImpl implements Shell {
return currentForegroundJob;
}
private class ShellJobHandler implements JobListener {
private static class ShellJobHandler implements JobListener {
ShellImpl shell;
public ShellJobHandler(ShellImpl shell) {

@ -4,7 +4,6 @@ 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.distribution.ResultConsumer;
import com.taobao.arthas.core.distribution.ResultDistributor;
import com.taobao.arthas.core.distribution.SharingResultDistributor;
import com.taobao.arthas.core.shell.ShellServerOptions;
import com.taobao.arthas.core.shell.session.Session;
@ -71,21 +70,24 @@ public class SessionManagerImpl implements SessionManager {
}
@Override
public Session closeSession(String sessionId) {
Session session = sessions.remove(sessionId);
if (session != null) {
//interrupt foreground job
Job job = session.getForegroundJob();
if (job != null) {
job.interrupt();
}
// release ResultDistributor
ResultDistributor resultDistributor = session.getResultDistributor();
if (resultDistributor != null) {
resultDistributor.close();
}
public Session removeSession(String sessionId) {
Session session = sessions.get(sessionId);
if (session == null) {
return null;
}
return session;
//interrupt foreground job
Job job = session.getForegroundJob();
if (job != null) {
job.interrupt();
}
SharingResultDistributor resultDistributor = session.getResultDistributor();
if (resultDistributor != null) {
resultDistributor.close();
}
return sessions.remove(sessionId);
}
@Override
@ -103,13 +105,12 @@ public class SessionManagerImpl implements SessionManager {
ArrayList<Session> sessions = new ArrayList<Session>(this.sessions.values());
for (Session session : sessions) {
logger.info("Removing session before shutdown: {}, last access time: {}", session.getSessionId(), session.getLastAccessTime());
ResultDistributor resultDistributor = session.getResultDistributor();
SharingResultDistributor resultDistributor = session.getResultDistributor();
if (resultDistributor != null) {
resultDistributor.appendResult(new MessageModel("arthas server is going to shutdown."));
resultDistributor.close();
}
this.closeSession(session.getSessionId());
logger.info("Removing session before shutdown: {}, last access time: {}", session.getSessionId(), session.getLastAccessTime());
this.removeSession(session.getSessionId());
}
jobController.close();
@ -151,14 +152,19 @@ public class SessionManagerImpl implements SessionManager {
evictConsumers(session);
}
for (Session session : toClose) {
logger.info("Removing inactive session: {}, last access time: {}", session.getSessionId(), session.getLastAccessTime());
ResultDistributor resultDistributor = session.getResultDistributor();
//interrupt foreground job
Job job = session.getForegroundJob();
if (job != null) {
job.interrupt();
}
long timeOutInMinutes = sessionTimeoutMillis / 1000 / 60;
String reason = "session is inactive for " + timeOutInMinutes + " min(s).";
SharingResultDistributor resultDistributor = session.getResultDistributor();
if (resultDistributor != null) {
long timeOutInMinutes = sessionTimeoutMillis / 1000 / 60;
String reason = "session is inactive for " + timeOutInMinutes + " min(s).";
resultDistributor.appendResult(new MessageModel(reason));
}
this.closeSession(session.getSessionId());
this.removeSession(session.getSessionId());
logger.info("Removing inactive session: {}, last access time: {}", session.getSessionId(), session.getLastAccessTime());
}
}
@ -166,10 +172,9 @@ public class SessionManagerImpl implements SessionManager {
* Check and remove inactive consumer
*/
public void evictConsumers(Session session) {
ResultDistributor distributor = session.getResultDistributor();
if (distributor != null && distributor instanceof SharingResultDistributor) {
SharingResultDistributor sharingResultDistributor = (SharingResultDistributor) distributor;
List<ResultConsumer> consumers = sharingResultDistributor.getConsumers();
SharingResultDistributor distributor = session.getResultDistributor();
if (distributor != null) {
List<ResultConsumer> consumers = distributor.getConsumers();
//remove inactive consumer from session directly
long now = System.currentTimeMillis();
for (ResultConsumer consumer : consumers) {
@ -179,7 +184,7 @@ public class SessionManagerImpl implements SessionManager {
logger.info("Removing inactive consumer from session, sessionId: {}, consumerId: {}, inactive duration: {}",
session.getSessionId(), consumer.getConsumerId(), inactiveTime);
consumer.appendResult(new MessageModel("consumer is inactive for a while, please refresh the page."));
sharingResultDistributor.removeConsumer(consumer);
distributor.removeConsumer(consumer);
}
}
}

@ -1,9 +1,9 @@
package com.taobao.arthas.core.shell.system.impl;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import com.alibaba.arthas.deps.org.slf4j.Logger;
@ -25,7 +25,7 @@ import com.taobao.arthas.core.shell.term.Term;
* @author gehui 2017731 11:55:41
*/
public class GlobalJobControllerImpl extends JobControllerImpl {
private Map<Integer, JobTimeoutTask> jobTimeoutTaskMap = new HashMap<Integer, JobTimeoutTask>();
private Map<Integer, JobTimeoutTask> jobTimeoutTaskMap = new ConcurrentHashMap<Integer, JobTimeoutTask>();
private static final Logger logger = LoggerFactory.getLogger(GlobalJobControllerImpl.class);
@Override
@ -92,7 +92,8 @@ public class GlobalJobControllerImpl extends JobControllerImpl {
result = Long.parseLong(jobTimeoutConfig);
break;
}
} catch (Exception e) {
} catch (Throwable e) {
logger.error("parse jobTimeoutConfig: {} error!", jobTimeoutConfig, e);
}
if (result < 0) {

@ -1,8 +1,6 @@
package com.taobao.arthas.core.shell.system.impl;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import com.taobao.arthas.core.shell.future.Future;
@ -134,8 +132,9 @@ public class JobImpl implements Job {
process.terminate();
} catch (IllegalStateException ignore) {
// Process already terminated, likely by itself
} finally {
controller.removeJob(this.id);
}
controller.removeJob(this.id);
}
@Override

@ -6,7 +6,6 @@ import com.taobao.arthas.core.shell.cli.CliToken;
import com.taobao.arthas.core.shell.cli.CliTokens;
import com.taobao.arthas.core.shell.handlers.Handler;
import com.taobao.arthas.core.shell.session.Session;
import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer;
import io.termd.core.function.Consumer;
import io.termd.core.readline.Completion;

@ -4,7 +4,6 @@ import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.shell.ShellServerOptions;
import com.taobao.arthas.core.shell.term.TermServer;
import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer;
import io.termd.core.readline.Keymap;
import java.io.FileInputStream;

@ -82,7 +82,9 @@ public final class BasicHttpAuthenticatorHandler extends ChannelDuplexHandler {
Subject subject = securityAuthenticator.login(principal);
if (subject != null) {
authed = true;
session.setAttribute(ArthasConstants.SUBJECT_KEY, subject);
if (session != null) {
session.setAttribute(ArthasConstants.SUBJECT_KEY, subject);
}
}
if (!authed) {
@ -160,6 +162,10 @@ public final class BasicHttpAuthenticatorHandler extends ChannelDuplexHandler {
if (constraint != null) {
if ("Basic".equalsIgnoreCase(constraint.trim())) {
String decoded = StringUtils.after(auth, " ");
if (decoded == null) {
logger.error("Extracted Basic Auth principal failed, bad auth String: {}", auth);
return null;
}
// the decoded part is base64 encoded, so we need to decode that
ByteBuf buf = Unpooled.wrappedBuffer(decoded.getBytes());
ByteBuf out = Base64.decode(buf);

@ -147,7 +147,7 @@ public class DirectoryBrowser {
*/
public static DefaultFullHttpResponse directView(File dir, String path, FullHttpRequest request, ChannelHandlerContext ctx) throws IOException {
if (path.startsWith("/")) {
path = path.substring(1, path.length());
path = path.substring(1);
}
// path maybe: arthas-output/20201225-203454.svg
@ -175,75 +175,81 @@ public class DirectoryBrowser {
return null;
}
RandomAccessFile raf;
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(file, "r");
} catch (Exception ignore) {
return null;
}
long fileLength = raf.length();
if (fileLength < MIN_NETTY_DIRECT_SEND_SIZE){
FileInputStream fileInputStream = new FileInputStream(file);
try {
byte[] content = IOUtils.getBytes(fileInputStream);
fullResp.content().writeBytes(content);
HttpUtil.setContentLength(fullResp, fullResp.content().readableBytes());
} finally {
IOUtils.close(fileInputStream);
long fileLength = raf.length();
if (fileLength < MIN_NETTY_DIRECT_SEND_SIZE){
FileInputStream fileInputStream = new FileInputStream(file);
try {
byte[] content = IOUtils.getBytes(fileInputStream);
fullResp.content().writeBytes(content);
HttpUtil.setContentLength(fullResp, fullResp.content().readableBytes());
} finally {
IOUtils.close(fileInputStream);
}
ctx.write(fullResp);
ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
future.addListener(ChannelFutureListener.CLOSE);
return fullResp;
}
logger.info("file {} size bigger than {}, send by future.",file.getName(), MIN_NETTY_DIRECT_SEND_SIZE);
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
HttpUtil.setContentLength(response, fileLength);
setContentTypeHeader(response, file);
setDateAndCacheHeaders(response, file);
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.write(fullResp);
ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
future.addListener(ChannelFutureListener.CLOSE);
return fullResp;
}
logger.info("file {} size bigger than {}, send by future.",file.getName(), MIN_NETTY_DIRECT_SEND_SIZE);
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
HttpUtil.setContentLength(response, fileLength);
setContentTypeHeader(response, file);
setDateAndCacheHeaders(response, file);
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
// Write the initial line and the header.
ctx.write(response);
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
ctx.newProgressivePromise());
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
// Write the initial line and the header.
ctx.write(response);
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
ctx.newProgressivePromise());
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown
logger.info(future.channel() + " Transfer progress: " + progress);
} else {
logger.info(future.channel() + " Transfer progress: " + progress + " / " + total);
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown
logger.info(future.channel() + " Transfer progress: " + progress);
} else {
logger.info(future.channel() + " Transfer progress: " + progress + " / " + total);
}
}
}
@Override
public void operationComplete(ChannelProgressiveFuture future) {
logger.info(future.channel() + " Transfer complete.");
}
});
@Override
public void operationComplete(ChannelProgressiveFuture future) {
logger.info(future.channel() + " Transfer complete.");
}
});
// Decide whether to close the connection or not.
if (!HttpUtil.isKeepAlive(request)) {
// Close the connection when the whole content is written out.
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
// Decide whether to close the connection or not.
if (!HttpUtil.isKeepAlive(request)) {
// Close the connection when the whole content is written out.
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}
} catch (Throwable e) {
logger.error("view file error, dir: {}, path: {}", dir, path, e);
return null;
} finally {
if (raf != null) {
IOUtils.close(raf);
}
}
return fullResp;
}
}

@ -97,7 +97,7 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequ
//try output dir later, avoid overlay classpath resources files
if (response == null) {
response = DirectoryBrowser.directView(dir, path, request, ctx);
isFileResponseFinished = (response == null) ? false : true;
isFileResponseFinished = response != null;
}
//not found
@ -158,7 +158,7 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequ
}
int li = path.lastIndexOf('.');
if (li != -1 && li != path.length() - 1) {
String ext = path.substring(li + 1, path.length());
String ext = path.substring(li + 1);
String contentType;
if ("html".equals(ext)) {
contentType = "text/html";

@ -669,7 +669,7 @@ public class HttpApiHandler {
}
}
private class ApiTerm implements Term {
private static class ApiTerm implements Term {
private Session session;

@ -8,7 +8,6 @@ import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import com.alibaba.deps.org.objectweb.asm.Type;
import com.taobao.arthas.core.command.model.ClassDetailVO;

@ -116,12 +116,12 @@ public class Decompiler {
List<String> lines = StringUtils.toLines(src);
if (maxLineNumber >= 100) {
formatStr = "/*%3d*/ ";
emptyStr = " ";
} else if (maxLineNumber >= 1000) {
if (maxLineNumber >= 1000) {
formatStr = "/*%4d*/ ";
emptyStr = " ";
} else if (maxLineNumber >= 100) {
formatStr = "/*%3d*/ ";
emptyStr = " ";
}
int index = 0;

@ -51,7 +51,7 @@ public class LogUtil {
*
* @param env
*/
public static LoggerContext initLooger(ArthasEnvironment env) {
public static LoggerContext initLogger(ArthasEnvironment env) {
String loggingConfig = env.resolvePlaceholders(LOGGING_CONFIG);
if (loggingConfig == null || loggingConfig.trim().isEmpty()) {
return null;
@ -88,7 +88,7 @@ public class LogUtil {
if (appender instanceof RollingFileAppender) {
RollingFileAppender fileAppender = (RollingFileAppender) appender;
if ("ARTHAS".equalsIgnoreCase(fileAppender.getName())) {
logFile = fileAppender.getFile();
logFile = new File(fileAppender.getFile()).getCanonicalPath();
}
}
}

@ -83,7 +83,7 @@ public class NetUtils {
int responseCode = con.getResponseCode();
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
@ -138,7 +138,7 @@ public class NetUtils {
pw.flush();
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
String line = null;
boolean start = false;
while ((line = br.readLine()) != null) {

@ -449,12 +449,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -475,12 +473,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -501,12 +497,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -527,12 +521,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -553,12 +545,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -579,12 +569,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -605,12 +593,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -631,12 +617,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}
@ -657,12 +641,10 @@ public abstract class ObjectUtils {
if(length == 0) {
return "{}";
} else {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder("{");
for(int i = 0; i < length; ++i) {
if(i == 0) {
sb.append("{");
} else {
if(i > 0) {
sb.append(", ");
}

@ -1,3 +1,19 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.taobao.arthas.core.util;
import java.io.BufferedReader;
@ -5,6 +21,7 @@ import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
@ -470,7 +487,7 @@ public abstract class StringUtils {
StringBuilder sb = new StringBuilder();
for(int patLen = oldPattern.length(); index >= 0; index = inString.indexOf(oldPattern, pos)) {
sb.append(inString.substring(pos, index));
sb.append(inString, pos, index);
sb.append(newPattern);
pos = index + patLen;
}
@ -655,17 +672,8 @@ public abstract class StringUtils {
}
public static Set<String> commaDelimitedListToSet(String str) {
TreeSet<String> set = new TreeSet<String>();
String[] tokens = commaDelimitedListToStringArray(str);
String[] var3 = tokens;
int var4 = tokens.length;
for(int var5 = 0; var5 < var4; ++var5) {
String token = var3[var5];
set.add(token);
}
return set;
return new TreeSet<String>(Arrays.asList(tokens));
}
/**
@ -689,7 +697,7 @@ public abstract class StringUtils {
}
int arraySize = array.length;
int bufSize = (arraySize == 0 ? 0 : (array[0].toString().length() + separator.length()) * arraySize);
StringBuffer buf = new StringBuffer(bufSize);
StringBuilder buf = new StringBuilder(bufSize);
for (int i = 0; i < arraySize; i++) {
if (i > 0) {
@ -722,7 +730,7 @@ public abstract class StringUtils {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
@ -910,12 +918,10 @@ public abstract class StringUtils {
} catch (IOException exc) {
// quit
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore
}
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
return result;
@ -960,7 +966,7 @@ public abstract class StringUtils {
// print|(ILjava/util/List;)V
public static String[] splitMethodInfo(String methodInfo) {
int index = methodInfo.indexOf('|');
return new String[] { methodInfo.substring(0, index), methodInfo.substring(index + 1, methodInfo.length()) };
return new String[] { methodInfo.substring(0, index), methodInfo.substring(index + 1) };
}
// demo/MathGame|primeFactors|(I)Ljava/util/List;|24
@ -969,6 +975,10 @@ public abstract class StringUtils {
int index2 = invokeInfo.indexOf('|', index1 + 1);
int index3 = invokeInfo.indexOf('|', index2 + 1);
return new String[] { invokeInfo.substring(0, index1), invokeInfo.substring(index1 + 1, index2),
invokeInfo.substring(index2 + 1, index3), invokeInfo.substring(index3 + 1, invokeInfo.length()) };
invokeInfo.substring(index2 + 1, index3), invokeInfo.substring(index3 + 1) };
}
public static String beautifyName(String name) {
return name.replace(' ', '_').toLowerCase();
}
}

@ -449,15 +449,13 @@ abstract public class ThreadUtil {
}
private static String getTCCL(Thread currentThread) {
if (null == currentThread.getContextClassLoader()) {
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
if (null == contextClassLoader) {
return "null";
} else {
String classloaderClassName = currentThread.getContextClassLoader().getClass().getName();
StringBuilder sb = new StringBuilder(classloaderClassName.length()+10);
sb.append(classloaderClassName)
.append("@")
.append(Integer.toHexString(currentThread.getContextClassLoader().hashCode()));
return sb.toString();
return contextClassLoader.getClass().getName() +
"@" +
Integer.toHexString(contextClassLoader.hashCode());
}
}

@ -161,7 +161,7 @@ public class TypeRenderUtils {
public static FieldVO[] getFields(Class clazz) {
Field[] fields = clazz.getDeclaredFields();
if (fields == null || fields.length == 0) {
if (fields.length == 0) {
return new FieldVO[0];
}

@ -1,8 +1,7 @@
package com.taobao.arthas.core.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
@ -17,6 +16,11 @@ import java.util.concurrent.ThreadFactory;
* Created by zhuyong on 15/11/12.
*/
public class UserStatUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192;
private static final byte[] SKIP_BYTE_BUFFER = new byte[DEFAULT_BUFFER_SIZE];
private static final ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
@ -87,9 +91,9 @@ public class UserStatUtil {
public void appendQueryData(String key, String value) {
if (key != null && value != null) {
if (queryData.length() == 0) {
queryData.append(key + "=" + value);
queryData.append(key).append("=").append(value);
} else {
queryData.append("&" + key + "=" + value);
queryData.append("&").append(key).append("=").append(value);
}
}
}
@ -100,28 +104,27 @@ public class UserStatUtil {
if (link == null) {
return;
}
BufferedReader br = null;
InputStream inputStream = null;
try {
if (queryData.length() != 0) {
link = link + "?" + queryData;
}
URL url = new URL(link.toString());
URL url = new URL(link);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(1000);
connection.setReadTimeout(1000);
connection.connect();
br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
StringBuilder result = new StringBuilder();
while ((line = br.readLine()) != null) {
result.append(line);
inputStream = connection.getInputStream();
//noinspection StatementWithEmptyBody
while (inputStream.read(SKIP_BYTE_BUFFER) != -1) {
// do nothing
}
} catch (Throwable t) {
// ignore
} finally {
if (br != null) {
if (inputStream != null) {
try {
br.close();
inputStream.close();
} catch (IOException e) {
// ignore
}

@ -144,7 +144,7 @@ public final class EnhancerAffect extends Affect {
cost(),
listenerId));
if (this.throwable != null) {
infoSB.append("\nEnhance error! exception: " + this.throwable);
infoSB.append("\nEnhance error! exception: ").append(this.throwable);
}
return infoSB.toString();
}

@ -144,27 +144,29 @@ public class ArthasReflectUtils {
|| (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(
packageName + "." + file.getName(),
file.getAbsolutePath(), recursive, classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0,
file.getName().length() - 6);
try {
// 添加到集合中去
// classes.add(Class.forName(packageName + '.' +
// className));
// 经过回复同学的提醒这里用forName有一些不好会触发static方法没有使用classLoader的load干净
classes.add(Thread.currentThread().getContextClassLoader()
.loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
// e.printStackTrace();
if (dirfiles != null) {
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(
packageName + "." + file.getName(),
file.getAbsolutePath(), recursive, classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0,
file.getName().length() - 6);
try {
// 添加到集合中去
// classes.add(Class.forName(packageName + '.' +
// className));
// 经过回复同学的提醒这里用forName有一些不好会触发static方法没有使用classLoader的load干净
classes.add(Thread.currentThread().getContextClassLoader()
.loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
// e.printStackTrace();
}
}
}
}

@ -7,6 +7,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@ -257,9 +258,7 @@ public class FieldUtils {
Class<?> currentClass = cls;
while (currentClass != null) {
final Field[] declaredFields = currentClass.getDeclaredFields();
for (final Field field : declaredFields) {
allFields.add(field);
}
allFields.addAll(Arrays.asList(declaredFields));
currentClass = currentClass.getSuperclass();
}
return allFields;
@ -444,7 +443,7 @@ public class FieldUtils {
}
static void isTrue(final boolean expression, final String message, final Object... values) {
if (expression == false) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, values));
}
}

@ -79,8 +79,7 @@ public class ClassInfoView implements View {
final StringBuilder fieldSB = new StringBuilder();
final Field[] fields = clazz.getDeclaredFields();
if (null != fields
&& fields.length > 0) {
if (fields.length > 0) {
for (Field field : fields) {
@ -128,7 +127,7 @@ public class ClassInfoView implements View {
final StringBuilder annotationSB = new StringBuilder();
final Annotation[] annotationArray = clazz.getDeclaredAnnotations();
if (null != annotationArray && annotationArray.length > 0) {
if (annotationArray.length > 0) {
for (Annotation annotation : annotationArray) {
annotationSB.append(StringUtils.classname(annotation.annotationType())).append(",");
}
@ -145,7 +144,7 @@ public class ClassInfoView implements View {
private String drawInterface() {
final StringBuilder interfaceSB = new StringBuilder();
final Class<?>[] interfaceArray = clazz.getInterfaces();
if (null == interfaceArray || interfaceArray.length == 0) {
if (interfaceArray.length == 0) {
interfaceSB.append(Constants.EMPTY_STRING);
} else {
for (Class<?> i : interfaceArray) {

@ -45,7 +45,7 @@ public class MethodInfoView implements View {
final StringBuilder annotationSB = new StringBuilder();
final Annotation[] annotationArray = method.getDeclaredAnnotations();
if (null != annotationArray && annotationArray.length > 0) {
if (annotationArray.length > 0) {
for (Annotation annotation : annotationArray) {
annotationSB.append(StringUtils.classname(annotation.annotationType())).append(",");
}
@ -62,7 +62,7 @@ public class MethodInfoView implements View {
private String drawParameters() {
final StringBuilder paramsSB = new StringBuilder();
final Class<?>[] paramTypes = method.getParameterTypes();
if (null != paramTypes && paramTypes.length > 0) {
if (paramTypes.length > 0) {
for (Class<?> clazz : paramTypes) {
paramsSB.append(StringUtils.classname(clazz)).append("\n");
}
@ -80,7 +80,7 @@ public class MethodInfoView implements View {
private String drawExceptions() {
final StringBuilder exceptionSB = new StringBuilder();
final Class<?>[] exceptionTypes = method.getExceptionTypes();
if (null != exceptionTypes && exceptionTypes.length > 0) {
if (exceptionTypes.length > 0) {
for (Class<?> clazz : exceptionTypes) {
exceptionSB.append(StringUtils.classname(clazz)).append("\n");
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save