From e13ced6fdf045d23eae98de7e85d1bcc1a6c3988 Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Mon, 2 Nov 2020 20:56:16 +0800 Subject: [PATCH] support config appName;tunnel client/server support add appName prefix for agentId. #1562 --- bin/as.sh | 17 ++++++++++++- .../com/taobao/arthas/boot/Bootstrap.java | 14 ++++++++++- .../taobao/arthas/common/ArthasConstants.java | 5 ++++ .../java/com/taobao/arthas/core/Arthas.java | 5 +++- .../taobao/arthas/core/config/Configure.java | 16 ++++++++++++ .../arthas/core/server/ArthasBootstrap.java | 7 ++++++ .../arthas/tunnel/client/TunnelClient.java | 12 +++++++++ .../arthas/tunnel/common/URIConstans.java | 2 ++ .../server/TunnelSocketFrameHandler.java | 25 +++++++++++++++---- 9 files changed, 95 insertions(+), 8 deletions(-) diff --git a/bin/as.sh b/bin/as.sh index 18f94ad23..f9ac4a321 100755 --- a/bin/as.sh +++ b/bin/as.sh @@ -139,6 +139,9 @@ AGENT_ID= # stat report url STAT_URL= +# app name +APP_NAME= + ############ Command Arguments ############ # if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true @@ -393,6 +396,7 @@ Usage: $0 [-h] [--target-ip ] [--telnet-port ] [--http-port ] [--session-timeout ] [--arthas-home ] [--tunnel-server ] [--agent-id ] [--stat-url ] + [--app-name ] [--use-version ] [--repo-mirror ] [--versions] [--use-http] [--attach-only] [-c ] [-f ] [-v] [pid] @@ -412,6 +416,7 @@ Options and Arguments: --debug-attach Debug attach agent --tunnel-server Remote tunnel server url --agent-id Special agent id + --app-name Special app name --select select target process by classname or JARfilename -c,--command Command to execute, multiple commands separated by ; @@ -425,7 +430,7 @@ EXAMPLES: ./as.sh ./as.sh --target-ip 0.0.0.0 ./as.sh --telnet-port 9999 --http-port -1 - ./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' + ./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp ./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw ./as.sh --stat-url 'http://192.168.10.11:8080/api/stat' ./as.sh -c 'sysprop; thread' @@ -567,6 +572,11 @@ parse_arguments() shift # past argument shift # past value ;; + --app-name) + APP_NAME="$2" + shift # past argument + shift # past value + ;; --use-http) USE_HTTP=true shift # past argument @@ -759,6 +769,11 @@ attach_jvm() tempArgs+=("${STAT_URL}") fi + if [ "${APP_NAME}" ]; then + tempArgs+=("-app-name") + tempArgs+=("${APP_NAME}") + fi + "${java_command[@]}" \ ${ARTHAS_OPTS} ${JVM_OPTS} \ -jar "${arthas_lib_dir}/arthas-core.jar" \ diff --git a/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java b/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java index ffd9049af..1573e4ac1 100644 --- a/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java +++ b/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java @@ -47,7 +47,7 @@ import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT; @Summary("Bootstrap Arthas") @Description("EXAMPLES:\n" + " java -jar arthas-boot.jar \n" + " java -jar arthas-boot.jar --target-ip 0.0.0.0\n" + " java -jar arthas-boot.jar --telnet-port 9999 --http-port -1\n" - + " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'\n" + + " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp\n" + " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw\n" + " java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'\n" + " java -jar arthas-boot.jar -c 'sysprop; thread' \n" @@ -118,6 +118,8 @@ public class Bootstrap { private String tunnelServer; private String agentId; + private String appName; + private String statUrl; private String select; @@ -258,6 +260,12 @@ public class Bootstrap { this.agentId = agentId; } + @Option(longName = "app-name") + @Description("The app name") + public void setAppName(String appName) { + this.appName = appName; + } + @Option(longName = "stat-url") @Description("The report stat url") public void setStatUrl(String statUrl) { @@ -760,6 +768,10 @@ public class Bootstrap { return agentId; } + public String getAppName() { + return appName; + } + public String getStatUrl() { return statUrl; } diff --git a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java index 6efcd453d..44c75eceb 100644 --- a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java +++ b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java @@ -17,4 +17,9 @@ public class ArthasConstants { public static int MAX_HTTP_CONTENT_LENGTH = 1024 * 1024 * 8; public static final String ARTHAS_OUTPUT = "arthas-output"; + + public static final String APP_NAME = "app-name"; + + public static final String PROJECT_NAME = "project.name"; + public static final String SPRING_APPLICATION_NAME = "spring.application.name"; } diff --git a/core/src/main/java/com/taobao/arthas/core/Arthas.java b/core/src/main/java/com/taobao/arthas/core/Arthas.java index 901e3f364..b53b920b9 100644 --- a/core/src/main/java/com/taobao/arthas/core/Arthas.java +++ b/core/src/main/java/com/taobao/arthas/core/Arthas.java @@ -3,6 +3,7 @@ package com.taobao.arthas.core; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import com.taobao.arthas.common.AnsiLog; +import com.taobao.arthas.common.ArthasConstants; import com.taobao.arthas.common.JavaVersionUtils; import com.taobao.arthas.core.config.Configure; import com.taobao.middleware.cli.CLI; @@ -42,11 +43,12 @@ public class Arthas { Option tunnelServer = new TypedOption().setType(String.class).setShortName("tunnel-server"); Option agentId = new TypedOption().setType(String.class).setShortName("agent-id"); + Option appName = new TypedOption().setType(String.class).setShortName(ArthasConstants.APP_NAME); Option statUrl = new TypedOption().setType(String.class).setShortName("stat-url"); CLI cli = CLIs.create("arthas").addOption(pid).addOption(core).addOption(agent).addOption(target) - .addOption(telnetPort).addOption(httpPort).addOption(sessionTimeout).addOption(tunnelServer).addOption(agentId).addOption(statUrl); + .addOption(telnetPort).addOption(httpPort).addOption(sessionTimeout).addOption(tunnelServer).addOption(agentId).addOption(appName).addOption(statUrl); CommandLine commandLine = cli.parse(Arrays.asList(args)); Configure configure = new Configure(); @@ -66,6 +68,7 @@ public class Arthas { configure.setTunnelServer((String) commandLine.getOptionValue("tunnel-server")); configure.setAgentId((String) commandLine.getOptionValue("agent-id")); configure.setStatUrl((String) commandLine.getOptionValue("stat-url")); + configure.setAppName((String) commandLine.getOptionValue(ArthasConstants.APP_NAME)); return configure; } diff --git a/core/src/main/java/com/taobao/arthas/core/config/Configure.java b/core/src/main/java/com/taobao/arthas/core/config/Configure.java index 17a62d868..f3b03c7e3 100644 --- a/core/src/main/java/com/taobao/arthas/core/config/Configure.java +++ b/core/src/main/java/com/taobao/arthas/core/config/Configure.java @@ -28,6 +28,14 @@ public class Configure { private String tunnelServer; private String agentId; + /** + *
+     * 1. 如果显式传入 arthas.agentId ,则直接使用
+     * 2. 如果用户没有指定,则自动尝试在查找应用的 appname,加为前缀,比如 system properties设置 project.name是 demo,则
+     *    生成的 agentId是  demo-xxxx
+     * 
+ */ + private String appName; /** * report executed command */ @@ -118,6 +126,14 @@ public class Configure { this.statUrl = statUrl; } + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + /** * 序列化成字符串 * diff --git a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java index 1b40c5763..ad44cf86c 100644 --- a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java +++ b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java @@ -26,6 +26,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.tunnel.client.TunnelClient; import com.taobao.arthas.common.AnsiLog; +import com.taobao.arthas.common.ArthasConstants; import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.common.SocketUtils; import com.taobao.arthas.core.advisor.Enhancer; @@ -294,11 +295,17 @@ public class ArthasBootstrap { configure.setHttpPort(newHttpPort); logger().info("generate random http port: " + newHttpPort); } + // try to find appName + if (configure.getAppName() == null) { + configure.setAppName(System.getProperty(ArthasConstants.PROJECT_NAME, + System.getProperty(ArthasConstants.SPRING_APPLICATION_NAME, null))); + } String agentId = null; try { if (configure.getTunnelServer() != null) { tunnelClient = new TunnelClient(); + tunnelClient.setAppName(configure.getAppName()); tunnelClient.setId(configure.getAgentId()); tunnelClient.setTunnelServerUrl(configure.getTunnelServer()); tunnelClient.setVersion(ArthasBanner.version()); diff --git a/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/TunnelClient.java b/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/TunnelClient.java index 1146fd87f..7477bd7ad 100644 --- a/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/TunnelClient.java +++ b/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/TunnelClient.java @@ -52,6 +52,7 @@ public class TunnelClient { // two thread because need to reconnect. #1284 private EventLoopGroup eventLoopGroup = new NioEventLoopGroup(2, new DefaultThreadFactory("arthas-TunnelClient", true)); + private String appName; // agent id, generated by tunnel server. if reconnect, reuse the id volatile private String id; @@ -68,6 +69,9 @@ public class TunnelClient { QueryStringEncoder queryEncoder = new QueryStringEncoder(this.tunnelServerUrl); queryEncoder.addParam(URIConstans.METHOD, MethodConstants.AGENT_REGISTER); queryEncoder.addParam(URIConstans.ARTHAS_VERSION, this.version); + if (appName != null) { + queryEncoder.addParam(URIConstans.APP_NAME, appName); + } if (id != null) { queryEncoder.addParam(URIConstans.ID, id); } @@ -178,4 +182,12 @@ public class TunnelClient { public void setVersion(String version) { this.version = version; } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } } diff --git a/tunnel-common/src/main/java/com/alibaba/arthas/tunnel/common/URIConstans.java b/tunnel-common/src/main/java/com/alibaba/arthas/tunnel/common/URIConstans.java index 8cdcf768b..2dcded068 100644 --- a/tunnel-common/src/main/java/com/alibaba/arthas/tunnel/common/URIConstans.java +++ b/tunnel-common/src/main/java/com/alibaba/arthas/tunnel/common/URIConstans.java @@ -41,4 +41,6 @@ public class URIConstans { public static final String PROXY_RESPONSE_DATA = "responseData"; public static final String ARTHAS_VERSION = "arthasVersion"; + + public static final String APP_NAME = "appName"; } diff --git a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelSocketFrameHandler.java b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelSocketFrameHandler.java index b1901834b..1f3d82d75 100644 --- a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelSocketFrameHandler.java +++ b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelSocketFrameHandler.java @@ -8,6 +8,7 @@ import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -206,17 +207,31 @@ public class TunnelSocketFrameHandler extends SimpleChannelInboundHandler idList = queryDecoder.parameters().get("id"); + Map> parameters = queryDecoder.parameters(); + + String appName = null; + List appNameList = parameters.get(URIConstans.APP_NAME); + if (appNameList != null && !appNameList.isEmpty()) { + appName = appNameList.get(0); + } + + // generate a random agent id + String id = null; + if (appName != null) { + // 如果有传 app name,则生成带 app name前缀的id,方便管理 + id = appName + "_" + RandomStringUtils.random(20, true, true).toUpperCase(); + } else { + id = RandomStringUtils.random(20, true, true).toUpperCase(); + } + // agent传过来,则优先用 agent的 + List idList = parameters.get(URIConstans.ID); if (idList != null && !idList.isEmpty()) { id = idList.get(0); } String arthasVersion = null; - List arthasVersionList = queryDecoder.parameters().get(URIConstans.ARTHAS_VERSION); + List arthasVersionList = parameters.get(URIConstans.ARTHAS_VERSION); if (arthasVersionList != null && !arthasVersionList.isEmpty()) { arthasVersion = arthasVersionList.get(0); }