perf: Optimize supervisor log reading (#11545)

Refs https://github.com/1Panel-dev/1Panel/issues/11515
This commit is contained in:
CityFun
2026-01-04 16:49:40 +08:00
committed by GitHub
parent 1f70646952
commit 6ab14185e0
4 changed files with 133 additions and 52 deletions

View File

@@ -658,6 +658,9 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
configPath = pathSet.Value
}
logFilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile")
case constant.Supervisor:
logDir := path.Join(global.Dir.DataDir, "tools", "supervisord", "log")
logFilePath = path.Join(logDir, req.Name)
}
file, err := os.Open(logFilePath)

View File

@@ -1,25 +1,12 @@
<template>
<DrawerPro
v-model="open"
:header="title"
:header="$t('website.source')"
@close="handleClose"
:size="globalStore.isFullScreen ? 'full' : 'large'"
:fullScreen="true"
>
<template #content>
<div v-if="req.file != 'config'">
<el-tabs v-model="req.file" type="card" @tab-click="handleChange">
<el-tab-pane :label="$t('logs.runLog')" name="out.log"></el-tab-pane>
<el-tab-pane :label="$t('logs.errLog')" name="err.log"></el-tab-pane>
</el-tabs>
<el-checkbox border v-model="tailLog" class="float-left" @change="changeTail">
{{ $t('commons.button.watch') }}
</el-checkbox>
<el-button class="ml-5" @click="cleanLog" icon="Delete">
{{ $t('commons.button.clean') }}
</el-button>
</div>
<br />
<div v-loading="loading">
<CodemirrorPro class="mt-5" v-model="content" :heightDiff="400"></CodemirrorPro>
</div>
@@ -28,19 +15,17 @@
<template #footer>
<span>
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" :disabled="loading" @click="submit()" v-if="req.file === 'config'">
<el-button type="primary" :disabled="loading" @click="submit()">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</DrawerPro>
<OpDialog ref="opRef" @search="getContent" />
</template>
<script lang="ts" setup>
import { onUnmounted, reactive, ref } from 'vue';
import { operateSupervisorProcessFile } from '@/api/modules/host-tool';
import i18n from '@/lang';
import { TabsPaneContext } from 'element-plus';
import { MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
@@ -55,10 +40,6 @@ const req = reactive({
operate: '',
content: '',
});
const title = ref('');
const opRef = ref();
let timer: NodeJS.Timer | null = null;
const em = defineEmits(['search']);
@@ -73,21 +54,6 @@ const getContent = () => {
});
};
const handleChange = (tab: TabsPaneContext) => {
req.file = tab.props.name.toString();
getContent();
};
const changeTail = () => {
if (tailLog.value) {
timer = setInterval(() => {
getContent();
}, 1000 * 5);
} else {
onCloseLog();
}
};
const handleClose = () => {
content.value = '';
open.value = false;
@@ -117,26 +83,12 @@ const acceptParams = (name: string, file: string, operate: string) => {
req.file = file;
req.operate = operate;
title.value = file == 'config' ? i18n.global.t('website.source') : i18n.global.t('commons.button.log');
getContent();
open.value = true;
};
const cleanLog = async () => {
let log = req.file === 'out.log' ? i18n.global.t('logs.runLog') : i18n.global.t('logs.errLog');
opRef.value.acceptParams({
title: i18n.global.t('commons.button.clean'),
names: [req.name],
msg: i18n.global.t('commons.msg.operatorHelper', [log, i18n.global.t('commons.button.clean')]),
api: operateSupervisorProcessFile,
params: { name: req.name, operate: 'clear', file: req.file },
});
};
const onCloseLog = async () => {
tailLog.value = false;
clearInterval(Number(timer));
timer = null;
};
onUnmounted(() => {

View File

@@ -3,7 +3,7 @@
<el-card v-if="showStopped" class="mask-prompt">
<span>{{ $t('tool.supervisor.notStartWarn') }}</span>
</el-card>
<LayoutContent :title="$t('tool.supervisor.list', 2)" v-loading="loading">
<LayoutContent :title="$t(' tool.supervisor.list', 2)" v-loading="loading">
<template #prompt v-if="!globalStore.isFxplay">
<el-alert type="info" :closable="false">
<template #title>
@@ -157,11 +157,14 @@
</LayoutContent>
<Create ref="createRef" @close="search"></Create>
<File ref="fileRef" @search="search"></File>
<Log ref="logRef" @close="search" />
<ProcessDetail ref="processDetailRef" />
</div>
</template>
<script setup lang="ts">
import Log from './log/index.vue';
import SuperVisorStatus from './status/index.vue';
import { ref } from 'vue';
import ConfigSuperVisor from './config/index.vue';
@@ -181,6 +184,7 @@ const loading = ref(false);
const setSuperVisor = ref(false);
const createRef = ref();
const fileRef = ref();
const logRef = ref();
const processDetailRef = ref();
const data = ref();
const maskShow = ref(true);
@@ -324,6 +328,10 @@ const getFile = (name: string, file: string) => {
fileRef.value.acceptParams(name, file, 'get');
};
const openLog = (name: string) => {
logRef.value.acceptParams(name);
};
const edit = (row: HostTool.SupersivorProcess) => {
createRef.value.acceptParams('update', row);
};
@@ -344,7 +352,7 @@ const buttons = [
{
label: i18n.global.t('commons.button.log'),
click: function (row: HostTool.SupersivorProcess) {
getFile(row.name, 'out.log');
openLog(row.name);
},
},
{

View File

@@ -0,0 +1,118 @@
<template>
<DrawerPro
v-model="open"
:header="$t('commons.button.log') + ' - ' + supervisorName"
@close="handleClose"
:size="globalStore.isFullScreen ? 'full' : 'large'"
:fullScreen="true"
>
<template #content>
<el-tabs v-model="tab" type="card" @tab-click="handleChange">
<el-tab-pane :label="$t('logs.runLog')" name="out.log"></el-tab-pane>
<el-tab-pane :label="$t('logs.errLog')" name="err.log"></el-tab-pane>
</el-tabs>
<LogFile
:key="logKey"
ref="logRef"
v-if="openLog"
:config="logConfig"
v-model:loading="loading"
v-model:has-content="hasContent"
:height-diff="300"
>
<template #button>
<el-button @click="cleanLog" icon="Delete" :disabled="hasContent === false">
{{ $t('commons.button.clean') }}
</el-button>
</template>
</LogFile>
</template>
<template #footer>
<span>
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
</span>
</template>
</DrawerPro>
<OpDialog ref="opRef" @search="refreshLog" />
</template>
<script lang="ts" setup>
import LogFile from '@/components/log/file/index.vue';
import { onUnmounted, reactive, ref } from 'vue';
import { GlobalStore } from '@/store';
import { operateSupervisorProcessFile } from '@/api/modules/host-tool';
import i18n from '@/lang';
import { TabsPaneContext } from 'element-plus';
const globalStore = GlobalStore();
const logConfig = reactive({
type: 'supervisor',
id: undefined,
name: '',
colorMode: 'nginx',
});
const loading = ref(false);
const open = ref(false);
const tab = ref('out.log');
const openLog = ref();
const supervisorName = ref('');
const opRef = ref();
const logKey = ref(0);
const hasContent = ref(false);
const em = defineEmits(['close']);
const handleChange = (tab: TabsPaneContext) => {
openLog.value = false;
logConfig.name = supervisorName.value + '.' + tab.props.name.toString();
logKey.value++;
openLog.value = true;
};
const handleClose = () => {
open.value = false;
};
const acceptParams = (name: string) => {
tab.value = 'out.log';
supervisorName.value = name;
logConfig.name = name + '.' + tab.value;
open.value = true;
openLog.value = true;
};
const onCloseLog = async () => {
em('close');
};
const refreshLog = () => {
logKey.value++;
};
const cleanLog = async () => {
let log = tab.value === 'out.log' ? i18n.global.t('logs.runLog') : i18n.global.t('logs.errLog');
opRef.value.acceptParams({
title: i18n.global.t('commons.button.clean'),
names: [supervisorName.value],
msg: i18n.global.t('commons.msg.operatorHelper', [log, i18n.global.t('commons.button.clean')]),
api: operateSupervisorProcessFile,
params: { name: supervisorName.value, operate: 'clear', file: tab.value },
});
};
onUnmounted(() => {
onCloseLog();
});
defineExpose({
acceptParams,
});
</script>
<style scoped lang="scss">
.fullScreen {
border: none;
}
</style>