NEZ-3166 fix: LogQL 输入框支持输入提示,高亮
This commit is contained in:
@@ -191,7 +191,6 @@ export default {
|
|||||||
|
|
||||||
this.legends = []
|
this.legends = []
|
||||||
this.series = chartOption.series = this.handleTimeSeries(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends
|
this.series = chartOption.series = this.handleTimeSeries(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends
|
||||||
console.log(this.$lodash.cloneDeep( this.chartData), ' this.chartData')
|
|
||||||
chartOption.series.forEach(item => {
|
chartOption.series.forEach(item => {
|
||||||
if (item.lineStyle) {
|
if (item.lineStyle) {
|
||||||
item.lineStyle.width = this.lineOption.lineWidth
|
item.lineStyle.width = this.lineOption.lineWidth
|
||||||
@@ -238,7 +237,6 @@ export default {
|
|||||||
delete chartOption.tooltip.position
|
delete chartOption.tooltip.position
|
||||||
}
|
}
|
||||||
const option = this.renderYAxis(this.chartData, this.chartInfo)
|
const option = this.renderYAxis(this.chartData, this.chartInfo)
|
||||||
console.log(option)
|
|
||||||
chartOption.yAxis[0] = { ...chartOption.yAxis[0], ...option.yAxis[0] }
|
chartOption.yAxis[0] = { ...chartOption.yAxis[0], ...option.yAxis[0] }
|
||||||
chartOption.yAxis[1] = { ...chartOption.yAxis[1], ...option.yAxis[1] }
|
chartOption.yAxis[1] = { ...chartOption.yAxis[1], ...option.yAxis[1] }
|
||||||
if (chartOption.toolbox.feature) {
|
if (chartOption.toolbox.feature) {
|
||||||
@@ -612,7 +610,6 @@ export default {
|
|||||||
yAxisLabelFormatter (minValue, maxValue, copies, unit, dot) {
|
yAxisLabelFormatter (minValue, maxValue, copies, unit, dot) {
|
||||||
const self = this
|
const self = this
|
||||||
return function (val, index) {
|
return function (val, index) {
|
||||||
console.log(val)
|
|
||||||
let value = formatScientificNotation(val, 6)
|
let value = formatScientificNotation(val, 6)
|
||||||
if (!val) {
|
if (!val) {
|
||||||
value = 0
|
value = 0
|
||||||
|
|||||||
@@ -1153,8 +1153,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Interval: function (value, copies, unit, interValType) {
|
Interval: function (value, copies, unit, interValType) {
|
||||||
console.log(unit)
|
const type = unit.type || unit
|
||||||
const type = unit.type
|
|
||||||
const ascii = unit.ascii || 1000
|
const ascii = unit.ascii || 1000
|
||||||
if (!copies) {
|
if (!copies) {
|
||||||
copies = 1
|
copies = 1
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { formatScientificNotation } from '@/components/common/js/tools'
|
|||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
renderYAxis (chartDatas, chartInfo, type) {
|
renderYAxis (chartDatas, chartInfo, type) {
|
||||||
console.log(chartDatas, '1')
|
|
||||||
let chartData = lodash.cloneDeep(chartDatas)
|
let chartData = lodash.cloneDeep(chartDatas)
|
||||||
if (type === 'legend') {
|
if (type === 'legend') {
|
||||||
chartData.forEach(item => {
|
chartData.forEach(item => {
|
||||||
@@ -13,7 +12,6 @@ export default {
|
|||||||
})
|
})
|
||||||
chartData = chartData.map(item => [item])
|
chartData = chartData.map(item => [item])
|
||||||
}
|
}
|
||||||
console.log(chartDatas, '2')
|
|
||||||
const decimals = chartInfo.param.decimals || 2
|
const decimals = chartInfo.param.decimals || 2
|
||||||
const chartOption = {
|
const chartOption = {
|
||||||
yAxis: [
|
yAxis: [
|
||||||
@@ -32,7 +30,6 @@ export default {
|
|||||||
}
|
}
|
||||||
// 左y轴
|
// 左y轴
|
||||||
const leftData = chartData.filter(item => item[0] && !item[0].yAxisIndex)
|
const leftData = chartData.filter(item => item[0] && !item[0].yAxisIndex)
|
||||||
console.log(chartDatas, '3')
|
|
||||||
const leftInfo = this.getMinMaxFromData(leftData, chartInfo.unit, chartInfo.param) //
|
const leftInfo = this.getMinMaxFromData(leftData, chartInfo.unit, chartInfo.param) //
|
||||||
chartOption.yAxis[0].minInterval = chartDataFormat.Interval(leftInfo.maxValue, leftInfo.copies, leftInfo.unit, 'min')
|
chartOption.yAxis[0].minInterval = chartDataFormat.Interval(leftInfo.maxValue, leftInfo.copies, leftInfo.unit, 'min')
|
||||||
chartOption.yAxis[0].maxInterval = chartDataFormat.Interval(leftInfo.maxValue, leftInfo.copies, leftInfo.unit, 'max') * Math.ceil(this.series.length / 5)
|
chartOption.yAxis[0].maxInterval = chartDataFormat.Interval(leftInfo.maxValue, leftInfo.copies, leftInfo.unit, 'max') * Math.ceil(this.series.length / 5)
|
||||||
@@ -64,14 +61,9 @@ export default {
|
|||||||
// 如果全都为右y轴数据 则右y轴显示网格
|
// 如果全都为右y轴数据 则右y轴显示网格
|
||||||
const unit = chartDataFormat.getUnit(lodash.get(chartInfo, 'param.rightYAxis.unit', 2))
|
const unit = chartDataFormat.getUnit(lodash.get(chartInfo, 'param.rightYAxis.unit', 2))
|
||||||
const allRight = this.series.every(item => item.yAxisIndex == 1)
|
const allRight = this.series.every(item => item.yAxisIndex == 1)
|
||||||
console.log(allRight)
|
|
||||||
chartOption.yAxis[1].splitLine.show = allRight
|
chartOption.yAxis[1].splitLine.show = allRight
|
||||||
console.log(chartDatas, '4')
|
|
||||||
const rightData = chartData.filter(item => item[0] && item[0].yAxisIndex)
|
const rightData = chartData.filter(item => item[0] && item[0].yAxisIndex)
|
||||||
console.log(chartDatas, '5')
|
|
||||||
console.log(rightData)
|
|
||||||
const rightInfo = this.getMinMaxFromData(rightData, lodash.get(chartInfo, 'param.rightYAxis.unit', 2), lodash.get(chartInfo, 'param.rightYAxis', {}))//
|
const rightInfo = this.getMinMaxFromData(rightData, lodash.get(chartInfo, 'param.rightYAxis.unit', 2), lodash.get(chartInfo, 'param.rightYAxis', {}))//
|
||||||
console.log(rightInfo)
|
|
||||||
chartOption.yAxis[1].minInterval = chartDataFormat.Interval(rightInfo.maxValue, rightInfo.copies, rightInfo.unit, 'min')
|
chartOption.yAxis[1].minInterval = chartDataFormat.Interval(rightInfo.maxValue, rightInfo.copies, rightInfo.unit, 'min')
|
||||||
chartOption.yAxis[1].maxInterval = chartDataFormat.Interval(rightInfo.maxValue, rightInfo.copies, rightInfo.unit, 'max') * Math.ceil(this.series.length / 5)
|
chartOption.yAxis[1].maxInterval = chartDataFormat.Interval(rightInfo.maxValue, rightInfo.copies, rightInfo.unit, 'max') * Math.ceil(this.series.length / 5)
|
||||||
if (chartInfo.param.stack) {
|
if (chartInfo.param.stack) {
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(response)
|
|
||||||
this.$message.error(response.msg || response.error)
|
this.$message.error(response.msg || response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ export default {
|
|||||||
momentTz (timestamp, fmt) { // moment 转化时间戳为str
|
momentTz (timestamp, fmt) { // moment 转化时间戳为str
|
||||||
const offset = localStorage.getItem('nz-sys-timezone')
|
const offset = localStorage.getItem('nz-sys-timezone')
|
||||||
const format = fmt || localStorage.getItem('nz-default-dateFormat')
|
const format = fmt || localStorage.getItem('nz-default-dateFormat')
|
||||||
console.log(timestamp, fmt, offset, localStorage.getItem('nz-default-dateFormat'), format)
|
|
||||||
return moment.tz(timestamp, offset).format(format)
|
return moment.tz(timestamp, offset).format(format)
|
||||||
},
|
},
|
||||||
momentStrToTimestamp (str, fmt) {
|
momentStrToTimestamp (str, fmt) {
|
||||||
|
|||||||
@@ -3885,10 +3885,12 @@ export default {
|
|||||||
this.$refs.logDetail && this.$refs.logDetail.resetOperation()
|
this.$refs.logDetail && this.$refs.logDetail.resetOperation()
|
||||||
if (this.expressions.length > 0) {
|
if (this.expressions.length > 0) {
|
||||||
const requestArr = []
|
const requestArr = []
|
||||||
|
const realArr = [] // 记录原始位置
|
||||||
// 过滤掉state为0的元素
|
// 过滤掉state为0的元素
|
||||||
this.expressions.forEach((item, index) => {
|
this.expressions.forEach((item, index) => {
|
||||||
if (item != '' && this.promqlKeys[index].state && item) {
|
if (item != '' && this.promqlKeys[index].state && item) {
|
||||||
requestArr.push(this.$get('/logs/loki/api/v1/query_range?format=1&query=' + encodeURIComponent(item) + '&start=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[0])) + '&end=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1])) + '&limit=' + limit))
|
requestArr.push(this.$get('/logs/loki/api/v1/query_range?format=1&query=' + encodeURIComponent(item) + '&start=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[0])) + '&end=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1])) + '&limit=' + limit))
|
||||||
|
realArr.push(index)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (requestArr.length > 0) {
|
if (requestArr.length > 0) {
|
||||||
@@ -3896,18 +3898,22 @@ export default {
|
|||||||
this.saveDisabled = false
|
this.saveDisabled = false
|
||||||
}
|
}
|
||||||
axios.all(requestArr).then(res => {
|
axios.all(requestArr).then(res => {
|
||||||
this.postHistory()
|
console.log(res)
|
||||||
this.chartLoading = false
|
this.chartLoading = false
|
||||||
const errorRowIndex = []
|
const errorRowIndex = []
|
||||||
res.forEach((r, i) => {
|
res.forEach((r, i) => {
|
||||||
if (typeof r === 'string') {
|
if (r.code !== 200) {
|
||||||
errorRowIndex.push(i)
|
errorRowIndex.push(i)
|
||||||
|
this.promqlKeys[realArr[i]].isResError = true
|
||||||
|
} else {
|
||||||
|
this.promqlKeys[realArr[i]].isResError = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (errorRowIndex.length > 0) {
|
if (errorRowIndex.length > 0) {
|
||||||
this.$message.error(this.$t('tip.errorInRow') + ': ' + errorRowIndex.map(e => e + 1).join(' ,'))
|
this.$message.error(this.$t('tip.errorInRow') + ': ' + errorRowIndex.map(e => e + 1).join(' ,'))
|
||||||
res = res.filter((r, i) => errorRowIndex.indexOf(i) === -1)
|
res = res.filter((r, i) => errorRowIndex.indexOf(i) === -1)
|
||||||
}
|
}
|
||||||
|
this.postHistory()
|
||||||
if (res.length > 0) {
|
if (res.length > 0) {
|
||||||
const logData = res.map(r => r.data)
|
const logData = res.map(r => r.data)
|
||||||
if (logData[0].result.length > 0) {
|
if (logData[0].result.length > 0) {
|
||||||
@@ -3941,6 +3947,8 @@ export default {
|
|||||||
this.logData = logData
|
this.logData = logData
|
||||||
hasGraph && this.loadLogGraph()
|
hasGraph && this.loadLogGraph()
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
this.showIntroduce = true
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.chartLoading = false
|
this.chartLoading = false
|
||||||
@@ -4370,7 +4378,6 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
const promiseArr = []
|
const promiseArr = []
|
||||||
this.expressions.forEach((item, index) => {
|
this.expressions.forEach((item, index) => {
|
||||||
console.log(item)
|
|
||||||
if (item != '' && this.promqlKeys[index].state && item) {
|
if (item != '' && this.promqlKeys[index].state && item) {
|
||||||
promiseArr.push(this.$get('logs/loki/api/v1/format_query', { query: item }))
|
promiseArr.push(this.$get('logs/loki/api/v1/format_query', { query: item }))
|
||||||
} else {
|
} else {
|
||||||
@@ -4386,7 +4393,6 @@ export default {
|
|||||||
this.updatePath()
|
this.updatePath()
|
||||||
},
|
},
|
||||||
initQueryFromPath () {
|
initQueryFromPath () {
|
||||||
console.log('initQueryFromPath')
|
|
||||||
const param = this.$route.query[this.position]
|
const param = this.$route.query[this.position]
|
||||||
if (param) {
|
if (param) {
|
||||||
const data = JSON.parse(param)
|
const data = JSON.parse(param)
|
||||||
@@ -4412,7 +4418,6 @@ export default {
|
|||||||
this.promqlCount = data.queries.length
|
this.promqlCount = data.queries.length
|
||||||
data.queries.forEach((item, index) => {
|
data.queries.forEach((item, index) => {
|
||||||
this.$set(this.expressions, index, item.expr)
|
this.$set(this.expressions, index, item.expr)
|
||||||
console.log(item)
|
|
||||||
this.promqlKeys[index] = {
|
this.promqlKeys[index] = {
|
||||||
...item,
|
...item,
|
||||||
id: getUUID(),
|
id: getUUID(),
|
||||||
@@ -4571,7 +4576,7 @@ export default {
|
|||||||
})
|
})
|
||||||
this.lastHistory.forEach((item) => {
|
this.lastHistory.forEach((item) => {
|
||||||
const findItem = arr.find(history => history.id == item.id)
|
const findItem = arr.find(history => history.id == item.id)
|
||||||
if (findItem && findItem.queryValue !== item.value) {
|
if (findItem && findItem.queryValue !== item.value && !findItem.isError && !findItem.isResError) {
|
||||||
postArr.push({
|
postArr.push({
|
||||||
queryKey,
|
queryKey,
|
||||||
queryValue: findItem.queryValue
|
queryValue: findItem.queryValue
|
||||||
@@ -4580,7 +4585,7 @@ export default {
|
|||||||
})
|
})
|
||||||
arr.forEach(item => {
|
arr.forEach(item => {
|
||||||
const findItem = this.lastHistory.find(history => history.id == item.id)
|
const findItem = this.lastHistory.find(history => history.id == item.id)
|
||||||
if (!findItem) {
|
if (!findItem && !item.isResError) {
|
||||||
postArr.push({
|
postArr.push({
|
||||||
queryKey,
|
queryKey,
|
||||||
queryValue: item.queryValue
|
queryValue: item.queryValue
|
||||||
@@ -4588,8 +4593,8 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
postArr = postArr.filter(item => item.queryValue)
|
postArr = postArr.filter(item => item.queryValue)
|
||||||
|
console.log(postArr)
|
||||||
this.$post('/sys/user/queryHistory', postArr).then(res => {
|
this.$post('/sys/user/queryHistory', postArr).then(res => {
|
||||||
console.log(res)
|
|
||||||
this.lastHistory = this.$lodash.cloneDeep(postArr)
|
this.lastHistory = this.$lodash.cloneDeep(postArr)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
178
nezha-fronted/src/components/page/dashboard/explore/logqlHint.js
Normal file
178
nezha-fronted/src/components/page/dashboard/explore/logqlHint.js
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
const logqlHint = {
|
||||||
|
functions: [{
|
||||||
|
label: 'rate',
|
||||||
|
detail: 'functions',
|
||||||
|
info: 'Calculates the number of entries per second.',
|
||||||
|
type: 'functions'
|
||||||
|
}, {
|
||||||
|
label: 'count_over_time',
|
||||||
|
detail: 'functions',
|
||||||
|
info: 'Counts the entries for each log stream within the given range.',
|
||||||
|
type: 'functions'
|
||||||
|
}, {
|
||||||
|
label: 'bytes_rate',
|
||||||
|
detail: 'functions',
|
||||||
|
info: 'Calculates the number of bytes per second for each stream.',
|
||||||
|
type: 'functions'
|
||||||
|
}, {
|
||||||
|
label: 'bytes_over_time',
|
||||||
|
detail: 'functions',
|
||||||
|
info: 'counts the amount of bytes used by each log stream for a given range.',
|
||||||
|
type: 'functions'
|
||||||
|
}, {
|
||||||
|
label: 'absent_over_time',
|
||||||
|
detail: 'functions',
|
||||||
|
info: 'returns an empty vector if the range vector passed to it has any elements and a 1-element vector with the value 1 if the range vector passed to it has no elements. (absent_over_time is useful for alerting on when no time series and logs stream exist for label combination for a certain amount of time.)',
|
||||||
|
type: 'functions'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
aggregateOp: [{
|
||||||
|
label: 'duration_seconds',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'which will convert the label value in seconds from the go duration format (e.g 5m, 24s30ms).',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'duration',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'which will convert the label value in seconds from the go duration format (e.g 5m, 24s30ms).',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'bytes',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'which will convert the label value to raw bytes applying the bytes unit (e.g. 5 MiB, 3k, 1G).',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'rate',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'calculates per second rate of the sum of all values in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'rate_counter',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'calculates per second rate of the values in the specified interval and treating them as “counter metric”.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'sum_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the sum of all values in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'avg_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the average value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'max_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the maximum value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'min_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the minimum value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'min_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the minimum value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'first_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the first value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'last_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the last value of all points in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'stdvar_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the population standard variance of the values in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'stddev_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the population standard deviation of the values in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'quantile_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'the φ-quantile (0 ≤ φ ≤ 1) of the values in the specified interval.',
|
||||||
|
type: 'keyword'
|
||||||
|
}, {
|
||||||
|
label: 'absent_over_time',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'returns an empty vector if the range vector passed to it has any elements and a 1-element vector with the value 1 if the range vector passed to it has no elements. (absent_over_time is useful for alerting on when no time series and logs stream exist for label combination for a certain amount of time.)',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'sum',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Calculate sum over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'avg',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Calculate the average over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'min',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Select minimum over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'max',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Select maximum over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'stddev',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Calculate the population standard deviation over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'stdvar',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Calculate the population standard variance over labels',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'count',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Count number of elements in the vector',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'topk',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Select largest k elements by sample value',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bottomk',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Select smallest k elements by sample value',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'sort',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'returns vector elements sorted by their sample values, in ascending order.',
|
||||||
|
type: 'keyword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'sort_desc',
|
||||||
|
detail: 'aggregation',
|
||||||
|
info: 'Same as sort, but sorts in descending order.',
|
||||||
|
type: 'keyword'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
export default logqlHint
|
||||||
@@ -10,30 +10,29 @@
|
|||||||
@click="dropDownVisible = false"
|
@click="dropDownVisible = false"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:id="pqid + 'editor'+index"
|
:id="pqid + 'editor'+index + type"
|
||||||
v-if="type !== 'log'"
|
|
||||||
class="not-fixed-height no-resize no-close"
|
class="not-fixed-height no-resize no-close"
|
||||||
style="padding-right: 24px;box-sizing: border-box"
|
style="padding-right: 24px;box-sizing: border-box"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">
|
<!-- <div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">-->
|
||||||
<MonacoEditor
|
<!-- <MonacoEditor-->
|
||||||
v-if="type == 'log'"
|
<!-- v-if="type == 'log'"-->
|
||||||
v-model="expressionList[index]"
|
<!-- v-model="expressionList[index]"-->
|
||||||
theme="nz"
|
<!-- theme="nz"-->
|
||||||
class="not-fixed-height no-resize"
|
<!-- class="not-fixed-height no-resize"-->
|
||||||
ref="monacoEditor"
|
<!-- ref="monacoEditor"-->
|
||||||
style="width: calc(100% - 24px)"
|
<!-- style="width: calc(100% - 24px)"-->
|
||||||
:style="{
|
<!-- :style="{-->
|
||||||
height: monacoEditorHeight + 'px'
|
<!-- height: monacoEditorHeight + 'px'-->
|
||||||
}"
|
<!-- }"-->
|
||||||
language="logql"
|
<!-- language="logql"-->
|
||||||
:options="MONACO_EDITOR_OPTIONS"
|
<!-- :options="MONACO_EDITOR_OPTIONS"-->
|
||||||
@editorWillMount="handelBeforeMount"
|
<!-- @editorWillMount="handelBeforeMount"-->
|
||||||
@editorDidMount="handleMount"
|
<!-- @editorDidMount="handleMount"-->
|
||||||
@change="expressionChange"
|
<!-- @change="expressionChange"-->
|
||||||
/>
|
<!-- />-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
|
||||||
<div v-if="errorMsg" class="append-msg error" style="position: absolute">
|
<div v-if="errorMsg" class="append-msg error" style="position: absolute">
|
||||||
<span>{{ errorMsg }}</span>
|
<span>{{ errorMsg }}</span>
|
||||||
@@ -68,30 +67,29 @@
|
|||||||
v-if="plugins.indexOf('metric-input') > -1"
|
v-if="plugins.indexOf('metric-input') > -1"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:id="pqid + 'editor'+index"
|
:id="pqid + 'editor'+index + type"
|
||||||
v-if="type !== 'log'"
|
|
||||||
class="not-fixed-height no-resize no-close"
|
class="not-fixed-height no-resize no-close"
|
||||||
style="padding-right: 24px;box-sizing: border-box"
|
style="padding-right: 24px;box-sizing: border-box"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">
|
<!-- <div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">-->
|
||||||
<MonacoEditor
|
<!-- <MonacoEditor-->
|
||||||
v-if="type == 'log'"
|
<!-- v-if="type == 'log'"-->
|
||||||
v-model="expressionList[index]"
|
<!-- v-model="expressionList[index]"-->
|
||||||
theme="nz"
|
<!-- theme="nz"-->
|
||||||
class="not-fixed-height no-resize"
|
<!-- class="not-fixed-height no-resize"-->
|
||||||
ref="monacoEditor"
|
<!-- ref="monacoEditor"-->
|
||||||
style="width: calc(100% - 24px)"
|
<!-- style="width: calc(100% - 24px)"-->
|
||||||
:style="{
|
<!-- :style="{-->
|
||||||
height: monacoEditorHeight + 'px'
|
<!-- height: monacoEditorHeight + 'px'-->
|
||||||
}"
|
<!-- }"-->
|
||||||
language="logql"
|
<!-- language="logql"-->
|
||||||
:options="MONACO_EDITOR_OPTIONS"
|
<!-- :options="MONACO_EDITOR_OPTIONS"-->
|
||||||
@editorWillMount="handelBeforeMount"
|
<!-- @editorWillMount="handelBeforeMount"-->
|
||||||
@editorDidMount="handleMount"
|
<!-- @editorDidMount="handleMount"-->
|
||||||
@change="expressionChange"
|
<!-- @change="expressionChange"-->
|
||||||
/>
|
<!-- />-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
<div class="append-msg error" v-if="errorMsg">
|
<div class="append-msg error" v-if="errorMsg">
|
||||||
<span>{{ errorMsg }}</span>
|
<span>{{ errorMsg }}</span>
|
||||||
@@ -254,6 +252,8 @@ import { get } from '@/http'
|
|||||||
import { PromQLExtension } from '@prometheus-io/codemirror-promql'
|
import { PromQLExtension } from '@prometheus-io/codemirror-promql'
|
||||||
import { baseTheme, promqlHighlighter, lightTheme } from './CMTheme.tsx'
|
import { baseTheme, promqlHighlighter, lightTheme } from './CMTheme.tsx'
|
||||||
import { newCompleteStrategy } from '@prometheus-io/codemirror-promql/dist/esm/complete'
|
import { newCompleteStrategy } from '@prometheus-io/codemirror-promql/dist/esm/complete'
|
||||||
|
import { analyzeCompletion, computeStartCompletePosition, ContextKind } from '@prometheus-io/codemirror-promql/dist/esm/complete/hybrid'
|
||||||
|
import { aggregateOpModifierTerms, aggregateOpTerms, atModifierTerms, binOpModifierTerms, binOpTerms, durationTerms, functionIdentifierTerms, matchOpTerms, numberTerms } from '@prometheus-io/codemirror-promql/dist/esm/complete/promql.terms'
|
||||||
// import {basicSetup} from '@codemirror/basic-setup';
|
// import {basicSetup} from '@codemirror/basic-setup';
|
||||||
import { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view'
|
import { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view'
|
||||||
import { EditorState, Prec, Compartment } from '@codemirror/state'
|
import { EditorState, Prec, Compartment } from '@codemirror/state'
|
||||||
@@ -261,6 +261,7 @@ import { bracketMatching, indentOnInput, syntaxHighlighting, syntaxTree } from '
|
|||||||
import { defaultKeymap, history, historyKeymap, insertNewlineAndIndent } from '@codemirror/commands'
|
import { defaultKeymap, history, historyKeymap, insertNewlineAndIndent } from '@codemirror/commands'
|
||||||
import { highlightSelectionMatches } from '@codemirror/search'
|
import { highlightSelectionMatches } from '@codemirror/search'
|
||||||
import { lintKeymap } from '@codemirror/lint'
|
import { lintKeymap } from '@codemirror/lint'
|
||||||
|
import logqlHint from './logqlHint'
|
||||||
import {
|
import {
|
||||||
autocompletion,
|
autocompletion,
|
||||||
completionKeymap,
|
completionKeymap,
|
||||||
@@ -418,28 +419,143 @@ export default {
|
|||||||
const defaultHeaders = {
|
const defaultHeaders = {
|
||||||
Authorization: localStorage.getItem('nz-token')
|
Authorization: localStorage.getItem('nz-token')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let api = '/prom/'
|
||||||
|
if (this.type === 'log') {
|
||||||
|
api = '/logs/loki/'
|
||||||
|
}
|
||||||
const promqlExtension = new PromQLExtension()
|
const promqlExtension = new PromQLExtension()
|
||||||
.activateCompletion(true)
|
const completeStrategy = newCompleteStrategy({
|
||||||
.activateLinter(true)
|
remote: {
|
||||||
.setComplete({
|
url: baseUrl + api,
|
||||||
completeStrategy: new HistoryCompleteStrategy(
|
fetchFn: (resource, options = {}) => {
|
||||||
newCompleteStrategy({
|
const params = options.body?.toString()
|
||||||
remote: {
|
const search = params ? `?${params}` : ''
|
||||||
url: baseUrl + '/prom/',
|
return fetch(resource + search, {
|
||||||
fetchFn: (resource, options = {}) => {
|
method: 'Get',
|
||||||
const params = options.body?.toString()
|
headers: new Headers(
|
||||||
const search = params ? `?${params}` : ''
|
defaultHeaders
|
||||||
return fetch(resource + search, {
|
)
|
||||||
method: 'Get',
|
|
||||||
headers: new Headers(
|
|
||||||
defaultHeaders
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
maxMetricsMetadata: 99999
|
|
||||||
})
|
})
|
||||||
)
|
}
|
||||||
|
},
|
||||||
|
maxMetricsMetadata: 99999
|
||||||
|
})
|
||||||
|
if (this.type === 'log') {
|
||||||
|
const autocompleteNodes = {
|
||||||
|
matchOp: matchOpTerms,
|
||||||
|
binOp: binOpTerms,
|
||||||
|
duration: durationTerms,
|
||||||
|
binOpModifier: [],
|
||||||
|
atModifier: [],
|
||||||
|
functionIdentifier: logqlHint.functions,
|
||||||
|
aggregateOp: logqlHint.aggregateOp,
|
||||||
|
aggregateOpModifier: aggregateOpModifierTerms,
|
||||||
|
number: numberTerms
|
||||||
|
}
|
||||||
|
completeStrategy.promQL = function (context) {
|
||||||
|
const { state, pos } = context
|
||||||
|
const tree = syntaxTree(state).resolve(pos, -1)
|
||||||
|
const contexts = analyzeCompletion(state, tree)
|
||||||
|
let asyncResult = Promise.resolve([])
|
||||||
|
let completeSnippet = false
|
||||||
|
const span = true
|
||||||
|
for (const context of contexts) {
|
||||||
|
switch (context.kind) {
|
||||||
|
case ContextKind.Aggregation:
|
||||||
|
completeSnippet = true
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.aggregateOp)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.Function:
|
||||||
|
completeSnippet = true
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.functionIdentifier)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.BinOpModifier:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.binOpModifier)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.BinOp:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.binOp)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.MatchOp:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.matchOp)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.AggregateOpModifier:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.aggregateOpModifier)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.Duration:
|
||||||
|
span = false
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.duration)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.Offset:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat([{ label: 'offset' }])
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.Bool:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat([{ label: 'bool' }])
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.AtModifiers:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.atModifier)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.Number:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return result.concat(autocompleteNodes.number)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.MetricName:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return this.autocompleteMetricName(result, context)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.LabelName:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return this.autocompleteLabelName(result, context)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case ContextKind.LabelValue:
|
||||||
|
asyncResult = asyncResult.then((result) => {
|
||||||
|
return this.autocompleteLabelValue(result, context)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return asyncResult.then((result) => {
|
||||||
|
return arrayToCompletionResult(result, computeStartCompletePosition(tree, pos), pos, completeSnippet, span)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function arrayToCompletionResult (data, from, to, includeSnippet = false, span = true) {
|
||||||
|
const options = data
|
||||||
|
// options.push(...logqlHint);
|
||||||
|
return {
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
options: options,
|
||||||
|
validFor: span ? /^[a-zA-Z0-9_:]+$/ : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(JSON.stringify(promqlExtension.promQL()))
|
||||||
|
promqlExtension.activateCompletion(true)
|
||||||
|
.activateLinter(!(this.type === 'log'))
|
||||||
|
.setComplete({
|
||||||
|
completeStrategy: new HistoryCompleteStrategy(completeStrategy)
|
||||||
|
|
||||||
})
|
})
|
||||||
function HistoryCompleteStrategy (CompleteStrategy) {
|
function HistoryCompleteStrategy (CompleteStrategy) {
|
||||||
@@ -467,6 +583,7 @@ export default {
|
|||||||
})),
|
})),
|
||||||
span: /^[a-zA-Z0-9_:]+$/
|
span: /^[a-zA-Z0-9_:]+$/
|
||||||
}
|
}
|
||||||
|
console.log(res.options)
|
||||||
// 过滤 非logs的函数
|
// 过滤 非logs的函数
|
||||||
if (res !== null) {
|
if (res !== null) {
|
||||||
historyItems.options = historyItems.options.concat(res.options)
|
historyItems.options = historyItems.options.concat(res.options)
|
||||||
@@ -485,6 +602,10 @@ export default {
|
|||||||
lightTheme
|
lightTheme
|
||||||
]
|
]
|
||||||
if (!this.newView) {
|
if (!this.newView) {
|
||||||
|
let placeholderStr = 'Metrics Expression (press Shift+Enter for newlines)'
|
||||||
|
if (this.type === 'log') {
|
||||||
|
placeholderStr = 'Logs Expression (press Shift+Enter for newlines)'
|
||||||
|
}
|
||||||
const EditorViewstate = EditorState.create({
|
const EditorViewstate = EditorState.create({
|
||||||
doc: self.codeMirrorValue[self.index],
|
doc: self.codeMirrorValue[self.index],
|
||||||
extensions: [
|
extensions: [
|
||||||
@@ -500,7 +621,7 @@ export default {
|
|||||||
highlightSelectionMatches(),
|
highlightSelectionMatches(),
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, ...lintKeymap]),
|
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, ...lintKeymap]),
|
||||||
placeholder('Expression (press Shift+Enter for newlines)'),
|
placeholder(placeholderStr),
|
||||||
dynamicConfigCompartment.of(dynamicConfig),
|
dynamicConfigCompartment.of(dynamicConfig),
|
||||||
keymap.of([
|
keymap.of([
|
||||||
{
|
{
|
||||||
@@ -539,7 +660,7 @@ export default {
|
|||||||
const view = new EditorView({
|
const view = new EditorView({
|
||||||
state: EditorViewstate,
|
state: EditorViewstate,
|
||||||
// parent: document.getElementById('editor')
|
// parent: document.getElementById('editor')
|
||||||
parent: document.getElementById(this.pqid + 'editor' + self.index)
|
parent: document.getElementById(this.pqid + 'editor' + self.index + this.type)
|
||||||
})
|
})
|
||||||
self.newView = view
|
self.newView = view
|
||||||
} else {
|
} else {
|
||||||
@@ -1090,14 +1211,35 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectLog (str) {
|
selectLog (item) {
|
||||||
if (!str || str.length === 0) return
|
if (!item.id) {
|
||||||
this.expressionList[this.index] = str
|
this.metricChangeNew(item.name)
|
||||||
this.codeMirrorValue[this.index] = str
|
} else if (item.id) {
|
||||||
this.dropDownVisible = false
|
this.dropDownVisible = false
|
||||||
this.$emit('change', str)
|
this.$get('/expression/tmpl/' + item.id).then(res => {
|
||||||
this.$forceUpdate()
|
if (res.code === 200) {
|
||||||
this.cascaderValue = ''
|
if (!res.data.vars || !res.data.vars.length) {
|
||||||
|
this.metricChange(item.expression)
|
||||||
|
this.initCodeMirror()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.data.vars.forEach(item => {
|
||||||
|
res.data[item] = ''
|
||||||
|
const arr = item.split('.')
|
||||||
|
const keyword = arr[0].toLowerCase()
|
||||||
|
this.getAllOptins(keyword, keyword + 'Option')
|
||||||
|
})
|
||||||
|
this.tempBox = {
|
||||||
|
...this.tempBox,
|
||||||
|
...res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.tempBoxShow = true
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -1150,11 +1292,9 @@ export default {
|
|||||||
deep: true,
|
deep: true,
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler (n) {
|
handler (n) {
|
||||||
if (n !== 'log') {
|
this.$nextTick(() => {
|
||||||
this.$nextTick(() => {
|
this.initCodeMirror()
|
||||||
this.initCodeMirror()
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ export default {
|
|||||||
this.hideMe()
|
this.hideMe()
|
||||||
},
|
},
|
||||||
selectLog () {
|
selectLog () {
|
||||||
this.$emit('selectLog', this.logFinalStr)
|
this.$emit('selectLog', { name: this.logFinalStr })
|
||||||
this.hideMe()
|
this.hideMe()
|
||||||
},
|
},
|
||||||
copyItem (value) {
|
copyItem (value) {
|
||||||
|
|||||||
Reference in New Issue
Block a user