Browse Source

add NginxLog.vue

reghao 2 tháng trước cách đây
mục cha
commit
278f08c049
2 tập tin đã thay đổi với 420 bổ sung0 xóa
  1. 9 0
      src/router/background_devops.js
  2. 411 0
      src/views/devops/srv/NginxLog.vue

+ 9 - 0
src/router/background_devops.js

@@ -16,6 +16,7 @@ const MachineProc = () => import('views/devops/machine/MachineProc')
 const MachineTask = () => import('views/devops/machine/MachineTask')
 // srv
 const MachineNginx = () => import('views/devops/srv/MachineNginx')
+const NginxLog = () => import('views/devops/srv/NginxLog')
 // build
 const BuildDir = () => import('views/devops/build/BuildDir')
 const RepoAuth = () => import('views/devops/build/RepoAuth')
@@ -131,6 +132,14 @@ export default {
           icon: 'el-icon-s-data',
           component: MachineNginx,
           meta: { needAuth: true, roles: ['devops_admin'] }
+        },
+        {
+          path: '/bg/srv/nginx_log',
+          name: 'NginxLog',
+          title: 'NginxLog',
+          icon: 'el-icon-s-data',
+          component: NginxLog,
+          meta: { needAuth: true, roles: ['devops_admin'] }
         }
       ]
     },

+ 411 - 0
src/views/devops/srv/NginxLog.vue

@@ -0,0 +1,411 @@
+<template>
+  <el-container>
+    <el-header height="220">
+      <el-row style="margin-top: 10px">
+        <span>
+          <span v-if="wsConnectStatus" style="color: green; margin: 5px">WebSocket 已连接</span>
+          <span v-if="!wsConnectStatus" style="color: red; margin: 5px">WebSocket 未连接</span>
+        </span>
+        <el-select
+          v-model="env"
+          size="mini"
+          placeholder="环境"
+          style="margin-left: 5px"
+          @change="onSelectChange"
+        >
+          <el-option
+            v-for="(item, index) in envList"
+            :key="index"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+        <el-select
+          v-model="machineId"
+          size="mini"
+          placeholder="机器"
+          style="margin-left: 5px"
+          @change="onSelectChange1"
+        >
+          <el-option
+            v-for="(item, index) in machineList"
+            :key="index"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+        <el-button size="mini" type="warning" icon="el-icon-refresh" style="margin-left: 5px" @click="onRefresh">刷新</el-button>
+        <el-button size="mini" type="warning" icon="el-icon-files" style="margin-left: 5px" @click="onGetImages">镜像列表</el-button>
+      </el-row>
+    </el-header>
+    <el-main>
+      <el-row>
+        <div id="chart1" style="height:400px;" />
+      </el-row>
+    </el-main>
+
+    <el-dialog
+      title="镜像列表"
+      append-to-body
+      :visible.sync="showImageDialog"
+      width="70%"
+      center
+    >
+      <template>
+        <el-select
+          v-model="queryInfo.type"
+          size="mini"
+          style="margin-left: 5px"
+        >
+          <el-option label="关键字匹配" value="1" />
+          <el-option label="前缀匹配" value="2" />
+        </el-select>
+        <el-input
+          v-model="queryInfo.keyword"
+          size="mini"
+          style="width: 20%; padding: 3px"
+          clearable
+          placeholder="标题"
+        />
+        <el-button size="mini" type="success" icon="el-icon-search" style="margin-left: 5px" @click="onGetImages">查询</el-button>
+        <el-button size="mini" type="danger" icon="el-icon-search" style="margin-left: 5px" @click="onDeleteImages">删除未用镜像</el-button>
+        <el-table
+          ref="multipleTable"
+          :data="dataList1"
+          border
+          height="480"
+          style="margin-left: 5px; width: 100%"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column
+            type="selection"
+          />
+          <el-table-column
+            prop="repoTag"
+            label="镜像标签"
+          />
+          <el-table-column
+            prop="createdAt"
+            label="创建时间"
+          />
+          <el-table-column
+            prop="totalContainers"
+            label="使用的容器数量"
+          />
+        </el-table>
+        <el-button size="mini" type="success" icon="el-icon-minus" style="margin: 5px" @click="toggleSelection()">取消已选择</el-button>
+        <el-button size="mini" type="success" icon="el-icon-delete" style="margin: 5px" @click="deleteSelection()">删除已选择</el-button>
+      </template>
+    </el-dialog>
+  </el-container>
+</template>
+
+<script>
+import { getEnvList, getMachineSessions } from '@/api/devops'
+
+export default {
+  name: 'NginxLog',
+  data() {
+    return {
+      env: 'test',
+      envList: [],
+      machineId: '',
+      machineList: [],
+      queryInfo: {
+        type: '1',
+        keyword: ''
+      },
+      multipleSelection: [],
+      dataList: [],
+      dockerContainerList: [],
+      showImageDialog: false,
+      dataList1: [],
+      wsClient: null,
+      wsConnectStatus: false,
+      wsReconnectLock: false,
+      myChart: null,
+      xData: [],
+      yData: []
+    }
+  },
+  mounted() {
+    this.initChart()
+  },
+  created() {
+    document.title = 'NginxLog'
+
+    getEnvList().then(resp => {
+      if (resp.code === 0) {
+        this.env = resp.data.userEnv
+        this.envList = resp.data.envList
+        this.getMachineList(this.env)
+      } else {
+        this.$message.error(resp.msg)
+      }
+    }).catch(error => {
+      this.$message.error(error.message)
+    })
+    this.initWebSocket()
+  },
+  methods: {
+    getMachineList(env) {
+      getMachineSessions(env).then(resp => {
+        if (resp.code === 0) {
+          this.machineList = resp.data
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
+      })
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    toggleSelection(rows) {
+      if (rows) {
+        rows.forEach(row => {
+          this.$refs.multipleTable.toggleRowSelection(row)
+        })
+      } else {
+        this.$refs.multipleTable.clearSelection()
+      }
+    },
+    deleteSelection() {
+      if (this.multipleSelection.length === 0) {
+        this.$message.warning('请先选择要删除的项')
+        return
+      }
+
+      const imageIds = []
+      for (const item of this.multipleSelection) {
+        imageIds.push(item.imageId)
+      }
+      this.$confirm('确定要删除选择的镜像?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const formData = new FormData()
+        formData.append('imageIds', imageIds)
+
+        const jsonPayload = {}
+        jsonPayload.machineId = this.machineId
+        jsonPayload.ops = 'imageRm'
+        jsonPayload.payload = imageIds
+        this.sendMessage(JSON.stringify(jsonPayload))
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    handleDelete(index, row) {
+      this.$confirm('确定要删除选择的容器?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const formData = new FormData()
+        formData.append('opsType', 3)
+        formData.append('containerId', row.containerId)
+
+        const containerIds = []
+        containerIds.push(row.containerId)
+        const jsonPayload = {}
+        jsonPayload.machineId = this.machineId
+        jsonPayload.ops = 'containerRm'
+        jsonPayload.payload = containerIds
+        this.sendMessage(JSON.stringify(jsonPayload))
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    onRefresh() {
+      const jsonPayload = {}
+      jsonPayload.machineId = this.machineId
+      jsonPayload.ops = 'containerList'
+      this.sendMessage(JSON.stringify(jsonPayload))
+    },
+    onGetImages() {
+      if (this.machineId === '') {
+        this.$message.warning('请选择机器')
+        return
+      }
+
+      const jsonPayload = {}
+      jsonPayload.machineId = this.machineId
+      jsonPayload.ops = 'imageList'
+      jsonPayload.dockerQuery = this.queryInfo
+      this.sendMessage(JSON.stringify(jsonPayload))
+      this.showImageDialog = true
+    },
+    onDeleteImages() {
+      const jsonPayload = {}
+      jsonPayload.machineId = this.machineId
+      jsonPayload.ops = 'imageRmUnused'
+      jsonPayload.dockerQuery = this.queryInfo
+      this.sendMessage(JSON.stringify(jsonPayload))
+    },
+    onSelectChange() {
+      this.machineId = ''
+      this.getMachineList(this.env)
+    },
+    onSelectChange1() {
+      if (!this.wsConnectStatus) {
+        this.$message.warning('websocket 未连接')
+        return
+      }
+
+      const jsonPayload = {}
+      jsonPayload.machineId = this.machineId
+      jsonPayload.ops = 'containerList'
+      this.sendMessage(JSON.stringify(jsonPayload))
+    },
+    // ****************************************************************************************************************
+    // WebSocket相关
+    // ****************************************************************************************************************
+    initChart() {
+      var option = {
+        title: {
+          text: 'Nginx Log'
+        },
+        tooltip: {},
+        toolbox: {
+          feature: {
+            dataZoom: {
+              yAxisIndex: 'none'
+            },
+            restore: {},
+            saveAsImage: {}
+          }
+        },
+        legend: {
+          data: ['reqs/s']
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xData
+        },
+        yAxis: {},
+        series: [{
+          name: 'reqs/s',
+          type: 'line',
+          smooth: true,
+          data: this.yData
+        }],
+        dataZoom: [{ // 这个是设置滚动条的,可以拉动这个滚动条来改变你的图形的显示比例
+          type: 'slider',
+          show: true, // flase直接隐藏图形
+          xAxisIndex: [0],
+          left: '9%', // 滚动条靠左侧的百分比
+          bottom: -5,
+          start: 0, // 滚动条的起始位置
+          end: 50 // 滚动条的截止位置(按比例分割你的柱状图x轴长度)
+        }]
+      }
+
+      this.myChart = this.$echarts.init(document.getElementById('chart1'))
+      this.myChart.setOption(option)
+    },
+    // ****************************************************************************************************************
+    // WebSocket相关
+    // ****************************************************************************************************************
+    getUrl() {
+      const protocol = location.protocol
+      const hostname = location.hostname
+      const port = location.port
+      let prefix
+      if (protocol === 'https:') {
+        if (port === '' || port === 443) {
+          prefix = 'wss://' + hostname
+        } else {
+          prefix = 'wss://' + hostname + ':' + port
+        }
+      } else {
+        if (port === '' || port === 80) {
+          prefix = 'ws://' + hostname
+        } else {
+          prefix = 'ws://' + hostname + ':' + port
+        }
+      }
+
+      var params = 'app=logstash&host=localhost'
+      return prefix + '/bgws/log/pull?' + params
+    },
+    initWebSocket() {
+      if ('WebSocket' in window) {
+        const wsUrl = this.getUrl()
+        console.log(wsUrl)
+        this.wsClient = new WebSocket(wsUrl)
+        const that = this
+        this.wsClient.onopen = function() {
+          that.setOnline()
+        }
+        this.wsClient.onclose = function() {
+          that.setOffline()
+          that.reconnect()
+        }
+        this.wsClient.onerror = function() {
+          that.setOffline()
+          console.log('websocket connection error...')
+          that.reconnect()
+        }
+        this.wsClient.onmessage = function(evt) {
+          const message = JSON.parse(evt.data)
+          that.processMessage(message)
+        }
+      } else {
+        // 浏览器不支持 WebSocket
+        this.$message.error('您的浏览器不支持 WebSocket!')
+      }
+    },
+    setOnline() {
+      this.wsConnectStatus = true
+    },
+    setOffline() {
+      this.wsConnectStatus = false
+    },
+    reconnect() {
+      if (this.wsReconnectLock) return
+      this.wsReconnectLock = true
+      const that = this
+      setTimeout(function() {
+        console.log('websocket reconnecting...')
+        that.initWebSocket()
+        that.wsReconnectLock = false
+      }, 5000)
+    },
+    sendMessage(message) {
+      this.$message.info('send ws msg')
+      // this.wsClient.send(message)
+    },
+    processMessage(message) {
+      console.log(message)
+      var data = message
+      for (const x of data[0]) {
+        this.xData.push(x)
+      }
+      for (const y of data[1]) {
+        this.yData.push(y)
+      }
+
+      this.myChart.setOption({
+        xAxis: {
+          data: this.xData
+        },
+        series: [{
+          data: this.yData
+        }]
+      })
+    }
+  }
+}
+</script>
+
+<style>
+</style>