• SkyWalking拓朴图group功能改造


      用过SkyWalking的拓朴图功能都知道,里面有个组功能,见左下角Create Group按钮,我称之为域,一个组就是一个子域,这个功能还是很重要的,因为如果一个月内活跃的服务器很多,整体的拓朴图就会密密麻麻,点击左上角All services的下拉框的值又只能看到这个服务器相关的链路信息,这样拓朴图又不够直观,所以需要group来切分为一个个相关的域(子集合)。但是SkyWalking原有的分组功能又很操蛋,分好的组数据依赖于localStorage和Vuex,这台机子的分组数据就只存在于本地,别人的机子看不到,所以架构要求我在现有的接口上模仿做一个类似的功能。

      先在guyhub找到SkyWalking前端项目代码:https://github.com/apache/skywalking-rocketbot-ui。看了看这部分的源码,有了一个想法,既然没有后台配合,那首先,利用外部化配置文件配置域之间的包含关系,页面初始化时读取这个json文件,然后模仿Create group按钮的执行逻辑直接一步步走下去,相当于初始化给你建好组。按着这个思路写好了,这个初始化的组可以被编辑,而且由于没写好控制逻辑,刷新的时候仍然会被新增已有的组,写了个按钮主动触发初始化新增的动作,感觉也不是很完美,于是,我就有有了一个思路,模仿All services的功能来做一个All domains,见图中左上角All domains下拉框。

      以SkyWalking7.0.0分支的代码为例:

    首先public下新建config.json,请严格遵守json格式

    {
       "domains" :[{
           "name":"第一个域",
           "children":["service1","service2","service3"]
       },{
           "name":"第二个域",
           "children":["service4","service5"]
       }]
    }

    页面上给新的All domains下拉框腾个位置,src/views/components/topology/topo-aside.vue

    <template>
        <svg class="link-topo-aside-btn icon cp lg" @click="showRadial()" :style="`position:absolute;left:290px;`">
          <use xlink:href="#issues" />
        </svg>
        <svg
          v-if="showServerInfo"
          class="link-topo-aside-btn icon cp lg"
          @click="show = !show"
          :style="`position:absolute;left:290px;transform: rotate(${show ? 0 : 180}deg);top:45px;`"
        >
          <use xlink:href="#chevron-left" />
        </svg>
    </template>
    
    <style>
    .link-topo-aside-box {
        border-radius: 4px;
        position: absolute;
         280px;
        z-index: 101;
        color: #ddd;
        background-color: #2b3037;
        padding: 15px 20px 10px;
    }
    </style>

    将上述代码template部分中的left:290px修改为410px,style部分中的 280px修改为400px,此处自行调整,开心就好。

    接下来修改src/views/components/topology/topo-services.vue,其中的请求本地文件用的是原生xhr对象,如果乐意也可以npm安装axios,此处不展开。

    <template>
      <div class="link-topo-aside-box" style="padding:0;">
        <TopoSelect :current="service" :data="services" @onChoose="handleChange" style="float:left;50%"/>
        <TopoSelect :current="domain" :data="domains" @onChoose="domainHandleChange" style="float:left;50%"/>
      </div>
    </template>
    <script lang="ts">
      import { DurationTime } from '@/types/global';
      import compareObj from '@/utils/comparison';
      import Axios, { AxiosResponse } from 'axios';
      import { Component, Vue, Watch } from 'vue-property-decorator';
      import { Action, Getter, Mutation } from 'vuex-class';
      import TopoSelect from './topo-select.vue';
    
      @Component({ components: { TopoSelect } })
      export default class TopoServices extends Vue {
        @Getter('durationTime') public durationTime: any;
        @Action('rocketTopo/GET_TOPO') public GET_TOPO: any;
        @Mutation('rocketTopoGroup/UNSELECT_GROUP') private UNSELECT_GROUP: any;
        private services = [{ key: 0, label: 'All services' }];
        private service = { key: 0, label: 'All services' };
        private domains = [{ key: 0, label: 'All domains' }];
        private domain = { key: 0, label: 'All domains' };
        private servicesMap=[];
        private domainsInJSON=[];
    
        private fetchData() {
          Axios.post('/graphql', {
            query: `
          query queryServices($duration: Duration!) {
            services: getAllServices(duration: $duration) {
              key: id
              label: name
            }
          }`,
            variables: {
              duration: this.durationTime,
            },
          }).then((res: AxiosResponse) => {
            this.services = res.data.data.services
              ? [{ key: 0, label: 'All services' }, ...res.data.data.services]
              : [{ key: 0, label: 'All services' }];
              this.servicesMap=res.data.data.services ? res.data.data.services:[];
          });
        }
    
        @Watch('durationTime')
        private watchDurationTime(newValue: DurationTime, oldValue: DurationTime) {
          // Avoid repeating fetchData() after enter the component for the first time.
          if (compareObj(newValue, oldValue)) {
            this.fetchData();
          }
        }
    
        private handleChange(i: any) {
          this.service = i;
          this.domain = { key: 0, label: 'All domains' };
          this.UNSELECT_GROUP();
          this.GET_TOPO({
            serviceId: this.service.key,
            duration: this.durationTime,
          });
        }
    
        private domainHandleChange(i: any) {
          this.domains = i;
          this.service = { key: 0, label: 'All services' };
          this.UNSELECT_GROUP();
          if(i.key==0){
            this.GET_TOPO({
              serviceId: this.service.key,
              duration: this.durationTime,
            });
          }else{
            let params:string[]=[];
            let domains:any = this.domainsInJSON[i.key-1];
            this.servicesMap.forEach((item:any)=>{
              domains.children.forEach((subItem:any)=>{
                if(item.label == subItem){
                  params.push(item.key);
                }
              })
            })
            this.GET_TOPO({
              serviceId: this.service.key,
              duration: this.durationTime,
            });
          }
        }
    
        private created() {
          this.fetchData();
          var that=this;
          var request=new XMLHttpRequest();
          request.open("get","./config.json");
          request.send(null);
          request.onload = function(){
            if(request.status==200){
              console.log("读取外部化配置文件成功>>>>>>>>>>");
              const json = JSON.parse(request.responseText);
              that.domainsInJSON = json.domains;
              const domains = json.domains;
              for(let i=1 ; i< (domains.length+1) ;i++){
                that.domains.push({ key:i , label:domains[i-1].name })
              }
            }else{
              console.log("读取外部化配置文件失败,请检查JSON文件是否符合格式>>>>>>>>>>");
            }
          }
        }
      }
    </script>

      最后修改vue.config.js文件,需要注意的是原本SkyWalking前端的包是会被打到SkyWalking后端包中,如果还是想这样子的话可以在skywalking官网下载的tar包解压后的根目录webapp下的skywalking-webapp.jar解压,然后路径为BOOT-INF/classes/public,然后把我们的刚打出来的dist包下的文件覆盖进去替换全部,然后再把skywalking-webapp压缩还原为jar包即可,那下面的步骤就可以不用看了。

      如果是把前端项目单独分离出来维护,就需要修改proxy字段中转发的地址修改为自己SkyWalking后端地址,端口为默认的12800,否则本地联调不通。

    let baseUrl='/skywalking-app' // 页面地址,根据自己需要进行修
    module.exports = {
      publicPath : baseUrl,
      lintOnsave : true,
      outputDir : dist, //包名,根据自己需要进行修改
      devServer: {
        proxy: {
          '/graphql': {
            target: `${process.env.SW_PROXY_TARGET || 'http://XXX.XX.XX.XX:12800'}`,
            changeOrigin: true,
          },
        },
      },
    };

    然后在nginx配置文件nginx.conf文件中进行配置,需要注意的是Skywalking的路由采用history模式,页面刷新会404,try_files语句就是为了解决这个问题。

            location /skywalking-app {
                alias html/dist;
                index  index.html index.htm;
                try_files $uri $uri/ /skywalking-app/index.html
                add_header 'Access-Control-Allow-Origin' '*'; #允许来自所有的访问地址
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS'; #支持请求方式
                add_header 'Access-Control-Allow-Headers' 'Content-Type,*';
            }
    
            #skywalking-app的反向代理
            location /graphql{
               proxy_set_header   Host             $host;
               proxy_set_header   x-forwarded-for  $remote_addr;
               proxy_set_header   X-Real-IP        $remote_addr;
               proxy_pass  http://XXXX.XX.XX.XX:12800;
            }
  • 相关阅读:
    POJ 1548 Robots(最小路径覆盖)
    <html>
    站点开发-日志-1
    JSP入门实战下
    rancher官方资源
    window10死机
    window10桌面图标空白
    sentry使用docker-compose部署
    docker下一步步部署sentry
    docker-compose编排服务
  • 原文地址:https://www.cnblogs.com/jdWu-d/p/14178985.html
Copyright © 2020-2023  润新知