opt:优化日志

This commit is contained in:
2024-12-25 21:48:10 +08:00
parent 5413cfc420
commit ac35c138d6
33 changed files with 1718 additions and 722 deletions

View File

@@ -1,18 +0,0 @@
import request from '@/utils/request'
export function getLogData(param) {
return request({
url: 'api/lucene/getAll',
method: 'get',
data: param
})
}
export function labelsValues() {
return request({
url: 'api/loki/labels/values',
method: 'get'
})
}
export default { getLogData, labelsValues }

View File

@@ -0,0 +1,139 @@
<template>
<div class="app-container">
<div class="head-container">
<Search />
<crudOperation>
<el-button
slot="left"
class="filter-item"
type="danger"
icon="el-icon-delete"
size="mini"
:loading="crud.delAllLoading"
@click="confirmDelAll()"
>
清空
</el-button>
</crudOperation>
</div>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="expand">
<template slot-scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="请求方法">
<span>{{ props.row.method }}</span>
</el-form-item>
<el-form-item label="请求参数">
<span>{{ props.row.params }}</span>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column prop="username" label="用户名" />
<el-table-column prop="requestIp" label="IP" />
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" />
<el-table-column prop="description" label="描述" />
<el-table-column prop="browser" label="浏览器" />
<el-table-column prop="createTime" label="创建日期">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="异常详情" width="100px">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="info(scope.row.id)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialog" title="异常详情" append-to-body top="30px" width="85%">
<pre v-highlightjs="errorInfo"><code class="java" /></pre>
</el-dialog>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import { getErrDetail, delAllError } from '@/api/monitor/log'
import Search from './search'
import CRUD, { presenter } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation.vue'
import pagination from '@crud/Pagination.vue'
export default {
name: 'ErrorLog',
components: { Search, crudOperation, pagination },
cruds() {
return CRUD({ title: '异常日志', url: 'api/logs/error' })
},
mixins: [presenter()],
data() {
return {
errorInfo: '', dialog: false
}
},
created() {
this.crud.optShow = {
add: false,
edit: false,
del: false,
download: true
}
},
methods: {
// 获取异常详情
info(id) {
this.dialog = true
getErrDetail(id).then(res => {
this.errorInfo = res.exception
})
},
confirmDelAll() {
this.$confirm(`确认清空所有异常日志吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.crud.delAllLoading = true
delAllError().then(res => {
this.crud.delAllLoading = false
this.crud.dleChangePage(1)
this.crud.delSuccessNotify()
this.crud.toQuery()
}).catch(err => {
this.crud.delAllLoading = false
console.log(err.response.data.message)
})
}).catch(() => {
})
}
}
}
</script>
<style scoped>
.demo-table-expand {
font-size: 0;
}
.demo-table-expand label {
width: 70px;
color: #99a9bf;
}
.demo-table-expand .el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 100%;
}
.demo-table-expand .el-form-item__content {
font-size: 12px;
}
/deep/ .el-dialog__body {
padding: 0 20px 10px 20px !important;
}
.java.hljs {
color: #444;
background: #ffffff !important;
height: 630px !important;
}
</style>

View File

@@ -1,109 +1,417 @@
<template>
<div class="app-container">
<div class="head-container">
<Search />
<crudOperation />
</div>
<!--表格渲染-->
<el-table
ref="table"
v-loading="crud.loading"
:data="crud.data"
style="width: 100%;"
@selection-change="crud.selectionChangeHandler"
>
<!-- <el-table-column type="selection" width="55"/>-->
<!-- <el-table-column v-if="false" prop="id" label="id"/>-->
<el-table-column prop="operate" width="50" label="操作" />
<el-table-column prop="device_code" label="设备号" min-width="130" show-overflow-tooltip />
<el-table-column prop="task_code" label="任务编号" />
<el-table-column prop="instruct_code" label="指令编号" />
<el-table-column prop="method" label="方法" />
<el-table-column prop="status_code" label="状态码" />
<el-table-column prop="requestparam" label="请求参数" />
<el-table-column prop="responseparam" label="返回参数" />
<el-table-column prop="logTime" width="170" label="记录时间" />
<el-table-column prop="content" width="500" label="内容详情" />
<!--工具栏-->
<el-form :inline="true" class="demo-form-inline" label-suffix=":" label-width="90px">
<el-form-item label="标签">
<el-select
v-model="system"
clearable
style="width: 100px; height: 35px;top: -5px;"
placeholder="所属标签"
>
<el-option
v-for="item in systemOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="级别">
<el-select
v-model="logLevelValue"
clearable
style="width: 100px; height: 35px;top: -5px;"
placeholder="日志级别"
>
<el-option
v-for="item in labelsOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="接口">
<el-input
v-model="requestMethod"
size="mini"
placeholder="请输入接口"
clearable
/>
</el-form-item>
<el-form-item label="关键字">
<el-input
v-model="message"
size="mini"
placeholder="请输入内容"
clearable
/>
</el-form-item>
<el-form-item label="链路追踪">
<el-input
v-model="traceId"
size="mini"
placeholder="请输入链路id"
clearable
/>
</el-form-item>
</el-table>
<!--分页组件-->
<pagination />
<el-form-item label="SQL日志" prop="filterSql">
<el-switch
v-model="filterSql"
active-color="#F56C6C"
inactive-color="#409EFF"
active-value="1"
inactive-valu="0"
/>
</el-form-item>
<el-form-item label="HTTP日志" prop="isRequest">
<el-switch
v-model="isRequest"
active-color="#409EFF"
inactive-color="#F56C6C"
active-value="1"
inactive-valu="0"
/>
</el-form-item>
<el-form-item v-show="!showOptions" label="时间范围">
<el-date-picker
v-model="timeRange"
size="mini"
clearable
type="datetimerange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
align="right"
@change="queryData"
@blur="queryData"
/>
</el-form-item>
<el-form-item v-show="showOptions" label="时间段">
<el-select v-model="timeZoneValue" filterable placeholder="请选择标签" size="mini" @change="queryData">
<el-option
v-for="item in timeZoneOptions"
:key="item.index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-tooltip class="item" effect="dark" content="切换查询条件" placement="top">
<span class="el-icon-sort" @click="changeShow" />
</el-tooltip>
</el-form-item>
<el-form-item label="显示条数">
<el-input-number
v-model="size"
size="mini"
controls-position="right"
:min="20"
:max="5000"
:step="10"
/>
</el-form-item>
<el-form-item label="当前页">
<el-input-number
v-model="page"
size="mini"
controls-position="right"
:min="1"
:max="2000"
:step="1"
/>
</el-form-item>
<el-form-item label="总条数">
<el-input
v-model="total"
size="small"
disabled
style="width: 110px"
/>
</el-form-item>
<el-form-item>
<el-dropdown split-button type="primary" size="mini" @click="queryData">
查询
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item, index) in runStatuOptions" :key="index" @click.native="startInterval(item)">{{ item.label }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-form-item>
<el-form-item>
<el-button @click="clearLogs">清空日志</el-button>
</el-form-item>
</el-form>
</div>
<!-- <div style="margin: 3px; min-height: 80vh;">
<el-table :data="logs">
<el-table-column label="ip" prop="requestIp" />
<el-table-column label="所属系统" prop="system" />
<el-table-column label="请求时间" prop="requestTime" />
<el-table-column label="traceId" prop="traceId" />
<el-table-column label="请求时间" prop="requestTime" />
<el-table-column label="请求接口" prop="requestMethod" />
<el-table-column label="logger" prop="logger" />
<el-table-column label="thread" prop="thread" />
<el-table-column label="message" prop="message" show-overflow-tooltip/>
</el-table>
</div>
-->
<div style="margin: 3px; min-height: 80vh;">
<!--数据判空-->
<el-empty v-if="showEmpty" :description="emptyText" />
<!--数据加载-->
<el-card v-else shadow="hover" style="width: 100%;overflow-x: scroll" class="log-warpper">
<div style="width: 100%">
<div v-for="(log, index) in logs" :key="index">
<div>
<span style="color: #6c0a99;font-weight: 700">{{ log.system }}</span>
<span style="color: #13ce66">{{ log.thread }}</span>
<span :style="fontType(log.logLevel)">{{ log.logLevel }}</span>
<span>{{ log.requestIp }}</span>
<span style="color: #7c8db0">{{ log.requestTime }}</span>
<span style="color: chocolate">{{ log.traceId }}</span>
<span style="color: #7a6df0">{{ log.requestMethod }}</span>
<span style="margin: 5px;font-size: 15px" v-html="log.message">{{ log.message }}</span>
</div>
</div>
</div>
</el-card>
</div>
</div>
</template>
<script>
import Search from './search'
import CRUD, { crud, header, presenter } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import { delAll } from '@/api/acs/lucene/log'
import logOperation from '@/views/monitor/lucene/loki'
let queryParam = {
logLevel: null,
system: null,
startTime: null,
endTime: null,
traceId: null,
requestMethod: null,
message: null,
filterSql: true,
isRequest: true,
page: null,
total: 0,
size: 20
}
export default {
name: 'LuceneLog',
components: { Search, pagination, crudOperation },
mixins: [presenter(), header(), crud()],
cruds: function() {
return CRUD({
title: '系统参数', url: 'api/lucene/getAll', idField: 'id', sort: 'id,desc',
queryOnPresenterCreated: true,
optShow: {
add: false,
edit: false,
del: false,
download: false
},
page: {
size: 40,
total: 0,
page: 0
},
query: {
createTime: [new Date(new Date().setTime(new Date().getTime() - 3600 * 1000)), new Date(new Date().setTime(new Date().getTime() + 3600 * 1000))]
}
})
},
name: 'ES',
data() {
return {
query: { blurry: '123' },
permission: {
add: ['admin', 'param:add'],
edit: ['admin', 'param:edit'],
del: ['admin', 'param:del']
},
rules: {}
labelsOptions: [], // 所有标签和对应所有值数据
systemOptions: [], // 所有标签和对应所有值数据
logLevelValue: '',
system: '',
timeRange: [],
message: '',
requestMethod: '',
traceId: '',
size: 20,
logData: [],
filterSql: '1',
isRequest: '1',
logs: [], // 所有日志
showEmpty: true,
emptyText: '请选择标签',
page: 1,
runStatu: 'off',
runStatuOptions: [{
label: 'off',
value: 0
}, {
label: '5s',
value: 5000
}, {
label: '10s',
value: 10000
}, {
label: '1m',
value: 60000
}, {
label: '5m',
value: 300000
}, {
label: '30m',
value: 1800000
}],
timeZoneOptions: [{
label: '最近5分钟',
value: 300 * 1000
}, {
label: '最近15分钟',
value: 900 * 1000
}, {
label: '最近30分钟',
value: 1800 * 1000
}, {
label: '最近1小时',
value: 3600 * 1000
}, {
label: '最近3小时',
value: 3600 * 1000 * 3
}, {
label: '最近6小时',
value: 3600 * 1000 * 6
}, {
label: '最近12小时',
value: 3600 * 1000 * 12
}, {
label: '最近24小时',
value: 3600 * 1000 * 24
}, {
label: '最近2天',
value: 3600 * 1000 * 24 * 2
}, {
label: '最近7天',
value: 3600 * 1000 * 24 * 7
}, {
label: '最近15天',
value: 3600 * 1000 * 24 * 15
}],
timeZoneValue: '',
showOptions: true
}
},
created() {
this.initLabelsValues('logLevel')
this.initLabelsValues('system')
},
methods: {
// 钩子在获取表格数据之前执行false 则代表不获取数据
[CRUD.HOOK.beforeRefresh]() {
return true
fontType(level) {
if (level === 'INFO') {
return { 'color': '#1b6cc4' }
}
if (level === 'ERROR') {
return { 'color': '#e30a0a' }
}
if (level === 'DEBUG') {
return { 'color': '#1e2022' }
}
return { 'color': '#a74dc6' }
},
confirmDelAll() {
this.$confirm(`确认清空所有操作日志吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.crud.delAllLoading = true
delAll('device_execute').then(res => {
this.crud.delAllLoading = false
this.crud.dleChangePage(1)
this.crud.delSuccessNotify()
this.crud.toQuery()
}).catch(err => {
this.crud.delAllLoading = false
console.log(err.response.data.message)
})
}).catch(() => {
initLabelsValues(type) {
logOperation.labelsValues(type).then(res => {
if (type === 'logLevel') {
this.labelsOptions = res
}
if (type === 'system') {
this.systemOptions = res
}
})
},
queryData() {
// 清空查询数据
this.clearParam()
queryParam.logLevel = this.logLevelValue
const time = new Date()
if (this.timeZoneValue !== '') {
queryParam.startTime = new Date(((time.getTime() - this.timeZoneValue)))
}
if (this.timeRange !== '' && this.timeRange.length > 0) {
queryParam.startTime = this.timeRange[0]
queryParam.endTime = this.timeRange[1]
}
queryParam.message = this.message.replace(/^\s*|\s*$/g, '')
queryParam.filterSql = this.filterSql === '1'
queryParam.isRequest = this.filterSql === '1'
queryParam.traceId = this.traceId
queryParam.requestMethod = this.requestMethod
queryParam.size = this.size
queryParam.page = this.page
queryParam.system = this.system
logOperation.getLogData(queryParam).then(res => {
this.showEmpty = false
this.total = res.total
// 清空
this.logs = []
for (const j in res.page) { // 用push的方式将所有日志数组添加进去
this.logs.push(res.page[j])
}
})
},
clearLogs() {
var message = '您确定要清空'
if (this.system !== '' && this.system !== null) {
message += '标签为:' + this.system + ' '
}
message += '10天前的日志吗 ?'
this.$confirm(message, '确认信息', {
distinguishCancelAndClose: true,
confirmButtonText: '确定',
cancelButtonText: '取消'
})
.then(() => {
// 清空查询数据
this.clearParam()
queryParam.logLevel = this.logLevelValue
const time = new Date()
if (this.timeZoneValue !== '') {
queryParam.startTime = new Date(((time.getTime() - this.timeZoneValue)))
}
if (this.timeRange !== '' && this.timeRange.length > 0) {
queryParam.startTime = this.timeRange[0]
queryParam.endTime = this.timeRange[1]
}
queryParam.message = this.message.replace(/^\s*|\s*$/g, '')
queryParam.traceId = this.traceId
queryParam.requestMethod = this.requestMethod
queryParam.system = this.system
logOperation.clearLogs(queryParam).then(res => {
this.queryData()
this.$message({
type: 'info',
message: '清除成功'
})
})
})
.catch(action => {
this.$message({
type: 'info',
message: action === 'cancel'
? '已取消'
: '已取消'
})
})
},
changetype() {
},
clearParam() {
queryParam = {
logLevel: null,
startTime: null,
endTime: null,
message: null,
traceId: null,
isRequest: true,
filterSql: true,
size: 20
}
},
changeShow() {
// 清空数据
this.timeZoneValue = ''
this.timeRange = []
this.showOptions = !this.showOptions
}
}
}
</script>
<style scoped>
.log-warpper {
white-space: nowrap;
word-break: break-word;
}
</style>

View File

@@ -0,0 +1,26 @@
import request from '@/utils/request'
export function getLogData(param) {
return request({
url: '/api/esLog/query',
method: 'post',
data: param
})
}
export function labelsValues(type) {
return request({
url: '/api/esLog/labels/' + type,
method: 'get'
})
}
export function clearLogs(param) {
return request({
url: '/api/esLog/clearLogs',
method: 'delete',
data: param
})
}
export default { getLogData, labelsValues, clearLogs }

View File

@@ -1,98 +1,14 @@
<template>
<div v-if="crud.props.searchToggle">
<!-- <el-input
v-model="query.device_code"
clearable
size="small"
placeholder="请输入你要搜索的设备号"
style="width: 200px;"
class="filter-item"
/> -->
<!-- <el-select
v-model="query.device_code"
clearable
filterable
size="small"
placeholder="请输入你要搜索的设备号"
class="filter-item"
style="width: 190px"
@change="crud.toQuery"
>
<el-option v-for="item in device_codes" :key="item.id" :label="item.label" :value="item.value" />
</el-select> -->
<el-select
ref="test"
v-model="query.device_code"
filterable
clearable
reserve-keyword
placeholder="设备号"
style="width: 190px;"
@change="crud.toQuery"
>
<el-option
v-for="item in deviceList"
:key="item.device_code"
:label="item.device_code"
:value="item.device_code"
/>
</el-select>
<el-input
v-model="query.method"
clearable
size="small"
placeholder="请输入你要搜索的方法名"
style="width: 200px;"
class="filter-item"
/>
<el-input
v-model="query.status_code"
clearable
size="small"
placeholder="请输入你要搜索的状态码"
style="width: 200px;"
class="filter-item"
/>
<el-input
v-model="query.requestparam"
clearable
size="small"
placeholder="请输入你要搜索的请求参数"
style="width: 200px;"
class="filter-item"
/>
<el-input
v-model="query.responseparam"
clearable
size="small"
placeholder="请输入你要搜索的返回参数"
style="width: 200px;"
class="filter-item"
/>
<el-input
v-model="query.blurry"
clearable
size="small"
placeholder="请输入你要搜索的内容详情"
placeholder="请输入你要搜索的内容"
style="width: 200px;"
class="filter-item"
/>
<!--
<date-range-picker v-model="query.createTime" class="date-item" />
-->
<el-date-picker
v-model="query.createTime"
type="datetimerange"
:picker-options="pickerOptions"
format="yyyy-MM-dd HH:mm:ss"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
align="right"
/>
<date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation />
</div>
</template>
@@ -100,51 +16,9 @@
<script>
import { header } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import deviceCrud from '@/api/acs/device/device'
import DateRangePicker from '@/components/DateRangePicker'
export default {
components: { rrOperation },
mixins: [header()],
data() {
return {
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
}]
},
value1: [new Date(2000, 10, 10, 10, 10), new Date(2000, 10, 11, 10, 10)],
value2: '',
deviceList: [],
device_code: ''
}
},
created() {
deviceCrud.selectDeviceList().then(data => {
this.deviceList = data
})
}
components: { rrOperation, DateRangePicker },
mixins: [header()]
}
</script>