Parcourir la source

update NginxLog.vue

reghao il y a 2 mois
Parent
commit
4ccd7c8c51
2 fichiers modifiés avec 504 ajouts et 125 suppressions
  1. 8 4
      src/api/devops.js
  2. 496 121
      src/views/devops/srv/NginxLog.vue

+ 8 - 4
src/api/devops.js

@@ -121,12 +121,16 @@ export function updateNginxConf(payload) {
   return post(devopsApi.getMachineNginx + '/conf', payload)
 }
 
-export function getNginxLog(queryInfo) {
-  return get(devopsApi.getMachineNginx + '/log', queryInfo)
+export function getLogDates(queryInfo) {
+  return get(devopsApi.getMachineNginx + '/log/date', queryInfo)
 }
 
-export function getNginxLogChart(queryInfo) {
-  return get(devopsApi.getMachineNginx + '/log/chart', queryInfo)
+export function getNginxLog2(payload) {
+  return post(devopsApi.getMachineNginx + '/log2', payload)
+}
+
+export function getNginxLogCount(queryInfo) {
+  return get(devopsApi.getMachineNginx + '/count', queryInfo)
 }
 
 export function getNginxLogChart1(queryInfo) {

+ 496 - 121
src/views/devops/srv/NginxLog.vue

@@ -2,13 +2,13 @@
   <el-container>
     <el-header height="220">
       <el-row style="margin-top: 10px">
-        <span>
+<!--        <span>
           <span v-if="wsConnectStatus" style="color: green; margin: 5px">WebSocket 已连接</span>
           <span v-if="!wsConnectStatus" style="color: red; margin: 5px">WebSocket 未连接</span>
-        </span>
+        </span>-->
+        <span style="color: red">{{ queryInfo.dateStr }} 访问统计</span>
         <el-select
           v-model="queryInfo.dateStr"
-          size="mini"
           placeholder="日期"
           style="margin-left: 5px"
           @change="onSelectChange"
@@ -16,81 +16,172 @@
           <el-option
             v-for="(item, index) in logDateList"
             :key="index"
-            :label="item.name"
-            :value="item.name"
+            :label="item.label"
+            :value="item.value"
           />
         </el-select>
+        <el-button style="margin: 5px" type="success" @click="onRefresh">刷新</el-button>
+        <el-button style="margin: 5px" type="success" @click="onRefreshChart1">最近一周</el-button>
+        <el-button style="margin: 5px" type="success" @click="showDatePicker ? showDatePicker = false : showDatePicker = true">显示</el-button>
+      </el-row>
+      <el-row v-if="showDatePicker" style="margin-top: 10px">
+        <el-date-picker
+          v-model="dateTimeArray"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期时间"
+          end-placeholder="结束日期时间"
+          :picker-options="pickerOptions1"
+        />
+        <el-button style="margin: 5px" size="small" type="success" @click="onSearch1">查询</el-button>
       </el-row>
     </el-header>
     <el-main>
       <el-row style="padding: 5px">
-        <el-card>
-          <div slot="header" class="clearfix">
-            <span>全站每日请求数量</span>
-            <el-button style="float: right; padding: 3px 0" type="text" @click="onRefreshChart1">刷新</el-button>
-          </div>
-          <div id="chart1" style="height:400px;" />
-        </el-card>
+        <el-col :md="16">
+          <el-card style="margin: 5px">
+            <div slot="header" class="clearfix">
+              <span>访问 IP 分布</span>
+              <el-button style="margin: 5px; float: right; padding: 3px 0" type="text" @click="onRefreshChart6">刷新</el-button>
+            </div>
+            <div id="chart6" style="height:600px;" />
+          </el-card>
+        </el-col>
+        <el-col :md="8">
+          <el-card style="margin: 5px">
+            <div slot="header" class="clearfix">
+              <span>访问数量</span>
+            </div>
+            <div>
+              <el-statistic
+                group-separator=","
+                :value="logCount"
+              />
+            </div>
+          </el-card>
+          <el-card style="margin: 5px">
+            <div slot="header" class="clearfix">
+              <span>请求状态码分布</span>
+              <el-button style="margin: 5px; float: right; padding: 3px 0" type="text" @click="onRefreshChart32">UserAgent</el-button>
+            </div>
+            <div id="chart3" style="height:400px;" />
+          </el-card>
+        </el-col>
       </el-row>
       <el-row style="padding: 5px">
         <el-card>
           <div slot="header" class="clearfix">
-            <span>全站 <span style="color: red">{{ queryInfo.dateStr }}</span> 每秒请求数量</span>
+            <span>每秒访问数量</span>
             <el-button style="float: right; padding: 3px 0" type="text" @click="onRefreshChart2">刷新</el-button>
           </div>
           <div id="chart2" style="height:400px;" />
         </el-card>
       </el-row>
       <el-row style="padding: 5px">
-        <el-card>
-          <div slot="header" class="clearfix">
-            <span>全站 <span style="color: red">{{ queryInfo.dateStr }}</span> 各 URL 访问数量</span>
-            <el-button style="float: right; padding: 3px 0" type="text" @click="onShowDialog">刷新</el-button>
-          </div>
-          <el-table
-            :data="urlList"
-            border
-            height="480"
-            style="width: 100%"
-          >
-            <el-table-column
-              fixed="left"
-              label="No"
-              type="index"
-            />
-            <el-table-column
-              prop="name"
-              label="URL"
-            />
-            <el-table-column
-              prop="total"
-              label="访问量"
-            />
-            <el-table-column
-              fixed="right"
-              label="操作"
-              width="280"
+        <el-col :md="12">
+          <el-card style="margin: 5px">
+            <div slot="header" class="clearfix">
+              <span>各 URL 访问数量</span>
+              <el-button style="float: right; padding: 3px 0" type="text" @click="onGetUrlChart">刷新</el-button>
+            </div>
+            <el-table
+              :data="urlList"
+              border
+              height="480"
+              style="width: 100%"
             >
-              <template slot-scope="scope">
-                <el-button
-                  style="margin-top: 5px; margin-left: 5px"
-                  size="mini"
-                  type="success"
-                  @click="onGetImages(scope.$index, scope.row)"
-                >每日分布</el-button>
-                <el-button
-                  style="margin-top: 5px; margin-left: 5px"
-                  size="mini"
-                  type="success"
-                  @click="onGetImages5(scope.$index, scope.row)"
-                >历史分布</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
+              <el-table-column
+                label="No"
+                type="index"
+              />
+              <el-table-column
+                prop="name"
+                label="URL"
+              />
+              <el-table-column
+                prop="total"
+                label="访问量"
+              />
+              <el-table-column
+                fixed="right"
+                label="操作"
+                width="240"
+              >
+                <template slot-scope="scope">
+                  <el-button
+                    style="margin-top: 5px; margin-left: 5px"
+                    size="mini"
+                    type="success"
+                    @click="onGetDaily(scope.$index, scope.row)"
+                  >当日分布</el-button>
+                  <el-button
+                    style="margin-top: 5px; margin-left: 5px"
+                    size="mini"
+                    type="success"
+                    @click="onGetWeekly(scope.$index, scope.row)"
+                  >当周数量</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-card>
+        </el-col>
+        <el-col :md="12">
+          <el-card style="margin: 5px">
+            <div slot="header" class="clearfix">
+              <span>耗时请求 Top100</span>
+              <el-button style="float: right; padding: 3px 0" type="text" @click="onGetRequestTime">刷新</el-button>
+            </div>
+            <el-table
+              :data="requestTimeList"
+              border
+              height="480"
+              style="width: 100%"
+            >
+              <el-table-column
+                label="No"
+                type="index"
+              />
+              <el-table-column
+                prop="name"
+                label="URL"
+              />
+              <el-table-column
+                prop="value"
+                label="耗时(秒)"
+              />
+              <el-table-column
+                fixed="right"
+                label="操作"
+                width="120"
+              >
+                <template slot-scope="scope">
+                  <el-button
+                    style="margin-top: 5px; margin-left: 5px"
+                    size="mini"
+                    type="success"
+                    @click="onGetDetail(scope.$index, scope.row)"
+                  >详情</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-card>
+        </el-col>
       </el-row>
     </el-main>
 
+    <el-dialog
+      :title="chart1DialogTitle"
+      append-to-body
+      :visible.sync="showChart1Dialog"
+      width="70%"
+      center
+      @opened="handleDialogOpened1"
+      @closed="handleDialogClosed1"
+    >
+      <template>
+        <div id="chart1" style="height:400px;" />
+      </template>
+    </el-dialog>
     <el-dialog
       :title="chart5DialogTitle"
       append-to-body
@@ -121,12 +212,8 @@
 </template>
 
 <script>
-import {
-  getNginxLog,
-  getNginxLogChart, getNginxLogChart1,
-  getNginxLogChart2, getNginxLogChart3,
-  getNginxLogChart4, getNginxLogChart5, getNginxLogChart6
-} from '@/api/devops'
+import * as echarts from 'echarts'
+import { getLogDates, getNginxLog1, getNginxLog2, getNginxLogChart1, getNginxLogChart2, getNginxLogChart3, getNginxLogChart4, getNginxLogChart5, getNginxLogChart6, getNginxLogCount } from '@/api/devops'
 
 export default {
   name: 'NginxLog',
@@ -134,11 +221,47 @@ export default {
     return {
       queryInfo: {
         dateStr: '',
+        aggregateField: '',
         url: ''
       },
       logDateList: [],
       urlList: [],
       // **********************************************************************
+      showDatePicker: false,
+      pickerOptions1: {
+        shortcuts: [{
+          text: '最近一天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      },
+      dateTimeArray: '',
+      // **********************************************************************
+      requestTimeList: [],
+      logCount: 0,
+      // **********************************************************************
+      showChart1Dialog: false,
+      chart1DialogTitle: '',
       showChart4Dialog: false,
       chart4DialogTitle: '',
       showChart5Dialog: false,
@@ -153,6 +276,9 @@ export default {
       myChart2: null,
       xData2: [],
       yData2: [],
+      myChart3: null,
+      xData3: [],
+      yData3: [],
       myChart4: null,
       xData4: [],
       yData4: [],
@@ -210,7 +336,14 @@ export default {
       return num.toString().padStart(2, '0')
     },
     getData() {
-      getNginxLog().then(resp => {
+      this.onGetCount()
+      this.onRefreshChart2()
+      this.onRefreshChart3()
+      this.onGetUrlChart()
+      this.onGetRequestTime()
+      // this.onRefreshChart6()
+
+      getLogDates().then(resp => {
         if (resp.code === 0) {
           this.logDateList = resp.data
         } else {
@@ -220,15 +353,75 @@ export default {
         this.$message.error(error.message)
       })
     },
-    onGetImages(index, row) {
+    onRefresh() {
+      this.getData()
+      this.$message.info('数据正在刷新')
+    },
+    onSelectChange() {
+      this.queryInfo.url = ''
+      this.$router.push({
+        path: '/bg/backend/access_log',
+        query: this.queryInfo
+      })
+      this.onRefresh()
+    },
+    onGetDaily(index, row) {
       this.queryInfo.url = row.name
       this.showChart4Dialog = true
-      this.chart4DialogTitle = row.name + ' 接口 ' + this.queryInfo.dateStr + ' 请求时间分布'
+      this.chart4DialogTitle = row.name + ' 接口 ' + this.queryInfo.dateStr + ' 访问时间分布'
+    },
+    onGetWeekly(index, row) {
+      this.queryInfo.url = row.name
+      this.showChart5Dialog = true
+      this.chart5DialogTitle = row.name + ' 接口 ' + this.queryInfo.dateStr + ' 前 7 天访问数量分布'
+    },
+    handleDialogOpened1() {
+      this.$nextTick(() => {
+        getNginxLogChart1(this.queryInfo).then(resp => {
+          if (resp.code === 0) {
+            const respData = resp.data
+            const xData = respData[0]
+            const yData = respData[1]
+
+            var chartOption1 = {
+              title: {
+                text: '每日请求数量',
+                subtext: '最近一周',
+                x: 'center',
+                y: 'top',
+                textAlign: 'center'
+              },
+              tooltip: {},
+              xAxis: {
+                data: xData
+              },
+              yAxis: {},
+              series: [{
+                name: '访问数量',
+                type: 'bar',
+                data: yData
+              }]
+            }
+            this.myChart1 = this.$echarts.init(document.getElementById('chart1'))
+            this.myChart1.setOption(chartOption1)
+          } else {
+            this.$message.error(resp.msg)
+          }
+        }).catch(error => {
+          this.$message.error(error.message)
+        })
+      })
+    },
+    handleDialogClosed1() {
+      if (this.myChart1) {
+        this.myChart1.dispose()
+        this.myChart1 = null
+      }
     },
     handleDialogOpened() {
       // 使用$nextTick确保DOM已完全渲染
       this.$nextTick(() => {
-        getNginxLogChart4(this.queryInfo).then(resp => {
+        getNginxLogChart2(this.queryInfo).then(resp => {
           if (resp.code === 0) {
             const respData = resp.data
             const xData = respData[0]
@@ -279,11 +472,6 @@ export default {
         this.myChart4 = null
       }
     },
-    onGetImages5(index, row) {
-      this.queryInfo.url = row.name
-      this.showChart5Dialog = true
-      this.chart5DialogTitle = row.name + ' 接口 ' + this.queryInfo.dateStr + ' 请求历史分布'
-    },
     handleDialogOpened5() {
       this.$nextTick(() => {
         getNginxLogChart5(this.queryInfo).then(resp => {
@@ -293,13 +481,6 @@ export default {
             const yData = respData[1]
 
             var option5 = {
-              title: {
-                text: '每日请求数量',
-                subtext: '最近一周',
-                x: 'center',
-                y: 'top',
-                textAlign: 'center'
-              },
               tooltip: {},
               xAxis: {
                 data: xData
@@ -327,7 +508,8 @@ export default {
         this.myChart5 = null
       }
     },
-    onShowDialog() {
+    onGetUrlChart() {
+      this.queryInfo.aggregateField = 'url'
       getNginxLogChart3(this.queryInfo).then(resp => {
         if (resp.code === 0) {
           this.urlList = resp.data
@@ -338,20 +520,24 @@ export default {
         this.$message.error(error.message)
       })
     },
-    onRefreshChart1() {
-      getNginxLogChart1(this.queryInfo).then(resp => {
+    onGetRequestTime() {
+      getNginxLogChart4(this.queryInfo).then(resp => {
         if (resp.code === 0) {
-          const respData = resp.data
-          const xData = respData[0]
-          const yData = respData[1]
-          this.myChart1.setOption({
-            xAxis: {
-              data: xData
-            },
-            series: [{
-              data: yData
-            }]
-          })
+          this.requestTimeList = resp.data
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
+      })
+    },
+    onGetDetail(index, row) {
+      this.$message.info('get request detail')
+    },
+    onGetCount() {
+      getNginxLogCount(this.queryInfo).then(resp => {
+        if (resp.code === 0) {
+          this.logCount = resp.data
         } else {
           this.$message.error(resp.msg)
         }
@@ -359,6 +545,10 @@ export default {
         this.$message.error(error.message)
       })
     },
+    onRefreshChart1() {
+      this.showChart1Dialog = true
+      this.chart1DialogTitle = this.queryInfo.dateStr + ' 前 7 天访问数量分布'
+    },
     onRefreshChart2() {
       getNginxLogChart2(this.queryInfo).then(resp => {
         if (resp.code === 0) {
@@ -380,39 +570,111 @@ export default {
         this.$message.error(error.message)
       })
     },
-    onSelectChange() {
-      this.queryInfo.url = ''
-      this.$router.push({
-        path: '/bg/backend/access_log',
-        query: this.queryInfo
+    onRefreshChart3() {
+      const queryInfo = {}
+      queryInfo.dateStr = this.queryInfo.dateStr
+      queryInfo.aggregateField = 'statusCode'
+      getNginxLogChart3(queryInfo).then(resp => {
+        if (resp.code === 0) {
+          const respData = resp.data
+          var list = []
+          for (const item of respData) {
+            list.push({
+              name: item.name,
+              value: item.total
+            })
+          }
+
+          this.myChart3.setOption({
+            series: [
+              {
+                data: list
+              }
+            ]
+          })
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
+      })
+    },
+    onRefreshChart32() {
+      const queryInfo = {}
+      queryInfo.dateStr = this.queryInfo.dateStr
+      queryInfo.aggregateField = 'userAgent'
+      getNginxLogChart3(queryInfo).then(resp => {
+        if (resp.code === 0) {
+          const respData = resp.data
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
+      })
+    },
+    onRefreshChart6() {
+      // 初始化统计图对象
+      this.myChart6 = this.$echarts.init(document.getElementById('chart6'))
+      // 显示 loading 动画
+      this.myChart6.showLoading()
+
+      var areaCode = '10-1'
+      const queryInfo = {}
+      queryInfo.dateStr = this.queryInfo.dateStr
+      queryInfo.aggregateField = 'ip'
+      getNginxLogChart6(queryInfo).then(resp => {
+        if (resp.code === 0) {
+          const respData = resp.data
+          var geoJsonStr = respData.geoJson
+          var geoJson = JSON.parse(geoJsonStr)
+          var dataList = respData.list
+
+          var mapName = areaCode
+          var mapData = geoJson
+          var chartOption6 = this.getChartOption1(mapName, dataList)
+          const deep = parseInt(mapName.split('-')[1])
+          var splitList = this.getSplitList(deep)
+          chartOption6.visualMap.splitList = splitList
+
+          // 注册地图(地图数据来自本地或后端的 geojson 格式数据)
+          echarts.registerMap(mapName, mapData)
+          this.myChart6.setOption(chartOption6)
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
+      }).finally(() => {
+        // 得到数据并绘制地图后关闭 loading 动画
+        this.myChart6.hideLoading()
+      })
+    },
+    onSearch1() {
+      if (this.dateTimeArray === '') {
+        this.$message.info('先选择日期时间, 间隔不超过 24 小时')
+        return
+      }
+
+      const startTime = this.formatDateTime(this.dateTimeArray[0])
+      const endTime = this.formatDateTime(this.dateTimeArray[1])
+      const payload = {}
+      payload.startDateTime = startTime
+      payload.endDateTime = endTime
+      getNginxLog2(payload).then(resp => {
+        if (resp.code === 0) {
+          const respData = resp.data
+        } else {
+          this.$message.error(resp.msg)
+        }
+      }).catch(error => {
+        this.$message.error(error.message)
       })
     },
     // ****************************************************************************************************************
     // chart 相关
     // ****************************************************************************************************************
     initChart() {
-      var chartOption1 = {
-        title: {
-          text: '每日请求数量',
-          subtext: '最近一周',
-          x: 'center',
-          y: 'top',
-          textAlign: 'center'
-        },
-        tooltip: {},
-        xAxis: {
-          data: this.xData1
-        },
-        yAxis: {},
-        series: [{
-          name: '访问数量',
-          type: 'bar',
-          data: this.yData1
-        }]
-      }
-      this.myChart1 = this.$echarts.init(document.getElementById('chart1'))
-      this.myChart1.setOption(chartOption1)
-
       var option2 = {
         title: {
           text: 'Nginx Log'
@@ -453,6 +715,119 @@ export default {
       }
       this.myChart2 = this.$echarts.init(document.getElementById('chart2'))
       this.myChart2.setOption(option2)
+
+      var chartOption3 = {
+        tooltip: {
+          trigger: 'item'
+        },
+        legend: {
+          top: '5%',
+          left: 'center'
+        },
+        series: [
+          {
+            name: 'Access From',
+            type: 'pie',
+            radius: ['40%', '70%'],
+            avoidLabelOverlap: false,
+            padAngle: 5,
+            itemStyle: {
+              borderRadius: 10
+            },
+            label: {
+              show: false,
+              position: 'center'
+            },
+            emphasis: {
+              label: {
+                show: true,
+                fontSize: 40,
+                fontWeight: 'bold'
+              }
+            },
+            labelLine: {
+              show: false
+            },
+            data: []
+          }
+        ]
+      }
+      this.myChart3 = this.$echarts.init(document.getElementById('chart3'))
+      this.myChart3.setOption(chartOption3)
+      this.onRefreshChart6()
+    },
+    getSplitList(deep) {
+      var splitList = []
+      if (deep === 1) {
+        splitList = [
+          { start: 800, end: 1000 },
+          { start: 600, end: 800 },
+          { start: 400, end: 600 },
+          { start: 200, end: 400 },
+          { start: 100, end: 200 },
+          { start: 0, end: 100 }
+        ]
+      } else if (deep === 2) {
+        splitList = [
+          { start: 500, end: 1000 },
+          { start: 100, end: 500 },
+          { start: 50, end: 100 },
+          { start: 20, end: 50 },
+          { start: 10, end: 20 },
+          { start: 0, end: 10 }
+        ]
+      } else if (deep === 3) {
+        splitList = [
+          { start: 20, end: 1000 },
+          { start: 15, end: 20 },
+          { start: 10, end: 15 },
+          { start: 5, end: 10 },
+          { start: 2, end: 5 },
+          { start: 0, end: 2 }
+        ]
+      }
+      return splitList
+    },
+    getChartOption1(mapName, dataList) {
+      return {
+        backgroundColor: '#FFFFFF',
+        tooltip: {
+          trigger: 'item'
+        },
+        // 数据导航栏
+        visualMap: {
+          show: true,
+          x: 'left', // 位于左侧
+          y: 'center',
+          splitList: [
+            { start: 800, end: 1000 },
+            { start: 600, end: 800 },
+            { start: 400, end: 600 },
+            { start: 200, end: 400 },
+            { start: 100, end: 200 },
+            { start: 0, end: 100 }
+          ],
+          // 对应 splitList 的颜色
+          color: [
+            '#5475f5',
+            '#9feaa5',
+            '#85daef',
+            '#74e2ca',
+            '#e6ac53',
+            '#9fb5ea'
+          ]
+        },
+        series: [{
+          name: '访问 IP 数量',
+          type: 'map',
+          map: mapName, // 和 registerMap 时使用的 name 一致
+          roam: true, // 是否可以移动, 放大缩小地图
+          label: {
+            show: false // 地图上显示地区名
+          },
+          data: dataList // 地图上显示的数据
+        }]
+      }
     },
     // ****************************************************************************************************************
     // WebSocket 相关