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.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 => {
if (item.lineStyle) {
item.lineStyle.width = this.lineOption.lineWidth
@@ -238,7 +237,6 @@ export default {
delete chartOption.tooltip.position
}
const option = this.renderYAxis(this.chartData, this.chartInfo)
console.log(option)
chartOption.yAxis[0] = { ...chartOption.yAxis[0], ...option.yAxis[0] }
chartOption.yAxis[1] = { ...chartOption.yAxis[1], ...option.yAxis[1] }
if (chartOption.toolbox.feature) {
@@ -612,7 +610,6 @@ export default {
yAxisLabelFormatter (minValue, maxValue, copies, unit, dot) {
const self = this
return function (val, index) {
console.log(val)
let value = formatScientificNotation(val, 6)
if (!val) {
value = 0

View File

@@ -1153,8 +1153,7 @@ export default {
}
},
Interval: function (value, copies, unit, interValType) {
console.log(unit)
const type = unit.type
const type = unit.type || unit
const ascii = unit.ascii || 1000
if (!copies) {
copies = 1

View File

@@ -5,7 +5,6 @@ import { formatScientificNotation } from '@/components/common/js/tools'
export default {
methods: {
renderYAxis (chartDatas, chartInfo, type) {
console.log(chartDatas, '1')
let chartData = lodash.cloneDeep(chartDatas)
if (type === 'legend') {
chartData.forEach(item => {
@@ -13,7 +12,6 @@ export default {
})
chartData = chartData.map(item => [item])
}
console.log(chartDatas, '2')
const decimals = chartInfo.param.decimals || 2
const chartOption = {
yAxis: [
@@ -32,7 +30,6 @@ export default {
}
// 左y轴
const leftData = chartData.filter(item => item[0] && !item[0].yAxisIndex)
console.log(chartDatas, '3')
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].maxInterval = chartDataFormat.Interval(leftInfo.maxValue, leftInfo.copies, leftInfo.unit, 'max') * Math.ceil(this.series.length / 5)
@@ -64,14 +61,9 @@ export default {
// 如果全都为右y轴数据 则右y轴显示网格
const unit = chartDataFormat.getUnit(lodash.get(chartInfo, 'param.rightYAxis.unit', 2))
const allRight = this.series.every(item => item.yAxisIndex == 1)
console.log(allRight)
chartOption.yAxis[1].splitLine.show = allRight
console.log(chartDatas, '4')
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', {}))//
console.log(rightInfo)
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)
if (chartInfo.param.stack) {

View File

@@ -154,7 +154,6 @@ export default {
})
}
} else {
console.log(response)
this.$message.error(response.msg || response.error)
}
})

View File

@@ -83,7 +83,6 @@ export default {
momentTz (timestamp, fmt) { // moment 转化时间戳为str
const offset = localStorage.getItem('nz-sys-timezone')
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)
},
momentStrToTimestamp (str, fmt) {

View File

@@ -3885,10 +3885,12 @@ export default {
this.$refs.logDetail && this.$refs.logDetail.resetOperation()
if (this.expressions.length > 0) {
const requestArr = []
const realArr = [] // 记录原始位置
// 过滤掉state为0的元素
this.expressions.forEach((item, index) => {
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))
realArr.push(index)
}
})
if (requestArr.length > 0) {
@@ -3896,18 +3898,22 @@ export default {
this.saveDisabled = false
}
axios.all(requestArr).then(res => {
this.postHistory()
console.log(res)
this.chartLoading = false
const errorRowIndex = []
res.forEach((r, i) => {
if (typeof r === 'string') {
if (r.code !== 200) {
errorRowIndex.push(i)
this.promqlKeys[realArr[i]].isResError = true
} else {
this.promqlKeys[realArr[i]].isResError = false
}
})
if (errorRowIndex.length > 0) {
this.$message.error(this.$t('tip.errorInRow') + ': ' + errorRowIndex.map(e => e + 1).join(' ,'))
res = res.filter((r, i) => errorRowIndex.indexOf(i) === -1)
}
this.postHistory()
if (res.length > 0) {
const logData = res.map(r => r.data)
if (logData[0].result.length > 0) {
@@ -3941,6 +3947,8 @@ export default {
this.logData = logData
hasGraph && this.loadLogGraph()
})
} else {
this.showIntroduce = true
}
}).catch(e => {
this.chartLoading = false
@@ -4370,7 +4378,6 @@ export default {
} else {
const promiseArr = []
this.expressions.forEach((item, index) => {
console.log(item)
if (item != '' && this.promqlKeys[index].state && item) {
promiseArr.push(this.$get('logs/loki/api/v1/format_query', { query: item }))
} else {
@@ -4386,7 +4393,6 @@ export default {
this.updatePath()
},
initQueryFromPath () {
console.log('initQueryFromPath')
const param = this.$route.query[this.position]
if (param) {
const data = JSON.parse(param)
@@ -4412,7 +4418,6 @@ export default {
this.promqlCount = data.queries.length
data.queries.forEach((item, index) => {
this.$set(this.expressions, index, item.expr)
console.log(item)
this.promqlKeys[index] = {
...item,
id: getUUID(),
@@ -4571,7 +4576,7 @@ export default {
})
this.lastHistory.forEach((item) => {
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({
queryKey,
queryValue: findItem.queryValue
@@ -4580,7 +4585,7 @@ export default {
})
arr.forEach(item => {
const findItem = this.lastHistory.find(history => history.id == item.id)
if (!findItem) {
if (!findItem && !item.isResError) {
postArr.push({
queryKey,
queryValue: item.queryValue
@@ -4588,8 +4593,8 @@ export default {
}
})
postArr = postArr.filter(item => item.queryValue)
console.log(postArr)
this.$post('/sys/user/queryHistory', postArr).then(res => {
console.log(res)
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"
>
<div
:id="pqid + 'editor'+index"
v-if="type !== 'log'"
:id="pqid + 'editor'+index + type"
class="not-fixed-height no-resize no-close"
style="padding-right: 24px;box-sizing: border-box"
>
</div>
<div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">
<MonacoEditor
v-if="type == 'log'"
v-model="expressionList[index]"
theme="nz"
class="not-fixed-height no-resize"
ref="monacoEditor"
style="width: calc(100% - 24px)"
:style="{
height: monacoEditorHeight + 'px'
}"
language="logql"
:options="MONACO_EDITOR_OPTIONS"
@editorWillMount="handelBeforeMount"
@editorDidMount="handleMount"
@change="expressionChange"
/>
</div>
<!-- <div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">-->
<!-- <MonacoEditor-->
<!-- v-if="type == 'log'"-->
<!-- v-model="expressionList[index]"-->
<!-- theme="nz"-->
<!-- class="not-fixed-height no-resize"-->
<!-- ref="monacoEditor"-->
<!-- style="width: calc(100% - 24px)"-->
<!-- :style="{-->
<!-- height: monacoEditorHeight + 'px'-->
<!-- }"-->
<!-- language="logql"-->
<!-- :options="MONACO_EDITOR_OPTIONS"-->
<!-- @editorWillMount="handelBeforeMount"-->
<!-- @editorDidMount="handleMount"-->
<!-- @change="expressionChange"-->
<!-- />-->
<!-- </div>-->
<div v-if="errorMsg" class="append-msg error" style="position: absolute">
<span>{{ errorMsg }}</span>
@@ -68,30 +67,29 @@
v-if="plugins.indexOf('metric-input') > -1"
>
<div
:id="pqid + 'editor'+index"
v-if="type !== 'log'"
:id="pqid + 'editor'+index + type"
class="not-fixed-height no-resize no-close"
style="padding-right: 24px;box-sizing: border-box"
>
</div>
<div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">
<MonacoEditor
v-if="type == 'log'"
v-model="expressionList[index]"
theme="nz"
class="not-fixed-height no-resize"
ref="monacoEditor"
style="width: calc(100% - 24px)"
:style="{
height: monacoEditorHeight + 'px'
}"
language="logql"
:options="MONACO_EDITOR_OPTIONS"
@editorWillMount="handelBeforeMount"
@editorDidMount="handleMount"
@change="expressionChange"
/>
</div>
<!-- <div class="zy" style="position: relative;overflow-x: hidden;display: block;border: 1px solid #dedede;width: 100%" v-if="type == 'log'">-->
<!-- <MonacoEditor-->
<!-- v-if="type == 'log'"-->
<!-- v-model="expressionList[index]"-->
<!-- theme="nz"-->
<!-- class="not-fixed-height no-resize"-->
<!-- ref="monacoEditor"-->
<!-- style="width: calc(100% - 24px)"-->
<!-- :style="{-->
<!-- height: monacoEditorHeight + 'px'-->
<!-- }"-->
<!-- language="logql"-->
<!-- :options="MONACO_EDITOR_OPTIONS"-->
<!-- @editorWillMount="handelBeforeMount"-->
<!-- @editorDidMount="handleMount"-->
<!-- @change="expressionChange"-->
<!-- />-->
<!-- </div>-->
</div>
<div class="append-msg error" v-if="errorMsg">
<span>{{ errorMsg }}</span>
@@ -254,6 +252,8 @@ import { get } from '@/http'
import { PromQLExtension } from '@prometheus-io/codemirror-promql'
import { baseTheme, promqlHighlighter, lightTheme } from './CMTheme.tsx'
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 { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view'
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 { highlightSelectionMatches } from '@codemirror/search'
import { lintKeymap } from '@codemirror/lint'
import logqlHint from './logqlHint'
import {
autocompletion,
completionKeymap,
@@ -418,14 +419,15 @@ export default {
const defaultHeaders = {
Authorization: localStorage.getItem('nz-token')
}
let api = '/prom/'
if (this.type === 'log') {
api = '/logs/loki/'
}
const promqlExtension = new PromQLExtension()
.activateCompletion(true)
.activateLinter(true)
.setComplete({
completeStrategy: new HistoryCompleteStrategy(
newCompleteStrategy({
const completeStrategy = newCompleteStrategy({
remote: {
url: baseUrl + '/prom/',
url: baseUrl + api,
fetchFn: (resource, options = {}) => {
const params = options.body?.toString()
const search = params ? `?${params}` : ''
@@ -439,7 +441,121 @@ export default {
},
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) {
@@ -467,6 +583,7 @@ export default {
})),
span: /^[a-zA-Z0-9_:]+$/
}
console.log(res.options)
// 过滤 非logs的函数
if (res !== null) {
historyItems.options = historyItems.options.concat(res.options)
@@ -485,6 +602,10 @@ export default {
lightTheme
]
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({
doc: self.codeMirrorValue[self.index],
extensions: [
@@ -500,7 +621,7 @@ export default {
highlightSelectionMatches(),
EditorView.lineWrapping,
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, ...lintKeymap]),
placeholder('Expression (press Shift+Enter for newlines)'),
placeholder(placeholderStr),
dynamicConfigCompartment.of(dynamicConfig),
keymap.of([
{
@@ -539,7 +660,7 @@ export default {
const view = new EditorView({
state: EditorViewstate,
// 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
} else {
@@ -1090,14 +1211,35 @@ export default {
})
}
},
selectLog (str) {
if (!str || str.length === 0) return
this.expressionList[this.index] = str
this.codeMirrorValue[this.index] = str
selectLog (item) {
if (!item.id) {
this.metricChangeNew(item.name)
} else if (item.id) {
this.dropDownVisible = false
this.$emit('change', str)
this.$forceUpdate()
this.cascaderValue = ''
this.$get('/expression/tmpl/' + item.id).then(res => {
if (res.code === 200) {
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: {
@@ -1150,13 +1292,11 @@ export default {
deep: true,
immediate: true,
handler (n) {
if (n !== 'log') {
this.$nextTick(() => {
this.initCodeMirror()
})
}
}
}
},
beforeDestroy () {
this.newView = null

View File

@@ -336,7 +336,7 @@ export default {
this.hideMe()
},
selectLog () {
this.$emit('selectLog', this.logFinalStr)
this.$emit('selectLog', { name: this.logFinalStr })
this.hideMe()
},
copyItem (value) {