mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
arthas-boot/arthas-core support tunnel server; Configure fix pass "null" string problem; #835
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user