Skip to content

Commit

Permalink
Merge branch 'develop-for-20190410' into hotfix/performance
Browse files Browse the repository at this point in the history
  • Loading branch information
oldmanpushcart authored Sep 18, 2019
2 parents 43c6bd1 + 5e2066d commit 46757ef
Show file tree
Hide file tree
Showing 45 changed files with 640 additions and 253 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ sandbox-agent/target/
sandbox-debug-module/target/
sandbox-mgr-module/target/
sandbox-mgr-provider/target/
sandbox-module-starter/target/
target/

## for eclipse and vscode
.classpath
.project
.settings
.factorypath

## for vim
*.swp
*.swo
*.swn

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
## 目标群体

- BTRACE好强大,也曾技痒想做一个更便捷、更适合自己的问题定位工具,既可支持线上链路监控排查,也可支持单机版问题定位。
- [BTRACE](https://github.com/btraceio/btrace)好强大,也曾技痒想做一个更便捷、更适合自己的问题定位工具,既可支持线上链路监控排查,也可支持单机版问题定位。
- 有时候突然一个问题反馈上来,需要入参才能完成定位,但恰恰没有任何日志,甚至出现在别人的代码里,好想开发一个工具可以根据需要动态添加日志,最好还能按照业务ID进行过滤。
- 系统间的异常模拟可以使用的工具很多,可是系统内的异常模拟怎么办,加开关或是用AOP在开发系统中实现,好想开发一个更优雅的异常模拟工具,既能模拟系统间的异常,又能模拟系统内的异常。
- 好想获取行调用链路数据,可以用它识别场景、覆盖率统计等等,覆盖率统计工具不能原生支持,统计链路数据不准确。想自己开发一个工具获取行链路数据。
Expand Down
3 changes: 3 additions & 0 deletions bin/sandbox.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ user_module=~/.sandbox-module;
# define the network port
## server.port=4769

# define the server http response charset
server.charset=UTF-8

# switch the sandbox can enhance system class
unsafe.enable=true

43 changes: 34 additions & 9 deletions bin/sandbox.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ typeset SANDBOX_SERVER_NETWORK
typeset SANDBOX_LIB_DIR=${SANDBOX_HOME_DIR}/lib

# define sandbox attach token file
typeset SANDBOX_TOKEN_FILE=${HOME}/.sandbox.token
typeset SANDBOX_TOKEN_FILENAME=.sandbox.token
typeset SANDBOX_TOKEN_FILE=${HOME}/${SANDBOX_TOKEN_FILENAME}

# define JVM OPS
typeset SANDBOX_JVM_OPS="-Xms128M -Xmx128M -Xnoclassgc -ea";

# define target JVM Process ID
typeset TARGET_JVM_PID

# define target JVM starting user
typeset TARGET_JVM_USER=${USER}

# define target SERVER network interface
typeset TARGET_SERVER_IP
typeset DEFAULT_TARGET_SERVER_IP="0.0.0.0"
Expand Down Expand Up @@ -193,6 +197,13 @@ check_permission()
# reset some options for env
reset_for_env()
{
TARGET_JVM_USER=$(ps aux | awk '$2==PID' PID=${TARGET_JVM_PID} | grep java | awk '{print $1}')
if [[ "${USER}" != "${TARGET_JVM_USER}" ]]; then
SANDBOX_TOKEN_FILE=$(eval echo "~${TARGET_JVM_USER}")/${SANDBOX_TOKEN_FILENAME}
# touch attach token file
su - ${TARGET_JVM_USER} -c "touch ${SANDBOX_TOKEN_FILE}" \
|| exit_on_err 1 "permission denied, ${SANDBOX_TOKEN_FILE} is not readable."
fi

# use the env JAVA_HOME for default
[[ ! -z ${JAVA_HOME} ]] \
Expand All @@ -201,10 +212,11 @@ reset_for_env()
# use the target JVM for SANDBOX_JAVA_HOME
[[ -z ${SANDBOX_JAVA_HOME} ]] \
&& SANDBOX_JAVA_HOME="$(\
ps aux\
|grep ${TARGET_JVM_PID}\
|grep java\
|awk '{print $11}'\
lsof -p ${TARGET_JVM_PID}\
|grep "/bin/java"\
|awk '{print $9}'\
|xargs ls -l\
|awk '{if($1~/^l/){print $11}else{print $9}}'\
|xargs ls -l\
|awk '{if($1~/^l/){print $11}else{print $9}}'\
|sed 's/\/bin\/java//g'\
Expand Down Expand Up @@ -235,13 +247,23 @@ function attach_jvm() {
local token=`date |head|cksum|sed 's/ //g'`

# attach target jvm
"${SANDBOX_JAVA_HOME}/bin/java" \
ATTACH_CMD="${SANDBOX_JAVA_HOME}/bin/java \
${SANDBOX_JVM_OPS} \
-jar ${SANDBOX_LIB_DIR}/sandbox-core.jar \
${TARGET_JVM_PID} \
"${SANDBOX_LIB_DIR}/sandbox-agent.jar" \
"home=${SANDBOX_HOME_DIR};token=${token};server.ip=${TARGET_SERVER_IP};server.port=${TARGET_SERVER_PORT};namespace=${TARGET_NAMESPACE}" \
|| exit_on_err 1 "attach JVM ${TARGET_JVM_PID} fail."
\"${SANDBOX_LIB_DIR}/sandbox-agent.jar\" \
\"home=${SANDBOX_HOME_DIR};token=${token};server.ip=${TARGET_SERVER_IP};server.port=${TARGET_SERVER_PORT};namespace=${TARGET_NAMESPACE}\""

if [[ "${USER}" == "${TARGET_JVM_USER}" ]]; then
eval ${ATTACH_CMD} \
|| exit_on_err 1 "attach JVM ${TARGET_JVM_PID} fail. Attach command: $ATTACH_CMD"
else
su - ${TARGET_JVM_USER} -c "${ATTACH_CMD}" \
|| exit_on_err 1 "attach JVM ${TARGET_JVM_PID} fail. Attach command: $ATTACH_CMD"
fi

#fix for windows shell $HOME diff with user.home
test -n "$USERPROFILE" -a -z "$(cat $SANDBOX_TOKEN_FILE)" && SANDBOX_TOKEN_FILE=$USERPROFILE/.sandbox.token

# get network from attach result
SANDBOX_SERVER_NETWORK=$(grep ${token} ${SANDBOX_TOKEN_FILE}|grep ${TARGET_NAMESPACE}|tail -1|awk -F ";" '{print $3";"$4}');
Expand All @@ -266,6 +288,9 @@ function sandbox_curl_with_exit() {
function sandbox_debug_curl() {
local host=$(echo "${SANDBOX_SERVER_NETWORK}"|awk -F ";" '{print $1}')
local port=$(echo "${SANDBOX_SERVER_NETWORK}"|awk -F ";" '{print $2}')
if [[ "$host" = "0.0.0.0" ]] ; then
host="127.0.0.1";
fi
curl -N -s "http://${host}:${port}/sandbox/${TARGET_NAMESPACE}/${1}" \
|| exit_on_err 1 "target JVM ${TARGET_JVM_PID} lose response."
}
Expand Down
36 changes: 18 additions & 18 deletions doc/JVM-SANDBOX-USER-GUIDE-English.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@

### Install the container


- **Local installation**

- First need[Download](http://gitlab.alibaba-inc.com/jvm-sandbox/jvm-sandbox-doc/raw/master/release/sandbox-stable-bin.zip)latest stable version
- After downloading and decompressing `./sandbox`carried out`./install-local.sh`scriptspecify the installation directory for the sandbox。I personally like to install the program in `${HOME}/opt`.
- First [download](http://gitlab.alibaba-inc.com/jvm-sandbox/jvm-sandbox-doc/raw/master/release/sandbox-stable-bin.zip) latest stable version
- After downloading, run the `./install-local.sh` script and specify the installation directory for the sandbox。I personally like to install the program in `${HOME}/opt`.

```shell
./install-local.sh -p ~/opt
Expand All @@ -31,18 +30,18 @@

### Start mode

There are two ways to start the sandbox:`ATTACH``AGENT`
There are two ways to start the sandbox:`ATTACH` or `AGENT`

- **ATTACH**

Plug and play mode, you can not restart the target JVM case to complete the sandbox implant. Principle and GREYS, BTrace similar to the use of the JVM Attach mechanism to achieve.
Plug and play mode, there is no need to restart the target JVM to complete the sandbox implant. Principle and GREYS, BTrace similar to the use of the JVM Attach mechanism to achieve.

```shell
# Assume that the target JVM process number is`2343`
./sandbox.sh -p 2343
```

If output
If the output is similar to

```
VERSION : 0.0.0.i
Expand All @@ -53,24 +52,25 @@ There are two ways to start the sandbox:`ATTACH`和`AGENT`
SANDBOX_HOME : /Users/vlinux/opt/sandbox/lib/..
MODULE_LIB : /Users/vlinux/opt/sandbox/lib/../module
USER_MODULE_LIB : /Users/vlinux/.sandbox-module
EVENT_POOL_SUPPORT : ENABLE
EVENT_POOL_KEY_MIN : 100
EVENT_POOL_KEY_MAX : 2000
EVENT_POOL_SUPPORT : ENABLE
EVENT_POOL_KEY_MIN : 100
EVENT_POOL_KEY_MAX : 2000
EVENT_POOL_TOTAL : 3000
```
Then the success of the start, the sandbox has been successfully implanted in the target JVM, and completed the underlying port open and all modules loaded.
Then the sandbox has been successfully implanted in the target JVM, and opened a port and loaded all modules.
- **AGENT**
Sometimes we need the sandbox to work before the application code loads, or the larger scale of engineering. This needs to be enabled`AGENT`mode to start。
Sometimes we need the sandbox to start before the application code loads, or the larger scale of engineering. This is possible by starting in the `AGENT` mode.
Assume that SANDBOX is installed in `/Users/vlinux/opt/sandbox`Need to be added in the JVM startup parameters
If we assume that `sandbox` is installed in `/Users/vlinux/opt/sandbox`,the following need to be added to the JVM startup parameters
```shell
-javaagent:/Users/vlinux/opt/sandbox/lib/sandbox-agent.jar
```

This will be accompanied by the JVM boot and start the initiative to load and load the corresponding sandbox module.
When starting the JVM this will load the `sandbox` module before any of the application code is loaded.

### Introduction to Sandbox Engineering

Expand All @@ -94,21 +94,21 @@ Then the success of the start, the sandbox has been successfully implanted in th

- **./sandbox/bin/sandbox.sh**

Sandbox client script for starting, managing sandboxes
This is the `sandbox` client script used for starting and managing sandboxes.

- **./sandbox/cfg/**

Sandbox configuration file storage directory, which holds all the configuration file of the sandbox. For a detailed list of configuration files, please refer to the following link
This directory holds the `sandbox` configuration files. For a detailed list of configuration files, please refer to the following link

- [sandbox-logback.xml](#sandbox-logback.xmlConfiguration)
- [sandbox.properties](#sandbox.propertiesConfiguration)
- version

- **./sandbox/lib/**
- **./sandbox/lib/**

Sandbox main program of the library package directory, where the sandbox is stored in the main program, can not be free to delete, rename and move!
This holds `sandbox`s main program and cannot be deleted, renamed or moved!

|file name|Explanation of the action|
|File name|What it is|
|---|---|
|sandbox-agent.jar|Sandbox start agent|
|sandbox-core.jar|Sandbox kernel|
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

<groupId>com.alibaba.jvm.sandbox</groupId>
<artifactId>sandbox</artifactId>
<version>1.2.1</version>
<version>1.2.2-SNAPSHOT</version>
<packaging>pom</packaging>

<name>sandbox ${sandbox.version}</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sandbox.version>1.2.1</sandbox.version>
<sandbox.version>1.2.2-SNAPSHOT</sandbox.version>
</properties>

<build>
Expand Down
2 changes: 1 addition & 1 deletion sandbox-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.jvm.sandbox</groupId>
<artifactId>sandbox</artifactId>
<version>1.2.1</version>
<version>1.2.2-SNAPSHOT</version>
</parent>
<artifactId>sandbox-agent</artifactId>
<name>sandbox-agent ${sandbox.version}</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarFile;
import java.util.regex.*;

import static java.lang.String.format;

Expand Down Expand Up @@ -123,7 +124,6 @@ private static synchronized void writeAttachResult(final String namespace,
final String token,
final InetSocketAddress local) {
final File file = new File(RESULT_FILE_PATH);

if (file.exists()
&& (!file.isFile()
|| !file.canWrite())) {
Expand Down Expand Up @@ -214,17 +214,17 @@ private static synchronized InetSocketAddress install(final Map<String, String>
final String coreFeatureString = toFeatureString(featureMap);

try {

final String home = getSandboxHome(featureMap);
// 将Spy注入到BootstrapClassLoader
inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(
getSandboxSpyJarPath(getSandboxHome(featureMap))
getSandboxSpyJarPath(home)
// SANDBOX_SPY_JAR_PATH
)));

// 构造自定义的类加载器,尽量减少Sandbox对现有工程的侵蚀
final ClassLoader sandboxClassLoader = loadOrDefineClassLoader(
namespace,
getSandboxCoreJarPath(getSandboxHome(featureMap))
getSandboxCoreJarPath(home)
// SANDBOX_CORE_JAR_PATH
);

Expand Down Expand Up @@ -346,9 +346,22 @@ private static String getDefault(final Map<String, String> map, final String key
: defaultValue;
}

private static String OS = System.getProperty("os.name").toLowerCase();

private static boolean isWindows() {
return OS.contains("win");
}

// 获取主目录
private static String getSandboxHome(final Map<String, String> featureMap) {
return getDefault(featureMap, KEY_SANDBOX_HOME, DEFAULT_SANDBOX_HOME);
String home = getDefault(featureMap, KEY_SANDBOX_HOME, DEFAULT_SANDBOX_HOME);
if( isWindows() ){
Matcher m = Pattern.compile("(?i)^[/\\\\]([a-z])[/\\\\]").matcher(home);
if( m.find() ){
home = m.replaceFirst("$1:/");
}
}
return home;
}

// 获取命名空间
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarFile;

/**
Expand All @@ -29,7 +31,7 @@ class SandboxClassLoader extends URLClassLoader {
@Override
public URL getResource(String name) {
URL url = findResource(name);
if(null != url) {
if (null != url) {
return url;
}
url = super.getResource(name);
Expand All @@ -39,7 +41,7 @@ public URL getResource(String name) {
@Override
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration<URL> urls = findResources(name);
if( null != urls ) {
if (null != urls) {
return urls;
}
urls = super.getResources(name);
Expand Down Expand Up @@ -92,8 +94,7 @@ public void closeIfPossible() {
// 如果是JDK7+的版本, URLClassLoader实现了Closeable接口,直接调用即可
if (this instanceof Closeable) {
try {
final Method closeMethod = URLClassLoader.class.getMethod("close");
closeMethod.invoke(this);
((Closeable) this).close();
} catch (Throwable cause) {
// ignore...
}
Expand All @@ -104,13 +105,13 @@ public void closeIfPossible() {
// 对于JDK6的版本,URLClassLoader要关闭起来就显得有点麻烦,这里弄了一大段代码来稍微处理下
// 而且还不能保证一定释放干净了,至少释放JAR文件句柄是没有什么问题了
try {
final Object sun_misc_URLClassPath = URLClassLoader.class.getDeclaredField("ucp").get(this);
final Object java_util_Collection = sun_misc_URLClassPath.getClass().getDeclaredField("loaders").get(sun_misc_URLClassPath);
final Object sun_misc_URLClassPath = forceGetDeclaredFieldValue(URLClassLoader.class, "ucp", this);
final Object java_util_Collection = forceGetDeclaredFieldValue(sun_misc_URLClassPath.getClass(), "loaders", sun_misc_URLClassPath);

for (Object sun_misc_URLClassPath_JarLoader :
for (final Object sun_misc_URLClassPath_JarLoader :
((Collection) java_util_Collection).toArray()) {
try {
final JarFile java_util_jar_JarFile = (JarFile) sun_misc_URLClassPath_JarLoader.getClass().getDeclaredField("jar").get(sun_misc_URLClassPath_JarLoader);
final JarFile java_util_jar_JarFile = forceGetDeclaredFieldValue(sun_misc_URLClassPath_JarLoader.getClass(), "jar", sun_misc_URLClassPath_JarLoader);
java_util_jar_JarFile.close();
} catch (Throwable t) {
// if we got this far, this is probably not a JAR loader so skip it
Expand All @@ -123,4 +124,10 @@ public void closeIfPossible() {

}

private <T> T forceGetDeclaredFieldValue(Class<?> clazz, String name, Object target) throws NoSuchFieldException, IllegalAccessException {
final Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return (T)field.get(target);
}

}
2 changes: 1 addition & 1 deletion sandbox-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.jvm.sandbox</groupId>
<artifactId>sandbox</artifactId>
<version>1.2.1</version>
<version>1.2.2-SNAPSHOT</version>
</parent>
<artifactId>sandbox-api</artifactId>
<name>sandbox-api ${sandbox.version}</name>
Expand Down
Loading

0 comments on commit 46757ef

Please sign in to comment.