diff --git a/nezha-fronted/src/components/common/mixin/promqlInput.js b/nezha-fronted/src/components/common/mixin/promqlInput.js index 16c136758..5abc91335 100644 --- a/nezha-fronted/src/components/common/mixin/promqlInput.js +++ b/nezha-fronted/src/components/common/mixin/promqlInput.js @@ -2,7 +2,40 @@ export default { data () { return { metricOptions: [], - showTemp: true + showTemp: true, + metricArr: [ + { expr: 'rate' }, + { expr: 'count_over_time' }, + { expr: 'bytes_rate' }, + { expr: 'bytes_over_time' }, + { expr: 'absent_over_time' }, + { expr: 'duration_seconds' }, + { expr: 'bytes' }, + { expr: 'rate_counter' }, + { expr: 'sum_over_time' }, + { expr: 'avg_over_time' }, + { expr: 'max_over_time' }, + { expr: 'min_over_time' }, + { expr: 'first_over_time' }, + { expr: 'last_over_time' }, + { expr: 'stdvar_over_time' }, + { expr: 'stddev_over_time' }, + { expr: 'quantile_over_time' }, + { expr: 'absent_over_time' }, + { expr: 'sum' }, + { expr: 'avg' }, + { expr: 'min' }, + { expr: 'max' }, + { expr: 'stddev' }, + { expr: 'stdvar' }, + { expr: 'count' }, + { expr: 'topk' }, + { expr: 'bottomk' }, + { expr: 'sort' }, + { expr: 'sort_desc' }, + { expr: 'vector' } + ] + } }, methods: { @@ -68,6 +101,13 @@ export default { }) } }) + }, + validateMetric (text) { + const flag = this.metricArr.some(item => { + const regex = new RegExp(`${item.expr}\\(.*\\)`) + return regex.test(text) + }) + return flag } }, watch: { diff --git a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue index 43b789ad9..3ac2a5a93 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue @@ -259,7 +259,18 @@ - + + @@ -3757,7 +3768,92 @@ export default { reader.readAsText(error.response.data) }) }, - queryLogData (limit) { // log的chart和table是一个请求 + queryLogChart () { + this.$refs.logDetail.$refs.logChart.startLoading() + const requestArr = [] + const start = this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[0])) + const end = this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1])) + // 当不是 指标查询表达式时,除直接查询 用户输入表达式外,另查询 sum by (level) (count_over_time($_expression[$_step])) + this.expressions.forEach((item, index) => { + if (item != '' && this.promqlKeys[index].state) { + const isMetric = this.validateMetric(item) + if (!isMetric) { + const step = bus.getStep(bus.formateTimeToTime(this.filterTime[0]), bus.formateTimeToTime(this.filterTime[1])) + const supplementaryExpr = `sum by (level) (count_over_time(${item}[${step}]))` + requestArr.push(this.$get('/logs/loki/api/v1/query_range?query=' + encodeURIComponent(supplementaryExpr) + '&start=' + start + '&end=' + end)) + } + } + }) + axios.all(requestArr).then(res => { + res = res.filter((r, i) => r.code === 200) + if (res.length > 0) { + let series = [] + let legend = [] + const seriesItem = { + type: 'line', + name: '', + symbol: 'emptyCircle', // 去掉点 + symbolSize: 8, + showSymbol: false, + smooth: 0.2, // 曲线变平滑 + data: [], + lineStyle: { + width: 2, + opacity: 0.9 + }, + emphasis: { + focus: 'none' + }, + blur: { + lineStyle: { + opacity: 0.3 + }, + itemStyle: { + opacity: 1 + } + } + } + function mergeAndSort (arr) { + const mergedMap = new Map() + // 合并数组,根据时间戳累加值 + arr.forEach(([timestamp, value]) => { + if (mergedMap.has(timestamp)) { + mergedMap.set(timestamp, mergedMap.get(timestamp) + Number(value)) + } else { + mergedMap.set(timestamp, Number(value)) + } + }) + // 将Map转换为二维数组,并根据时间戳排序 + const mergedArray = Array.from(mergedMap.entries()).sort((a, b) => a[0] - b[0]) + return mergedArray + } + const logData = res.map(r => r.data) + logData.forEach((response) => { + const data = response.result + data.forEach((result, i) => { + seriesItem.name = 'logs' + const values = result.values.map((item) => { + return [item[0] * 1000, item[1]] + }) + seriesItem.data.push(...values) + }) + }) + seriesItem.data = mergeAndSort(seriesItem.data) + series = [seriesItem] + legend = [{ name: seriesItem.name, alias: seriesItem.name, isGray: false }] + this.$nextTick(() => { + this.$refs.logDetail.$refs.logChart.setLegend(legend) + this.$refs.logDetail.$refs.logChart.setLogColor(series.length) + if (!series.length) { + series = '' + } + this.$refs.logDetail.$refs.logChart.setSeries(series) + this.$refs.logDetail.$refs.logChart.endLoading() + }) + } + }) + }, + queryLogData (limit) { this.chartLoading = true if (!limit) { limit = this.$refs.logDetail ? this.$refs.logDetail.getLimit() : 100 @@ -3836,7 +3932,7 @@ export default { let series = [] const legend = [] this.expressions.forEach((item, index) => { - if (item !== '') { + if (item !== '' && this.promqlKeys[index].state) { promqlInputIndexs.push(index) queryExpression.push(item) } @@ -4165,6 +4261,7 @@ export default { this.storeHistory() } else { this.queryLogData() + this.queryLogChart() } } this.updatePath() diff --git a/nezha-fronted/src/components/page/dashboard/explore/exploreItemHtml.vue b/nezha-fronted/src/components/page/dashboard/explore/exploreItemHtml.vue index 612020fac..f5d20a626 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/exploreItemHtml.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/exploreItemHtml.vue @@ -612,9 +612,16 @@ export default { const graphData = this.logData.filter(l => l.resultType === 'matrix') if (graphData && graphData.length > 0) { this.$refs.logChart.startLoading() + const promqlInputIndexs = [] const queryExpression = [] let series = [] const legend = [] + this.dataJson.data.forEach((item, index) => { + if (item.expression !== '' && item.state) { + promqlInputIndexs.push(index) + queryExpression.push(item.expression) + } + }) this.logData.forEach((response, index) => { if (response.resultType === 'matrix') { const data = response.result diff --git a/nezha-fronted/src/components/page/dashboard/explore/logTab.vue b/nezha-fronted/src/components/page/dashboard/explore/logTab.vue index 26a853a72..924423e1a 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/logTab.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/logTab.vue @@ -1,6 +1,7 @@