add:添加日志删除功能

This commit is contained in:
zhangzq
2026-06-18 15:05:07 +08:00
parent b14042dd68
commit 7b0a86dd42
5 changed files with 87 additions and 38 deletions

View File

@@ -39,7 +39,7 @@ public class LuceneLogController {
} }
@DeleteMapping("/clearLogs") @DeleteMapping("/clearLogs")
//("清空日志") //("清空日志")
public ResponseEntity<Object> clearLogs(@RequestBody LogQuery query) { public ResponseEntity<Object> clearLogs(@RequestBody(required = false) LogQuery query) {
luceneLogService.clearLogs(query); luceneLogService.clearLogs(query);
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }

View File

@@ -44,4 +44,9 @@ public class LogQuery {
private Integer size = 20; private Integer size = 20;
private Integer page = 1; private Integer page = 1;
/**
* 日志保留天数null 或 0 表示全部删除
*/
private Integer retainDays;
} }

View File

@@ -28,7 +28,6 @@ import java.nio.file.Paths;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -46,13 +45,20 @@ public class LuceneLogServiceImpl implements LuceneLogService {
try { try {
IndexWriter indexWriter = LuceneAppender.indexWriter; IndexWriter indexWriter = LuceneAppender.indexWriter;
if (indexWriter != null){ if (indexWriter != null){
BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder(); Integer retainDays = query == null ? null : query.getRetainDays();
DateTime offset = DateUtil.offset(new Date(), DateField.HOUR_OF_DAY, -10); Query deleteQuery;
TermRangeQuery termRangeQuery = new TermRangeQuery( if (retainDays == null || retainDays <= 0) {
"requestTime",null, deleteQuery = new MatchAllDocsQuery();
new BytesRef(DateUtil.format(offset, "yyyy-MM-dd HH:mm:ss.SSS")), true, true); } else {
booleanQueryBuilder.add(termRangeQuery,BooleanClause.Occur.MUST); DateTime cutoff = DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, -retainDays);
indexWriter.deleteDocuments(termRangeQuery); deleteQuery = new TermRangeQuery(
"requestTime",
null,
new BytesRef(DateUtil.format(cutoff, "yyyy-MM-dd HH:mm:ss.SSS")),
true,
true);
}
indexWriter.deleteDocuments(deleteQuery);
indexWriter.commit(); indexWriter.commit();
} }
}catch (Exception ex){ }catch (Exception ex){

View File

@@ -14,10 +14,11 @@ export function getTagName() {
method: 'post' method: 'post'
}) })
} }
export function deleteAllLog() { export function deleteAllLog(data) {
return request({ return request({
url: 'api/lucene/clearLogs', url: 'api/lucene/clearLogs',
method: 'post' method: 'delete',
data
}) })
} }

View File

@@ -59,20 +59,41 @@
<el-button type="primary" size="mini" @click="queryData"> <el-button type="primary" size="mini" @click="queryData">
{{ $t('common.Query') }} {{ $t('common.Query') }}
</el-button> </el-button>
<el-button type="danger" size="mini" @click="clearDialogVisible = true">
清除日志
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<el-dialog
title="清除日志"
:visible.sync="clearDialogVisible"
width="360px"
>
<el-radio-group v-model="clearOption" class="clear-log-options">
<el-radio label="all">全部删除</el-radio>
<el-radio :label="3">保留3天</el-radio>
<el-radio :label="5">保留5天</el-radio>
<el-radio :label="7">保留7天</el-radio>
</el-radio-group>
<span slot="footer">
<el-button size="mini" @click="clearDialogVisible = false"> </el-button>
<el-button type="danger" size="mini" :loading="clearLoading" @click="handleClearLogs">
</el-button>
</span>
</el-dialog>
<!--表格渲染--> <!--表格渲染-->
<el-card shadow="hover" style="width: 100%" class="log-warpper"> <el-card shadow="hover" style="width: 100%" class="log-warpper">
<div class="log-list"> <div class="log-list">
<div v-for="(log, index) in logs" :key="index" class="log-item"> <div v-for="(log, index) in logs" :key="index" class="log-item">
<div class="log-meta"> <div class="log-meta">
<span v-if="log.requestTime" class="log-time log-badge log-badge-time">{{ log.requestTime }}</span> <span v-if="log.requestTime" class="log-tag log-time">{{ log.requestTime }}</span>
<span class="log-level" :class="`log-level-${getLevelClass(log.logLevel)}`">{{ log.logLevel || 'UNKNOWN' }}</span> <span class="log-level" :class="`log-level-${getLevelClass(log.logLevel)}`">{{ log.logLevel || 'UNKNOWN' }}</span>
<span v-if="log.requestIp" class="log-ip log-badge log-badge-ip">IP: {{ log.requestIp }}</span> <span v-if="log.requestIp" class="log-tag log-request-ip">{{ log.requestIp }}</span>
<span v-if="log.requestMethod" class="log-method log-badge log-badge-method">{{ log.requestMethod }}</span> <span v-if="log.requestMethod" class="log-tag log-request-method">{{ log.requestMethod }}</span>
<span v-if="log.traceId && log.traceId.trim()" class="log-trace log-badge log-badge-trace">traceId: {{ log.traceId }}</span> <span v-if="log.traceId && log.traceId.trim()" class="log-tag log-trace">traceId: {{ log.traceId }}</span>
<span v-if="log.thread" class="log-thread log-badge log-badge-thread">{{ log.thread }}</span> <span v-if="log.thread" class="log-tag log-thread">{{ log.thread }}</span>
</div> </div>
<div class="log-message" v-html="log.messageHtml" /> <div class="log-message" v-html="log.messageHtml" />
</div> </div>
@@ -120,6 +141,9 @@ export default {
rules: {}, rules: {},
logs: [], logs: [],
tagList: [], tagList: [],
clearDialogVisible: false,
clearLoading: false,
clearOption: 3,
query: { query: {
traceId: '', traceId: '',
requestMethod: '', requestMethod: '',
@@ -166,11 +190,25 @@ export default {
requestIp: item && item.requestIp, requestIp: item && item.requestIp,
requestMethod: item && item.requestMethod, requestMethod: item && item.requestMethod,
logLevel: item && item.logLevel, logLevel: item && item.logLevel,
logger: item && item.logger,
system: item && item.system,
thread: item && item.thread, thread: item && item.thread,
traceId: item && item.traceId, traceId: item && item.traceId,
messageHtml: ansi_up.ansi_to_html(rawMessage) messageHtml: ansi_up.ansi_to_html(rawMessage)
} }
}, },
handleClearLogs() {
const retainDays = this.clearOption === 'all' ? 0 : this.clearOption
this.clearLoading = true
luceneOperation.deleteAllLog({ retainDays }).then(() => {
this.$message.success('日志清除成功')
this.clearDialogVisible = false
this.query.page = 1
this.queryData()
}).finally(() => {
this.clearLoading = false
})
},
queryData() { queryData() {
if (this.query.createTime && this.query.createTime.length === 2) { if (this.query.createTime && this.query.createTime.length === 2) {
this.query.startTime = this.query.createTime[0] this.query.startTime = this.query.createTime[0]
@@ -192,6 +230,12 @@ export default {
</script> </script>
<style scoped> <style scoped>
.clear-log-options {
display: flex;
flex-direction: column;
gap: 12px;
}
.log-list { .log-list {
width: 100%; width: 100%;
} }
@@ -214,52 +258,45 @@ export default {
color: #606266; color: #606266;
} }
.log-badge { .log-tag {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
max-width: 100%;
padding: 0 8px; padding: 0 8px;
line-height: 22px; line-height: 22px;
border-radius: 11px; border-radius: 11px;
border: 1px solid transparent; border: 1px solid transparent;
word-break: break-all;
} }
.log-time, .log-time {
.log-ip,
.log-method,
.log-thread,
.log-trace {
line-height: 20px;
}
.log-badge-time {
color: #606266; color: #606266;
background: #f4f4f5; background: #f4f4f5;
border-color: #dcdfe6; border-color: #dcdfe6;
} }
.log-badge-ip { .log-request-ip {
color: #7c4dff; color: #7c4dff;
background: #f3edff; background: #f3edff;
border-color: #d9c8ff; border-color: #d9ccff;
} }
.log-badge-method { .log-request-method {
color: #0f766e; color: #0f766e;
background: #ecfdf5; background: #ecfdf5;
border-color: #b7ebd3; border-color: #a7f3d0;
font-weight: 500;
} }
.log-badge-thread { .log-thread {
color: #8e44ad; color: #8e44ad;
background: #f8f0ff; background: #f5eef8;
border-color: #e2cfff; border-color: #d7bde2;
} }
.log-badge-trace { .log-trace {
color: #c05621; color: #1f2d3d;
background: #fff7ed; background: #ecf5ff;
border-color: #fbd38d; border-color: #b3d8ff;
} }
.log-level { .log-level {