我正在参与「构思开发 投稿大赛」详情请看:构思开发大赛来了!

信任在公司的小伙伴,有许多都经历过这样一种情况:公司关于某些开源软件制止运用,或许说需求修正源码,去掉其logo或许身份信息,各种监控软件就是其受害者。关于较大的系统,或许组件较多的系统,拥有一个牢靠的监控系统将是十分有必要的。

warriors体会地址:http://122.112.181.245/

布景

之前我曾就职于一家面向三大运营商的传统职业公司,一切的系统都是内网安置,且关于第三方的开源软件并不完全发起运用。

比如springboot自带的监组件springboot-admin,在运用的时分,我还专门去修正器源码,将logo替换为自己公司的logo,重新打包安置,说实话,挺苦楚的。而关于我一直比较推重的skywalkingprometheus,底子就不给你安置的机会。

但是一个好的方针监控系统,关于项目的平稳工作仍是能起到很关键的效果的。所以虽然不在之前的公司了,但是我一直有一个建立自己的监控系统的主意,可以按照公司的需求自行接入,而与本来的系统做到毫无违和。

简介

鉴于前面提到的布景,我在休息的时间,缓慢的开端了我自己的监控系统的建造,因为我是库里的球迷,所以暂时将此监控系统命名为勇士监控系统,即warriors,系统的色彩,也选用了勇士蓝黄组合。

甲方不让用开源【监控软件】?大不了我自己写一个!

勇士监控系统供应各种常用组件的接入,因为业余时间较少,现在只是接入了redis,作为给我们的演示。供应组件的各种常用方针,以报表的办法给用户供应直观的展现。

界面介绍

现在首要供应两个界面,主页简介,以及具体的监控页面。

  • 主页

    主页首要简略的为我们介绍勇士监控系统:

    甲方不让用开源【监控软件】?大不了我自己写一个!

    此界面可以手动准则即将查看的组件功用信息:

    甲方不让用开源【监控软件】?大不了我自己写一个!

  • 监控界面

    选择”redis”后,即进入redis监控页面,页面将会对具体的方针信息进行展现,包含但不限于以下的方针,可以随时增加新的方针。

    甲方不让用开源【监控软件】?大不了我自己写一个!

架构介绍

勇士监控系统以简略为主,只有一个服务,组件的监控代码通过stater的办法进行引入,整体架构如下所示:

甲方不让用开源【监控软件】?大不了我自己写一个!

如上图所示,整个监控系统由四部分组成,由上至下分别是:

  • ui界面:选用vue3完结
  • 服务端:选用springboot完结
  • 组件依托:通过stater定义不同组件的不同监控方针
  • 基础依托:供应各组件需求的基础类

完结

后台完结

依据简略的架构,组件的完结也十分的简略。代码结构如下所示:

甲方不让用开源【监控软件】?大不了我自己写一个!

上图傍边还包含了代码生成器的部分,便当我们快速开发。

关于常见的一些组件,比如redis,我们可以通过它自带的api去完结对其功用的监控,我这儿运用的是RedisTemplate,一同简略看下其完结:

  • 首选,看下公共依托都包含什么?

    甲方不让用开源【监控软件】?大不了我自己写一个!
    如上图所示,从上至下分别是:

    • 常量:公共常量
    • 枚举:回来枚举
    • 东西类:bean copye东西类,分页方针,回来结果

    需求特别重视的spring.factories,它是stater可以完结的中心配备,后边单独说明。

  • 引入redis依托

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!--    redis 连接池    -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <!--    基础依托    -->
    <dependency>
        <groupId>com.wjbgn.warriors</groupId>
        <artifactId>warriors-base-starter</artifactId>
    </dependency>
    
  • 看看redis-stater包含什么?

    甲方不让用开源【监控软件】?大不了我自己写一个!

    如上图所示,从上直线分别是:

    • redis配备文件:用来便当redis操作实例化方针:

      /**
       * description: 默许情况下RedisTemplate模板只能支撑字符串,我们自定义一个RedisTemplate,
       * 设置序列化器,这样我们可以很便当的操作实例方针。
       *
       * @return:
       * @author: weirx
       * @time: 2021/3/26 13:58
       */
      @Configuration
      public class RedisConfig {
          @Bean
          public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
              RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
              redisTemplate.setKeySerializer(new StringRedisSerializer());
              redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
              redisTemplate.setConnectionFactory(connectionFactory);
              return redisTemplate;
          }
      }
      
    • 实体类:用来封装监控方针的特色,比如服务信息如下所示:

      package com.wjbgn.warriors.redis.entity;
      import lombok.Data;
      /**
       * @description: 服务信息
       * @author:weirx
       * @date:2022/6/23 17:41
       * @version:3.0
       */
      @Data
      public class ServerInfo {
          /**
           * 版别
           */
          private String version;
          /**
           * 方式:单例,集群
           */
          private String mode;
          /**
           * 操作系统
           */
          private String os;
          private String port;
          /**
           * 工作时间
           */
          private String updateInDays;
          /**
           * 配备文件路径
           */
          private String config_path;
      }
      
    • 东西类:redis各类方针采集的东西类,以服务信息的代码为例:

       ```java
       package com.wjbgn.warriors.redis.util;
       import cn.hutool.core.util.ObjectUtil;
       import com.wjbgn.warriors.base.util.Result;
       import com.wjbgn.warriors.redis.entity.ServerInfo;
       import lombok.extern.slf4j.Slf4j;
       import org.springframework.stereotype.Component;
       import java.util.Arrays;
       import java.util.HashMap;
       import java.util.List;
       import java.util.Map;
       import static com.wjbgn.warriors.base.constants.CommonConstants.FLAG;
       /**
        * @description: redis服务信息
        * @author:weirx
        * @date:2022/6/23 17:19
        * @version:3.0
        */
       @Slf4j
       @Component
       public class RedisServerInfoUtil extends AbstractRedisInfoUtil{
           /**
            * description: 获取服务信息
            * @return: com.wjbgn.warriors.base.util.Result
            * @author: weirx
            * @time: 2022/6/24 10:21
            */
           public Result serverInfo() {
               Object serverInfo = getInfo("server");
               if (ObjectUtil.isNotEmpty(serverInfo)) {
                   String s = serverInfo.toString().replaceAll("[\t\n\r]", FLAG);
                   ServerInfo parse = this.parse(s);
                   return Result.success(parse);
               }
               return Result.failed();
           }
           /**
            * description: 解析服务信息
            * @param s
            * @return: com.wjbgn.warriors.redis.entity.ServerInfo
            * @author: weirx
            * @time: 2022/6/24 10:21
            */
           public ServerInfo parse(String s) {
               String[] split = s.split(FLAG + FLAG);
               List<String> list = Arrays.asList(split);
               ServerInfo serverInfo = new ServerInfo();
               Map<String, String> map = new HashMap<>();
               list.stream().forEach(str -> {
                   String[] strings = str.split(":");
                   if (strings.length > 1) {
                       map.put(strings[0], strings[1]);
                   }
               });
               map.forEach((k, v) -> {
                   if (k.equals("redis_version")) {
                       serverInfo.setVersion(v);
                   } else if (k.equals("redis_mode")) {
                       serverInfo.setMode(v);
                   } else if (k.equals("os")) {
                       serverInfo.setOs(v);
                   } else if (k.equals("tcp_port")) {
                       serverInfo.setPort(v);
                   } else if (k.equals("uptime_in_days")) {
                       serverInfo.setUpdateInDays(v);
                   } else if (k.equals("config_file")) {
                       serverInfo.setConfig_path(v);
                   }
               });
               return serverInfo;
           }
       }
       ```
      
    • 仍然是很重要的spring.factories

前台完结

前台代码的完结十分简略,选用vue3 + element-plus为基础进行开发,标准的vue3结构,如下所示:

甲方不让用开源【监控软件】?大不了我自己写一个!

组件实际只引用了:

  • element-plus
  • router
  • echarts
  • axios

具体监控界面,选用elment-plus的布局:

<el-card>
  <el-row>
    <el-col :span="4">
      Redis版别: {{redisServerInfo.redisVersion}}
    </el-col>
    <el-col :span="4">
      方式: {{redisServerInfo.redisMode}}
    </el-col>
    <el-col :span="4">
      端口: {{redisServerInfo.redisPort}}
    </el-col>
    <el-col :span="4">
      工作时间: {{redisServerInfo.redisUpdateInDays}}  天
    </el-col>
    <el-col :span="4">
      总内存: {{parseFloat((redisMemoryInfo.totalSystemMemory - redisMemoryInfo.usedMemory)/(1024*1024*1024)).toFixed(2)  }} G
    </el-col>
    <el-col :span="4">
      客户端: {{redisClientsInfo.connectionClientsNum}}
    </el-col>
  </el-row>
</el-card>

运用echarts完结报表的展现:

function drawHistogram(){
  // 依据准备好的dom,初始化echarts实例
  let myChart = echarts.init(document.getElementById('histogram'));
  // 绘制图表
  myChart.setOption({
    title: {
      text: '客户端信息'
    },
    tooltip: {},
    xAxis: {
      data: ['连接数','集群数','堵塞数','超时数']
    },
    yAxis: {},
    series: [
      {
        name: '',
        type: 'bar',
        data: [
          redisClientsInfo.connectionClientsNum,
          redisClientsInfo.clusterConnections,
          redisClientsInfo.blockedClients,
          redisClientsInfo.clientsInTimeoutTable
        ]
      }
    ]
  });
}

spring.factories是什么?

前面提到的spring.factories,单独拿出一部分来说明。其内部的构成如下所示:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.wjbgn.warriors.redis.util.RedisSlowLogUtil,\
  com.wjbgn.warriors.redis.util.RedisServerInfoUtil,\
  com.wjbgn.warriors.redis.util.RedisClientsInfoUtil,\
  com.wjbgn.warriors.redis.util.RedisMemoryInfoUtil,\
  com.wjbgn.warriors.redis.util.RedisPersistenceInfoUtil,\
  com.wjbgn.warriors.redis.util.RedisStatsInfoUtil

如上所示,在第一行的类:EnableAutoConfiguration,信任了解springboot的小伙伴都很了解,它是sopringboot自动装载配备的注解。所以我们可以知道,这个文件就是合作自动装置进行运用的。

在向下,则是配备文件,和我们定义的一系列的redis方针获取东西类。我们可以依据自己的项目需求进行配备拟定的util。

不配备spring.factories行吗?

答案是**可以配备,可以不配备*。

但是需求分为两种情况:

  • 不需求配备:东西类和依托它的服务在同一个包名下。
  • 需求配备:东西类和依托它的服务不在同一个包名下。

形成这种问题的本质原因是什么呢?

比如warriors这个系统,我完全可以不进行配备,因为我的包路径,全部都是com.wjbgn.warriors

我们需求知道的是,springboot的发起类,在发起的时分,会默许扫描和其同一级包名,和其包名下的类,这些类需求带有指定的注解,比如:@Service@Component等等。所以即使不指定spring.factories,也可以扫描到我们定义的配备文件和东西类,冰江他们注入到的spring容器傍边,供我们直接运用。

但是当我们的redis-starter是在其他的服务傍边被依托了呢?

他们想要运用此starter去做一些定制化的开发,那么就必须要配备spring.factories

spring.factoriesEnableAutoConfiguration相互合作,然后将其需求的bean进行自动配备。

上面提到的这种办法,我们可以称之为SPI,(Service Provider Interface)

总结

到此为止,warriors监控就介绍完结了,无论是运用的技能,仍是完结计划,都是我们常常运用,并且很实用的办法,可以尽量简略的完结自定义监控系统的研发。也十分合适初学者小伙伴上手去学习java相关的知识,同时可以使你更加清晰的知道各种组件的功用方针。

现在还处于开发阶段,发展取决于我的空闲时间,但是后续的规划仍是有的:

  • 接入邮件等告警模块。
  • 完结页面的动态配备办法。
  • 完善更多的组件监控。

相比于市道大多数的监控软件,warriors仍是一个襁褓里的孩子。但是含义在于给我们供应一个监控的最简略思路,让你可以快速的打造完全归于公司自己的监控系统。


发明不易,如需转载,请标明作者【我犟不过你】。