diff --git a/nezha-fronted/src/components/charts/chart-alert-list.vue b/nezha-fronted/src/components/charts/chart-alert-list.vue
index 0b2088e9b..768834a2e 100644
--- a/nezha-fronted/src/components/charts/chart-alert-list.vue
+++ b/nezha-fronted/src/components/charts/chart-alert-list.vue
@@ -60,12 +60,13 @@
:id="'tableContainer'+chartIndex"
:tableData="storedTableData"
:loading="loadingTable"
- :height="'calc(100% - 0px)'"
+ :height="'calc(100% - 46px)'"
:customTableTitle="tableTitle"
:tableId="''"
:projectAlertId="'tableContainer'+chartIndex"
@tableDataSort="tableDataSort"
@del="deleteMessage"
+ @showText="showText"
@messageDetail="messageDetail"
ref="alertListTable"
:form="'chartList'"
@@ -88,7 +89,7 @@
:id="'tableContainer'+chartIndex"
:tableData="storedScreanTableData"
:loading="loadingTable"
- :height="'calc(100% - 0px)'"
+ :height="'calc(100% - 20px)'"
:customTableTitle="tableTitle"
:tableId="''"
:projectAlertId="'tableContainer'+chartIndex"
@@ -129,10 +130,28 @@
{{$t("project.endpoint.dialogTitle")}}
+
+
+
+
+
+
+
+
+
+ {{$t('alert.config.trbShot')}}
+
+
-
@@ -296,7 +315,12 @@ export default {
chartUnit: 5,
deleteBox: { show: false, ids: '', remark: '', state: 2 },
isPreview: false,
- ps: null
+ ps: null,
+ resultType: '',
+ logData: [],
+ chartLoading: false,
+ dialogShowText: false,
+ dialogText: ''
}
},
computed: {
@@ -389,7 +413,7 @@ export default {
this.currentMsg = obj
this.chartUnit = obj.alertRule.unit ? obj.alertRule.unit : 5
this.$nextTick(() => {
- this.queryChartDate()
+ this.queryDate()
})
},
dialogClose () {
@@ -433,7 +457,7 @@ export default {
chartUnitChange (unit) {
this.chartUnit = unit
this.$nextTick(() => {
- this.queryChartDate()
+ this.queryDate()
})
},
messageDetail (row) {
@@ -441,7 +465,7 @@ export default {
this.currentMsg = { ...row, alertRule: { ...res.data } }
this.graphShow = true
this.$nextTick(() => {
- this.queryChartDate()
+ this.queryDate()
})
})
},
@@ -471,6 +495,7 @@ export default {
this.legend = []
this.chartDatas = []
axios.all(axiosArr).then(res => {
+ this.chartLoading = false
try {
res.forEach((response, promIndex) => {
if (response.status == 200) {
@@ -891,7 +916,168 @@ export default {
this.$set(this.searchLabel, 'orderBy', orderBy)
this.getAlertList()
},
-
+ queryDate () {
+ this.chartLoading = true
+ if (this.currentMsg.alertRule.type === 1) {
+ this.resultType = 'matrix'
+ this.$nextTick(() => {
+ this.queryChartDate()
+ })
+ } else if (this.currentMsg.alertRule.type === 2) {
+ this.queryLogData(1000)
+ }
+ },
+ exportLog ({ limit, descending }) {
+ const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
+ const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
+ const params = {
+ logql: this.expressions,
+ start: start,
+ end: end,
+ direction: descending ? 'backward' : 'forward',
+ limit
+ }
+ axios.get('/logs/loki/export', { responseType: 'blob', params: params }).then(res => {
+ if (window.navigator.msSaveOrOpenBlob) {
+ // 兼容ie11
+ const blobObject = new Blob([res.data])
+ window.navigator.msSaveOrOpenBlob(blobObject, 'log')
+ } else {
+ const url = URL.createObjectURL(new Blob([res.data]))
+ const a = document.createElement('a')
+ document.body.appendChild(a) // 此处增加了将创建的添加到body当中
+ a.href = url
+ a.download = 'log'
+ a.target = '_blank'
+ a.click()
+ a.remove() // 将a标签移除
+ }
+ }, error => {
+ const $self = this
+ const reader = new FileReader()
+ reader.onload = function (event) {
+ const responseText = reader.result
+ const exception = JSON.parse(responseText)
+ if (exception.message) {
+ $self.$message.error(exception.message)
+ } else {
+ console.error(error)
+ }
+ }
+ reader.readAsText(error.response.data)
+ })
+ },
+ queryLogData (limit) { // log的chart和table是一个请求
+ if (!limit) {
+ limit = 1000
+ }
+ const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
+ const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
+ this.expressions = [this.currentMsg.alertRule.expr]
+ this.$get('/logs/loki/api/v1/query_range?format=1&query=' + this.currentMsg.alertRule.expr + '&start=' + this.$stringTimeParseToUnix(start) + '&end=' + this.$stringTimeParseToUnix(end) + '&limit=' + limit).then(res => {
+ this.chartLoading = false
+ const logData = [res.data]
+ this.resultType = res.data.resultType
+ this.$nextTick(() => {
+ if (this.$refs.logDetail) {
+ this.$refs.logDetail.time = this.chartData.param.time
+ this.$refs.logDetail.wrapLines = this.chartData.param.wrapLines
+ this.$refs.logDetail.operations.descending = this.chartData.param.descending
+ }
+ // logData.forEach((item, index) => {
+ // item.result.forEach(result => {
+ // result.elements = this.expressions[index]
+ // })
+ // })
+ this.logData = logData
+ this.resultType === 'matrix' && this.loadLogGraph()
+ })
+ })
+ },
+ loadLogGraph () {
+ const graphData = this.logData.filter(l => l.resultType === 'matrix')
+ if (graphData && graphData.length > 0) {
+ this.$refs.messageChart.startLoading()
+ const queryExpression = []
+ let series = []
+ const legend = []
+ this.expressions.forEach((item, index) => {
+ if (item !== '') {
+ queryExpression.push(item)
+ }
+ })
+ this.logData.forEach((response, index) => {
+ if (response.resultType === 'matrix') {
+ const data = response.result
+ if (!data || data.length < 1) {
+ return
+ }
+ data.forEach((result, i) => {
+ const seriesItem = {
+ name: '',
+ symbol: 'emptyCircle', // 去掉点
+ symbolSize: [2, 2],
+ showSymbol: false,
+ smooth: 0.2, // 曲线变平滑
+ data: [],
+ lineStyle: {
+ width: 1,
+ opacity: 0.9
+ },
+ type: 'line'
+ }
+ seriesItem.data = result.values.map((item) => {
+ return [item[0] * 1000, item[1]]
+ })
+ let host = ''// up,
+ let alias = ''
+ if (result.metric && Object.keys(result.metric).length > 0) {
+ const metric = Object.keys(result.metric)
+ if (metric.__name__) {
+ host = `${metric.__name__}{`// up,
+ }
+ metric.forEach((tag, i) => {
+ if (tag !== '__name__') {
+ host += `${tag}="${result.metric[tag]}",`
+ }
+ })
+ if (host.endsWith(',')) {
+ host = host.substr(0, host.length - 1)
+ }
+ if (metric.__name__) {
+ host += '}'
+ }
+ // 处理legend别名
+ // alias = this.dealLegendAlias(host, this.chartData.elements[index].legend)
+ if (!alias || alias === '') {
+ alias = host
+ }
+ } else {
+ alias = queryExpression[index]
+ }
+ seriesItem.name = alias + '-' + index
+ series.push(seriesItem)
+ legend.push({ name: seriesItem.name, alias: alias, isGray: false })
+ })
+ }
+ })
+ this.$refs.messageChart.setLegend(legend)
+ this.$refs.messageChart.setRandomColors(series.length)
+ if (!series.length) {
+ series = ''
+ }
+ this.$refs.messageChart.setSeries(series)
+ this.defaultChartVisible = true
+ this.$nextTick(() => {
+ this.$refs.messageChart.endLoading()
+ this.$refs.messageChart.resize()
+ })
+ }
+ },
+ showText (row) {
+ this.dialogShowText = true
+ this.dialogText = row.alertRule.trbShot
+ }
},
created () {
// 是否存在分页缓存
diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
index 53e9237d5..4f6da10ff 100644
--- a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
+++ b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue
@@ -54,10 +54,13 @@
{{$t("project.endpoint.dialogTitle")}}
-
+
+
+
+
@@ -177,7 +180,12 @@ export default {
chartUnit: 5,
requestIndex: 0,
viewAssetState: false,
- nowTime: ''
+ nowTime: '',
+ resultType: '',
+ logData: [],
+ chartLoading: false,
+ dialogShowText: false,
+ dialogText: ''
}
},
methods: {
@@ -199,7 +207,7 @@ export default {
chartUnitChange (unit) {
this.chartUnit = unit
this.$nextTick(() => {
- this.queryChartDate()
+ this.queryDate()
})
},
queryChartDate () {
@@ -228,6 +236,7 @@ export default {
this.legend = []
this.chartDatas = []
axios.all(axiosArr).then(res => {
+ this.chartLoading = false
try {
res.forEach((response, promIndex) => {
if (response.status === 200) {
@@ -430,7 +439,7 @@ export default {
this.graphShow = true
this.$nextTick(() => {
this.searchTime = [bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000), bus.computeTimezoneTime(new Date().getTime())]
- this.queryChartDate()
+ this.queryDate()
})
})
},
@@ -613,6 +622,168 @@ export default {
return [{}, { yAxis: this.currentMsg.alertRule.threshold }]
}
}
+ },
+ queryDate () {
+ this.chartLoading = true
+ if (this.currentMsg.alertRule.type === 1) {
+ this.resultType = 'matrix'
+ this.$nextTick(() => {
+ this.queryChartDate()
+ })
+ } else if (this.currentMsg.alertRule.type === 2) {
+ this.queryLogData(1000)
+ }
+ },
+ exportLog ({ limit, descending }) {
+ const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
+ const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
+ const params = {
+ logql: this.expressions,
+ start: start,
+ end: end,
+ direction: descending ? 'backward' : 'forward',
+ limit
+ }
+ axios.get('/logs/loki/export', { responseType: 'blob', params: params }).then(res => {
+ if (window.navigator.msSaveOrOpenBlob) {
+ // 兼容ie11
+ const blobObject = new Blob([res.data])
+ window.navigator.msSaveOrOpenBlob(blobObject, 'log')
+ } else {
+ const url = URL.createObjectURL(new Blob([res.data]))
+ const a = document.createElement('a')
+ document.body.appendChild(a) // 此处增加了将创建的添加到body当中
+ a.href = url
+ a.download = 'log'
+ a.target = '_blank'
+ a.click()
+ a.remove() // 将a标签移除
+ }
+ }, error => {
+ const $self = this
+ const reader = new FileReader()
+ reader.onload = function (event) {
+ const responseText = reader.result
+ const exception = JSON.parse(responseText)
+ if (exception.message) {
+ $self.$message.error(exception.message)
+ } else {
+ console.error(error)
+ }
+ }
+ reader.readAsText(error.response.data)
+ })
+ },
+ queryLogData (limit) { // log的chart和table是一个请求
+ if (!limit) {
+ limit = 1000
+ }
+ const start = this.searchTimeDialog[0] ? this.searchTimeDialog[0] : bus.computeTimezoneTime(new Date().getTime() - 1 * 60 * 60 * 1000)
+ const end = this.searchTimeDialog[1] ? this.searchTimeDialog[1] : bus.computeTimezoneTime(new Date().getTime())
+ this.expressions = [this.currentMsg.alertRule.expr]
+ this.$get('/logs/loki/api/v1/query_range?format=1&query=' + this.currentMsg.alertRule.expr + '&start=' + this.$stringTimeParseToUnix(start) + '&end=' + this.$stringTimeParseToUnix(end) + '&limit=' + limit).then(res => {
+ this.chartLoading = false
+ const logData = [res.data]
+ this.resultType = res.data.resultType
+ this.$nextTick(() => {
+ if (this.$refs.logDetail) {
+ this.$refs.logDetail.time = this.chartData.param.time
+ this.$refs.logDetail.wrapLines = this.chartData.param.wrapLines
+ this.$refs.logDetail.operations.descending = this.chartData.param.descending
+ }
+ // logData.forEach((item, index) => {
+ // item.result.forEach(result => {
+ // result.elements = this.expressions[index]
+ // })
+ // })
+ this.logData = logData
+ this.resultType === 'matrix' && this.loadLogGraph()
+ })
+ })
+ },
+ loadLogGraph () {
+ const graphData = this.logData.filter(l => l.resultType === 'matrix')
+ if (graphData && graphData.length > 0) {
+ this.$refs.messageChart.startLoading()
+ const queryExpression = []
+ let series = []
+ const legend = []
+ this.expressions.forEach((item, index) => {
+ if (item !== '') {
+ queryExpression.push(item)
+ }
+ })
+ this.logData.forEach((response, index) => {
+ if (response.resultType === 'matrix') {
+ const data = response.result
+ if (!data || data.length < 1) {
+ return
+ }
+ data.forEach((result, i) => {
+ const seriesItem = {
+ name: '',
+ symbol: 'emptyCircle', // 去掉点
+ symbolSize: [2, 2],
+ showSymbol: false,
+ smooth: 0.2, // 曲线变平滑
+ data: [],
+ lineStyle: {
+ width: 1,
+ opacity: 0.9
+ },
+ type: 'line'
+ }
+ seriesItem.data = result.values.map((item) => {
+ return [item[0] * 1000, item[1]]
+ })
+ let host = ''// up,
+ let alias = ''
+ if (result.metric && Object.keys(result.metric).length > 0) {
+ const metric = Object.keys(result.metric)
+ if (metric.__name__) {
+ host = `${metric.__name__}{`// up,
+ }
+ metric.forEach((tag, i) => {
+ if (tag !== '__name__') {
+ host += `${tag}="${result.metric[tag]}",`
+ }
+ })
+ if (host.endsWith(',')) {
+ host = host.substr(0, host.length - 1)
+ }
+ if (metric.__name__) {
+ host += '}'
+ }
+ // 处理legend别名
+ // alias = this.dealLegendAlias(host, this.chartData.elements[index].legend)
+ if (!alias || alias === '') {
+ alias = host
+ }
+ } else {
+ alias = queryExpression[index]
+ }
+ seriesItem.name = alias + '-' + index
+ series.push(seriesItem)
+ legend.push({ name: seriesItem.name, alias: alias, isGray: false })
+ })
+ }
+ })
+ this.$refs.messageChart.setLegend(legend)
+ this.$refs.messageChart.setRandomColors(series.length)
+ if (!series.length) {
+ series = ''
+ }
+ this.$refs.messageChart.setSeries(series)
+ this.defaultChartVisible = true
+ this.$nextTick(() => {
+ this.$refs.messageChart.endLoading()
+ this.$refs.messageChart.resize()
+ })
+ }
+ },
+ showText (row) {
+ this.dialogShowText = true
+ this.dialogText = row.alertRule.trbShot
}
}
}
diff --git a/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue b/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue
index 5529e3e2c..31cf28fb5 100644
--- a/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue
+++ b/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue
@@ -602,6 +602,9 @@ export default {
}
},
selectAlertRuleMetric (val) {
+ if (!this.editAlertRule.operator) {
+ this.editAlertRule.operator = '>'
+ }
if (val === 1) {
this.showSnmpTrap = true // showSnmpTrap 为 true 时显示 expr,threshold,unit
this.$refs.alertRuleForm.clearValidate('expr') // 移除from表单的 expr 验证
@@ -612,6 +615,10 @@ export default {
} else if (val === 3) {
this.showSnmpTrap = false // showSnmpTrap 为 false 时,展示 OID
this.editAlertRule.inr = ''
+ this.editAlertRule.last = ''
+ this.editAlertRule.unit = 0
+ this.editAlertRule.operator = ''
+ this.editAlertRule.threshold = ''
}
},
afterInitRich () {