NEZ-3166 fix: LogQL 输入框支持输入提示,高亮

This commit is contained in:
zhangyu
2023-10-24 18:11:21 +08:00
parent 725025990e
commit d34e16a2b2
9 changed files with 408 additions and 99 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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)
} }
}) })

View File

@@ -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) {

View File

@@ -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)
}) })
}, },

View 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

View File

@@ -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,14 +419,15 @@ 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)
.setComplete({
completeStrategy: new HistoryCompleteStrategy(
newCompleteStrategy({
remote: { remote: {
url: baseUrl + '/prom/', url: baseUrl + api,
fetchFn: (resource, options = {}) => { fetchFn: (resource, options = {}) => {
const params = options.body?.toString() const params = options.body?.toString()
const search = params ? `?${params}` : '' const search = params ? `?${params}` : ''
@@ -439,7 +441,121 @@ export default {
}, },
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,13 +1292,11 @@ 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()
}) })
} }
} }
}
}, },
beforeDestroy () { beforeDestroy () {
this.newView = null this.newView = null

View File

@@ -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) {