arthas-boot/arthas-core support tunnel server; Configure fix pass "null" string problem; #835

This commit is contained in:
hengyunabc
2019-08-29 20:45:27 +08:00
parent 3eb73c7067
commit bde058572f
8 changed files with 156 additions and 11 deletions
@@ -39,8 +39,12 @@ public class Arthas {
.setShortName("http-port").setDefaultValue(DEFAULT_HTTP_PORT);
Option sessionTimeout = new TypedOption<Integer>().setType(Integer.class)
.setShortName("session-timeout").setDefaultValue("" + Configure.DEFAULT_SESSION_TIMEOUT_SECONDS);
Option tunnelServer = new TypedOption<String>().setType(String.class).setShortName("tunnel-server");
Option agentId = new TypedOption<String>().setType(String.class).setShortName("agent-id");
CLI cli = CLIs.create("arthas").addOption(pid).addOption(core).addOption(agent).addOption(target)
.addOption(telnetPort).addOption(httpPort).addOption(sessionTimeout);
.addOption(telnetPort).addOption(httpPort).addOption(sessionTimeout).addOption(tunnelServer).addOption(agentId);
CommandLine commandLine = cli.parse(Arrays.asList(args));
Configure configure = new Configure();
@@ -56,6 +60,9 @@ public class Arthas {
configure.setIp((String) commandLine.getOptionValue("target-ip"));
configure.setTelnetPort((Integer) commandLine.getOptionValue("telnet-port"));
configure.setHttpPort((Integer) commandLine.getOptionValue("http-port"));
configure.setTunnelServer((String) commandLine.getOptionValue("tunnel-server"));
configure.setAgentId((String) commandLine.getOptionValue("agent-id"));
return configure;
}
@@ -24,6 +24,9 @@ public class Configure {
private String arthasCore;
private String arthasAgent;
private String tunnelServer;
private String agentId;
/**
* session timeout seconds
*/
@@ -85,6 +88,22 @@ public class Configure {
this.sessionTimeout = sessionTimeout;
}
public String getTunnelServer() {
return tunnelServer;
}
public void setTunnelServer(String tunnelServer) {
this.tunnelServer = tunnelServer;
}
public String getAgentId() {
return agentId;
}
public void setAgentId(String agentId) {
this.agentId = agentId;
}
// 对象的编码解码器
private final static FeatureCodec codec = new FeatureCodec(';', '=');
@@ -106,7 +125,10 @@ public class Configure {
// 非静态的才需要纳入非序列化过程
try {
map.put(field.getName(), String.valueOf(ArthasReflectUtils.getFieldValueByField(this, field)));
Object fieldValue = ArthasReflectUtils.getFieldValueByField(this, field);
if (fieldValue != null) {
map.put(field.getName(), String.valueOf(fieldValue));
}
} catch (Throwable t) {
//
}
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.server;
import com.taobao.arthas.core.config.Configure;
import com.alibaba.arthas.tunnel.client.TunnelClient;
import com.taobao.arthas.core.command.BuiltinCommandPack;
import com.taobao.arthas.core.shell.ShellServer;
import com.taobao.arthas.core.shell.ShellServerOptions;
@@ -9,19 +10,26 @@ import com.taobao.arthas.core.shell.handlers.BindHandler;
import com.taobao.arthas.core.shell.impl.ShellServerImpl;
import com.taobao.arthas.core.shell.term.impl.HttpTermServer;
import com.taobao.arthas.core.shell.term.impl.TelnetTermServer;
import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.arthas.core.util.Constants;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.UserStatUtil;
import com.taobao.middleware.logger.Logger;
import io.netty.channel.ChannelFuture;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -39,6 +47,7 @@ public class ArthasBootstrap {
private Thread shutdown;
private ShellServer shellServer;
private ExecutorService executorService;
private TunnelClient tunnelClient;
private ArthasBootstrap(int pid, Instrumentation instrumentation) {
this.pid = pid;
@@ -78,11 +87,40 @@ public class ArthasBootstrap {
throw new IllegalStateException("already bind");
}
String agentId = null;
try {
if (configure.getHttpPort() > 0) {
tunnelClient = new TunnelClient();
tunnelClient.setId(configure.getAgentId());
tunnelClient.setTunnelServerUrl(configure.getTunnelServer());
// ws://127.0.0.1:8563/ws
String host = "127.0.0.1";
if(configure.getIp() != null) {
host = configure.getIp();
}
URI uri = new URI("ws", null, host, configure.getHttpPort(), "/ws", null, null);
tunnelClient.setLocalServerUrl(uri.toString());
ChannelFuture channelFuture = tunnelClient.start();
channelFuture.await(10, TimeUnit.SECONDS);
if(channelFuture.isSuccess()) {
agentId = tunnelClient.getId();
}
}
} catch (Throwable t) {
logger.error("arthas", "start tunnel client error", t);
}
try {
ShellServerOptions options = new ShellServerOptions()
.setInstrumentation(instrumentation)
.setPid(pid)
.setSessionTimeout(configure.getSessionTimeout() * 1000);
if (agentId != null) {
Map<String, String> welcomeInfos = new HashMap<String, String>();
welcomeInfos.put("id", agentId);
options.setWelcomeMessage(ArthasBanner.welcome(welcomeInfos));
}
shellServer = new ShellServerImpl(options, this);
BuiltinCommandPack builtinCommands = new BuiltinCommandPack();
List<CommandResolver> resolvers = new ArrayList<CommandResolver>();
@@ -132,6 +170,13 @@ public class ArthasBootstrap {
}
public void destroy() {
if (this.tunnelClient != null) {
try {
tunnelClient.stop();
} catch (Throwable e) {
logger.error("arthas", "stop tunnel client error", e);
}
}
executorService.shutdownNow();
UserStatUtil.destroy();
// clear the reference in Spy class.
@@ -9,6 +9,9 @@ import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import static com.taobao.text.ui.Element.label;
@@ -93,6 +96,10 @@ public class ArthasBanner {
}
public static String welcome() {
return welcome(Collections.<String, String>emptyMap());
}
public static String welcome(Map<String, String> infos) {
logger.info("arthas version: " + version());
TableElement table = new TableElement().rightCellPadding(1)
.row("wiki", wiki())
@@ -100,6 +107,9 @@ public class ArthasBanner {
.row("version", version())
.row("pid", PidUtils.currentPid())
.row("time", DateUtils.getCurrentDate());
for (Entry<String, String> entry : infos.entrySet()) {
table.row(entry.getKey(), entry.getValue());
}
return logo() + "\n" + RenderUtil.render(table);
}