SpringBoot Admin集成诊断利器Arthas示例实现

目录
  • 前言
  • SpringBoot Admin
  • SBA 集成
  • 客户端配置
    • 在配置中心加入配置
    • 实现开关效果
  • 结束

前言

Arthas 是 Alibaba开源的Java诊断工具,具有实时查看系统的运行状况,查看函数调用参数、返回值和异常,在线热更新代码,秒解决类冲突问题、定位类加载路径,生成热点图,通过网页诊断线上应用。  如今在各大厂都有广泛应用,也延伸出很多产品。

这里将介绍如何将Arthas集成进SpringBoot监控平台中。

SpringBoot Admin

为了方便SpringBoot Admin 简称为SBA

版本:1.5.x

1.5版本的SBA如果要开发插件比较麻烦,需要下载SBA的源码包,再按照spring-boot-admin-server-ui-hystrix的形式copy一份,由于JS使用的是Angular,本人放弃了

版本:2.x

2.x版本的SBA插件开发,官网有介绍如何开发,JS使用Vue,方便很多,由于我们项目还在使用1.5,所以并没有使用该版本,请读者自行尝试

不能使用SBA的插件进行集成,那还有什么办法呢?????

SBA 集成

鄙人的办法是将Arthas的相关文件直接copy到admin服务中

arthas包该包下存放的是所有arthas的Java文件

  • endpoint包下的文件可以都注释掉,没多大用
  • ArthasController这个文件是我自己新建的,用来获取所有注册到Arthas的客户端,这在后面是有用的
  • 其他文件直接copy过来就行
@RequestMapping("/api/arthas")
@RestController
public class ArthasController {
 @Autowired
 private TunnelServer tunnelServer;
 @RequestMapping(value = "/clients", method = RequestMethod.GET)
 public Set<String> getClients() {
  Map<String, AgentInfo> agentInfoMap = tunnelServer.getAgentInfoMap();
  return agentInfoMap.keySet();
 }
}

spring-boot-admin-server-ui

该文件建在resources.META-INF下,admin会在启动的时候加载该目录下的文件

index.html 覆盖SBA原来的首页,在其中添加一个导航,首页会是这样

<!DOCTYPE html>
<html class="no-js">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Spring Boot Admin</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <link rel="shortcut icon" type="image/x-icon" href="img/favicon.png" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="core.css" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="all-modules.css" rel="external nofollow" />
</head>
<body>
<header class="navbar header--navbar desktop-only">
    <div class="navbar-inner">
        <div class="container-fluid">
            <div class="spring-logo--container">
                <a class="spring-logo" href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" ><span></span></a>
            </div>
            <div class="spring-logo--container">
                <a class="spring-boot-logo" href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" ><span></span></a>
            </div>
            <ul class="nav pull-right">
              <!--增加Arthas导航-->
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="arthas/arthas.html" rel="external nofollow" >Arthas</a>
                </li>
                <li ng-repeat="view in mainViews" class="navbar-link" ng-class="{active: $state.includes(view.state)}">
                    <a ui-sref="{{view.state}}" ng-bind-html="view.title"></a>
                </li>
            </ul>
        </div>
    </div>
</header>
<div ui-view></div>
<footer class="footer">
    <ul class="inline">
        <li><a href="https://codecentric.github.io/spring-boot-admin/@project.version@" rel="external nofollow"  target="_blank">Reference
            Guide</a></li>
        <li>-</li>
        <li><a href="https://github.com/codecentric/spring-boot-admin" rel="external nofollow"  target="_blank">Sources</a></li>
        <li>-</li>
        <li>Code licensed under <a href="http://www.apache.org/licenses/LICENSE-2.0" rel="external nofollow"  target="_blank">Apache License
            2.0</a></li>
    </ul>
</footer>
<script src="dependencies.js" type="text/javascript"></script>
<script type="text/javascript">
  sbaModules = [];
</script>
<script src="core.js" type="text/javascript"></script>
<script src="all-modules.js" type="text/javascript"></script>
<script type="text/javascript">
  angular.element(document).ready(function () {
    angular.bootstrap(document, sbaModules.slice(0), {
      strictDi: true
    });
  });
</script>
</body>
</html>

arthas.html 新建页面,用于显示arthas控制台页面

<!DOCTYPE html>
<html class="no-js">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Spring Boot Admin</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <link rel="shortcut icon" type="image/x-icon" href="../img/favicon.png" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="../core.css" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="../all-modules.css" rel="external nofollow" />
    <script src="js/jquery-3.3.1.min.js"></script>
    <script src="js/popper-1.14.6.min.js"></script>
    <script src="js/xterm.js"></script>
    <script src="js/web-console.js"></script>
    <script src="js/arthas.js"></script>
    <link href="js/xterm.css" rel="external nofollow"  rel="stylesheet" />
    <script type="text/javascript">
        window.addEventListener('resize', function () {
            var terminalSize = getTerminalSize();
            ws.send(JSON.stringify({ action: 'resize', cols: terminalSize.cols, rows: terminalSize.rows }));
            xterm.resize(terminalSize.cols, terminalSize.rows);
        });
    </script>
</head>
<body>
<header class="navbar header--navbar desktop-only">
    <div class="navbar-inner">
        <div class="container-fluid">
            <div class="spring-logo--container">
                <a class="spring-logo" href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" ><span></span></a>
            </div>
            <div class="spring-logo--container">
                <a class="spring-boot-logo" href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" ><span></span></a>
            </div>
            <ul class="nav pull-right">
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="arthas.html" rel="external nofollow" >Arthas</a>
                </li>
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="../" rel="external nofollow" >Applications</a>
                </li>
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="../#/turbine" rel="external nofollow" >Turbine</a>
                </li>
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="../#/events" rel="external nofollow" >Journal</a>
                </li>
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="../#/about" rel="external nofollow" >About</a>
                </li>
                <li class="navbar-link ng-scope">
                    <a  class="ng-binding" href="../#/logout" rel="external nofollow" ><i class="fa fa-2x fa-sign-out" aria-hidden="true"></i></a>
                </li>
            </ul>
        </div>
    </div>
</header>
<div ui-view>
    <div class="container-fluid">
        <form class="form-inline">
            <input type="hidden" id="ip" name="ip" value="127.0.0.1">
            <input type="hidden" id="port" name="port" value="19898">
            Select Application:
            <select id="selectServer"></select>
            <button class="btn" onclick="startConnect()" type="button"><i class="fa fa-connectdevelop"></i> Connect</button>
            <button class="btn" onclick="disconnect()" type="button"><i class="fa fa-search-minus"></i> Disconnect</button>
            <button class="btn" onclick="release()" type="button"><i class="fa fa-search-minus"></i> Release</button>
        </form>
        <div id="terminal-card">
            <div id="terminal"></div>
        </div>
    </div>
</div>
</body>
</html>

arthas.js 存储页面控制的js

var registerApplications = null;
var applications = null;
$(document).ready(function () {
    reloadRegisterApplications();
    reloadApplications();
});
/**
 * 获取注册的arthas客户端
 */
function reloadRegisterApplications() {
    var result = reqSync("/api/arthas/clients", "get");
    registerApplications = result;
    initSelect("#selectServer", registerApplications, "");
}
/**
 * 获取注册的应用
 */
function reloadApplications() {
    applications = reqSync("/api/applications", "get");
    console.log(applications)
}
/**
 * 初始化下拉选择框
 */
function initSelect(uiSelect, list, key) {
    $(uiSelect).html('');
    var server;
    for (var i = 0; i < list.length; i++) {
        server = list[i].toLowerCase().split("@");
        if ("phantom-admin" === server[0]) continue;
        $(uiSelect).append("<option value=" + list[i].toLowerCase() + ">" + server[0] + "</option>");
    }
}
/**
 * 重置配置文件
 */
function release() {
    var currentServer = $("#selectServer").text();
    for (var i = 0; i < applications.length; i++) {
        serverId = applications[i].id;
        serverName = applications[i].name.toLowerCase();
        console.log(serverId + "/" + serverName);
        if (currentServer === serverName) {
            var result = reqSync("/api/applications/" +serverId+ "/env/reset", "post");
            alert("env reset success");
        }
    }
}
function reqSync(url, method) {
    var result = null;
    $.ajax({
        url: url,
        type: method,
        async: false, //使用同步的方式,true为异步方式
        headers: {
            'Content-Type': 'application/json;charset=utf8;',
        },
        success: function (data) {
            // console.log(data);
            result = data;
        },
        error: function (data) {
            console.log("error");
        }
    });
    return result;
}
  • 其他文件 jquery-3.3.1.min.js 新加Js

copy过来的js

popper-1.14.6.min.js

web-console.js

xterm.css

xterm.js

  • bootstrap.yml
# arthas端口
arthas:
  server:
    port: 9898

这样子,admin端的配置完成了

客户端配置

在配置中心加入配置

#arthas服务端域名
arthas.tunnel-server = ws://admin域名/ws
#客户端id,应用名@随机值,js会截取前面的应用名
arthas.agent-id = ${spring.application.name}@${random.value}
#arthas开关,可以在需要调试的时候开启,不需要的时候关闭
spring.arthas.enabled = false

需要自动Attach的应用中引入arthas-spring-boot-starter 需要对starter进行部分修改,要将注册arthas的部分移除,下面是修改后的文件。

我这里是将修改后的文件重新打包成jar包,上传到私服,但有些应用会有无法加载arthasConfigMap的情况,可以将这两个文件单独放到项目的公共包中

@EnableConfigurationProperties({ ArthasProperties.class })
public class ArthasConfiguration {
 private static final Logger logger = LoggerFactory.getLogger(ArthasConfiguration.class);
 @ConfigurationProperties(prefix = "arthas")
 @ConditionalOnMissingBean
 @Bean
 public HashMap<String, String> arthasConfigMap() {
  return new HashMap<String, String>();
 }
}
@ConfigurationProperties(prefix = "arthas")
public class ArthasProperties {
 private String ip;
 private int telnetPort;
 private int httpPort;
 private String tunnelServer;
 private String agentId;
 /**
  * report executed command
  */
 private String statUrl;
 /**
  * session timeout seconds
  */
 private long sessionTimeout;
 private String home;
 /**
  * when arthas agent init error will throw exception by default.
  */
 private boolean slientInit = false;
 public String getHome() {
  return home;
 }
 public void setHome(String home) {
  this.home = home;
 }
 public boolean isSlientInit() {
  return slientInit;
 }
 public void setSlientInit(boolean slientInit) {
  this.slientInit = slientInit;
 }
 public String getIp() {
  return ip;
 }
 public void setIp(String ip) {
  this.ip = ip;
 }
 public int getTelnetPort() {
  return telnetPort;
 }
 public void setTelnetPort(int telnetPort) {
  this.telnetPort = telnetPort;
 }
 public int getHttpPort() {
  return httpPort;
 }
 public void setHttpPort(int httpPort) {
  this.httpPort = httpPort;
 }
 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;
 }
 public String getStatUrl() {
  return statUrl;
 }
 public void setStatUrl(String statUrl) {
  this.statUrl = statUrl;
 }
 public long getSessionTimeout() {
  return sessionTimeout;
 }
 public void setSessionTimeout(long sessionTimeout) {
  this.sessionTimeout = sessionTimeout;
 }
}

实现开关效果

为了实现开关效果,还需要一个文件用来监听配置文件的改变
我这里使用的是在SBA中改变环境变量,对应服务监听到变量改变,当监听spring.arthas.enabled为true的时候,注册arthas, 到下面是代码

@Component
public class EnvironmentChangeListener implements ApplicationListener<EnvironmentChangeEvent> {
    @Autowired
    private Environment env;
    @Autowired
    private Map<String, String> arthasConfigMap;
    @Autowired
    private ArthasProperties arthasProperties;
    @Autowired
    private ApplicationContext applicationContext;
    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        Set<String> keys = event.getKeys();
        for (String key : keys) {
            if ("spring.arthas.enabled".equals(key)) {
                if ("true".equals(env.getProperty(key))) {
                    registerArthas();
                }
            }
        }
    }
    private void registerArthas() {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        String bean = "arthasAgent";
        if (defaultListableBeanFactory.containsBean(bean)) {
            ((ArthasAgent)defaultListableBeanFactory.getBean(bean)).init();
            return;
        }
        defaultListableBeanFactory.registerSingleton(bean, arthasAgentInit());
    }
    private ArthasAgent arthasAgentInit() {
        arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap);
        // 给配置全加上前缀
        Map<String, String> mapWithPrefix = new HashMap<String, String>(arthasConfigMap.size());
        for (Map.Entry<String, String> entry : arthasConfigMap.entrySet()) {
            mapWithPrefix.put("arthas." + entry.getKey(), entry.getValue());
        }
        final ArthasAgent arthasAgent = new ArthasAgent(mapWithPrefix, arthasProperties.getHome(),
                arthasProperties.isSlientInit(), null);
        arthasAgent.init();
        return arthasAgent;
    }
}

结束

到此可以愉快的在SBA中调试应用了,看看最后的页面

调试流程

开启Arthas

在Select Application中选择应用

  • Connect 连接应用
  • DisConnect 断开应用
  • Release 释放配置文件

这种集成方式有一些缺陷:

  • 使用jar包的方式引入应用,具有一定的侵略性,如果arthas无法启动,会导致应用也无法启动
  • 如果使用docker,需要适当调整JVM内存,防止开启arthas的时候,内存炸了
  • 没有使用SBA插件的方式集成
  • 如上集成仅供参考,还是需要根据自己企业的情况来做

以上就是SpringBoot Admin集成诊断利器Arthas示例实现的详细内容,更多关于SpringBoot Admin集成Arthas的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringCloud Alibaba Nacos 整合SpringBoot Admin实战

    目录 1. Spring Boot Admin 是什么 2. Spring Boot Admin 服务端 2.1. 添加依赖(服务端) 2.2. 配置 application.yml 2.3启动类:AdminServerMain 2.4配置类 :SecuritySecureConfig (直接cp官方文档) 3. Spring Boot Admin 客户端 3.1 客户端依赖 3.2 客户端配置 3.3. 客户端运行 4. Spring Boot Admin 功能 1. Spring Boot

  • SpringBoot Admin2.0 集成Arthas的实现步骤

    项目最初使用 Arthas 主要有两个目的: 通过 arthas 解决实现测试环境.性能测试环境以及生产环境性能问题分析工具的问题. 通过使用 jad.mc.redefine 功能组合实现生产环境部分节点代码热更新的能力. 技术选型相关 因为公司还未能建立起较为统一的生产微服务配置以及状态管理的能力,各自系统的研发运维较为独立.现在项目使用了 Spring Cloud 以及 Eureka 的框架结构,和 SBA 的基础支撑能力较为匹配,同时,SBA 已经可以提供服务感知,日志级别配置管理,以及基

  • SpringBoot Admin的简单使用的方法步骤

    目录 一.快速入门 1.1 SpringBoot Admin服务端的搭建 1.2 SpringBootAdmin client端搭建 1.3 效果展示 二.安全性 2.1 admin-server端安全加固 2.2 admin-client端的安全 三.小结 公司有个SpringBoot项目需要加个监控,网上找了下发现大家都在推荐SpringBootAdmin.SpringBoot Admin是开源社区孵化的项目,用于对SpringBoot应用的管理和监控.SpringBoot Admin 分为

  • SpringBoot-Admin实现微服务监控+健康检查+钉钉告警

    基于SpringCloud微服务平台,进行服务实例监控及健康检查,注册中心为eureka,SpringBoot提供了很好的组件SpringBoot Admin,2.X版本直接可以配置钉钉机器人告警. 效果:可以实现eureka注册的实例上线.下线触发钉钉告警.监控我们的服务实例健康检查. 搭建admin-server pom依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="

  • 五分钟解锁springboot admin监控新技巧

    最近这一个月由于项目进度紧张,将近一个月没有动静.分享一下最近体会的springboot监控的一些心得体会,供一些规模不是很大的团队做一些监控. 适用场景: 1.项目规模不大 2.用户量不是很大.并发要求不强 3.无专门运维力量 4.精致的团队规模 对于一些常规的项目,或者企业职责分工不是非常明确的单位来说.往往一个系统从需求到设计,开发,测试到最终上线,运维.往往80%的任务由开发团队来完成.由此,开发人员除了要实现系统的功能,还要为客户进行问题咨询答疑以及生产问题解决. 试想,一个应用上线后

  • SpringBoot Admin集成诊断利器Arthas示例实现

    目录 前言 SpringBoot Admin SBA 集成 客户端配置 在配置中心加入配置 实现开关效果 结束 前言 Arthas 是 Alibaba开源的Java诊断工具,具有实时查看系统的运行状况,查看函数调用参数.返回值和异常,在线热更新代码,秒解决类冲突问题.定位类加载路径,生成热点图,通过网页诊断线上应用.  如今在各大厂都有广泛应用,也延伸出很多产品. 这里将介绍如何将Arthas集成进SpringBoot监控平台中. SpringBoot Admin 为了方便SpringBoot

  • SpringBoot框架集成ElasticSearch实现过程示例详解

    目录 依赖 与SpringBoot集成 配置类 实体类 测试例子 RestHighLevelClient直接操作 索引操作 文档操作 检索操作 依赖 SpringBoot版本:2.4.2 <dependencies> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <opti

  • SpringBoot整合java诊断工具Arthas解读

    目录 一.Arthas官方文档 二.springBoot整合方式 1.pom文件引入 2.yaml文件引入 3.下载arthas-tunnel-server 4.启动Arthas Tunnel Server及spring项目 5.登录Arthas Tunnel Server 6.输入命令进行测试 总结 一.Arthas官方文档 https://arthas.aliyun.com/doc/ 二.springBoot整合方式 1.pom文件引入 <dependency> <groupId&g

  • Springboot WebFlux集成Spring Security实现JWT认证的示例

    1 简介 在之前的文章<Springboot集成Spring Security实现JWT认证>讲解了如何在传统的Web项目中整合Spring Security和JWT,今天我们讲解如何在响应式WebFlux项目中整合.二者大体是相同的,主要区别在于Reactive WebFlux与传统Web的区别. 2 项目整合 引入必要的依赖: <dependency> <groupId>org.springframework.boot</groupId> <art

  • springboot集成camunda的实现示例

    目录 1.说明 2.配置实战 3.生成数据库表说明 1.说明 camunda使用Java开的工作流引擎.这里使用springboot 2.2.6.release + camunda 3.4.2 2.配置实战 使用camunda流程引擎.web界面.Rest服务接口相应依赖如下: 流程引擎:camunda-bpm-spring-boot-starter Rest服务接口:camunda-bpm-spring-boot-starter-rest web界面模块:camunda-bpm-spring-

  • SpringBoot中集成企业微信机器人实现运维报警的示例

    目录 1.注册企业微信 2.添加群机器人 3.引入 forest 依赖 4.请求方法 5.发送消息 6.测试 在企业运营中,为了实现工作效率和执行效率的提升,往往会选择在社群中使用群聊机器人进行协助管理.机器人可以定时或者按照一定的规则给群里发信息并@群成员等.群聊机器人可以活跃气氛,关怀员工比如根据天气情况提醒员工注意天气变化,发送节日.生日祝福等.它也可以进行工作提醒,帮助员工更好的做系统化的回报总结,机器人可以依托业务系统,每天定时发送工作总结给对应负责人,帮助员工更好地复盘工作. 1.注

  • SpringBoot集成slf4j+log4j2的示例代码

    本文介绍了SpringBoot集成slf4j+log4j2的示例代码,分享给大家,具体如下: Maven依赖 <!--增加log4j2依赖↓--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency&g

  • springboot 集成支付宝支付的示例代码

    最简单的springboot集成支付宝 1 注册沙箱 沙箱是一个模拟环境登录,百度蚂蚁金服开放平台,支付宝扫码登录如下 然后沙箱需要注册一下,非常之简单,注册好以后进入到如下页面,选沙箱工具,然后下载一个生成密钥的工具.然后解压按照里面的readme生成公私密钥, 选择沙箱应用 上传公钥即可..沙箱到这里就基本完成了,里面还有沙箱版本的的android app可以下载下来. java 程序 1 新建一个springboot项目 因为我们创建的是一个web工程,所以,仅仅演示支付宝的demo,只需

  • SpringBoot集成SpringMVC的方法示例

    Spring MVC是一款优秀的.基于MVC思想的应用框架,它是Spring的一个子框架.是当前最优秀的MVC框架. Spring Boot整合Spring MVC只需在pom.xml中引入 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.3.7.RE

  • SpringBoot集成Auth0 JWT的示例代码

    目录 前言 session认证与Token认证 session认证 Token认证 JWT简介 JWT定义 JWT的类库 具体实现 JWT配置 JWT工具类 测试接口 前言 说说JWT,先说下互联网服务常见的两种用户认证方式: session认证与Token认证 session认证 传统的Session认证的大体流程可以表示为用户提供用户名和密码登录后由服务器存储一份用户登录信息并传递给浏览器保存为Cookie,并在下次请求中根据Cookie来识别用户,但这种方式缺陷明显: Session都是保

随机推荐