优化日志系统:网络请求降噪并按接口聚合,补齐双时间说明与实例标识,发布0.3.2
- 逐条网络日志(请求完成 / 接口返回异常 / 响应刷新CSRF已同步)从 info/warn 降为 debug: 实测一次 6 账号的模拟抢购里 233 条日志有 174 条(74%)属于这类;真实抢购会产生几千条, 把界面仅 800 条的内存日志冲掉,反而看不到关键信息。HTTP/解析/传输层错误仍为 error 级 - 新增按接口聚合的网络统计,抢购任务结束时输出一行,替代逐条刷屏: "接口统计: 锁定兑换商品 ×341 失败341 平均=95ms 最慢=312ms 最后错误=活动火爆,请稍后再试" - 日志文件开头新增表头:实例名、数据目录、双时间格式说明(本地时间 + D 斗鱼估算时间)、 并说明"校准完成前偏移为 0,只显示本地时间"。双时间一直存在却没有任何地方解释过, 多实例日志复制或汇总后也分不清来源 - 界面日志面板:显示日志级别并按级别着色(此前级别只存在于 CSS class,复制出去就丢); 新增"复制"按钮,按与日志文件一致的单行格式导出(此前直接复制会变成 5 行一条、 1204 行里其实只有 233 条日志) - 设置页"日志显示等级"补充说明:Info 起只显示关键日志,需要逐请求细节时切到 Debug - 新增测试:TestRequestStatsAggregatesByLabel、TestLogFileHeaderDocumentsFormat、 TestRunNowLogsAggregateInsteadOfPerRequest(断言必须有聚合行、且不得出现逐条请求日志)
This commit is contained in:
@@ -1,10 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { nextTick, ref, watch } from 'vue'
|
||||
import { ClipboardSetText } from '@wails/runtime/runtime'
|
||||
import { useLogs } from '@/composables/useLogs'
|
||||
|
||||
const { logs, clearLogs } = useLogs()
|
||||
const { logs, clearLogs, exportLogsText } = useLogs()
|
||||
const expanded = ref(false)
|
||||
const logBodyRef = ref<HTMLElement | null>(null)
|
||||
const copyState = ref('复制')
|
||||
|
||||
const copyLogs = async () => {
|
||||
if (logs.value.length === 0) return
|
||||
try {
|
||||
// 复制成与后端日志文件一致的单行格式,避免面板的多 span 变成 5 行一条、丢失级别。
|
||||
const ok = await ClipboardSetText(exportLogsText())
|
||||
copyState.value = ok ? '已复制' : '复制失败'
|
||||
} catch {
|
||||
copyState.value = '复制失败'
|
||||
}
|
||||
setTimeout(() => { copyState.value = '复制' }, 1500)
|
||||
}
|
||||
|
||||
watch(logs, async () => {
|
||||
if (!expanded.value) return
|
||||
@@ -21,7 +35,10 @@ watch(logs, async () => {
|
||||
<span>日志</span>
|
||||
<span v-if="logs.length" class="log-count">{{ logs.length }}</span>
|
||||
</button>
|
||||
<button v-if="expanded" class="btn btn-compact" @click="clearLogs">清空</button>
|
||||
<div v-if="expanded" class="log-actions">
|
||||
<button class="btn btn-compact" @click="copyLogs">{{ copyState }}</button>
|
||||
<button class="btn btn-compact" @click="clearLogs">清空</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="expanded" ref="logBodyRef" class="log-body">
|
||||
<div v-if="logs.length === 0" class="log-i">[系统] 就绪,等待操作...</div>
|
||||
@@ -31,6 +48,7 @@ watch(logs, async () => {
|
||||
<span v-if="log.time" class="log-time">[{{ log.time }}]</span>
|
||||
<span v-if="log.douyuTime" class="log-douyu-time">D:{{ log.douyuTime }}</span>
|
||||
<span v-if="log.category" class="log-cat">{{ log.category }}</span>
|
||||
<span class="log-level">[{{ log.level || 'info' }}]</span>
|
||||
<span v-if="log.account" class="log-account">{{ log.account }}</span>
|
||||
<span class="log-msg">{{ log.message }}</span>
|
||||
</template>
|
||||
@@ -51,6 +69,11 @@ watch(logs, async () => {
|
||||
.log-line { display: flex; align-items: flex-start; gap: 4px; padding: 2px 0; word-break: break-all; }
|
||||
.log-prefix, .log-time { color: var(--muted); flex-shrink: 0; font-size: 10px; }
|
||||
.log-douyu-time { color: var(--accent); flex-shrink: 0; font-size: 10px; font-weight: 600; }
|
||||
.log-actions { display: inline-flex; gap: 6px; }
|
||||
.log-level { color: var(--muted-2); flex-shrink: 0; font-size: 10px; }
|
||||
.log-line.log-w .log-level { color: var(--warning); }
|
||||
.log-line.log-e .log-level { color: var(--danger); }
|
||||
.log-line.log-s .log-level { color: var(--success); }
|
||||
.log-cat, .log-account { display: inline-block; padding: 0 4px; border-radius: 3px; font-size: 10px; line-height: 1.4; flex-shrink: 0; }
|
||||
.log-cat { border: 1px solid var(--line); color: var(--muted); background: var(--surface); }
|
||||
.log-account { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: 1px solid var(--accent-border); color: var(--accent); background: var(--accent-soft); }
|
||||
|
||||
@@ -130,6 +130,10 @@ defineExpose({ open, close })
|
||||
<option value="warn">Warn</option>
|
||||
<option value="error">Error</option>
|
||||
</select>
|
||||
<div class="form-hint">
|
||||
Info 起只显示关键日志;需要看每个请求的耗时与错误码时切到 Debug
|
||||
(抢购任务结束时仍会输出各类接口的<strong>聚合统计</strong>)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,9 @@ export interface LogEntry {
|
||||
|
||||
export interface LogMessage {
|
||||
time: string
|
||||
rawTime?: string
|
||||
douyuTime?: string
|
||||
level?: string
|
||||
type: 's' | 'e' | 'i' | 'w' | 'd'
|
||||
message: string
|
||||
category?: string
|
||||
@@ -57,6 +59,21 @@ const cleanServerLogMessage = (message: string): string => {
|
||||
.replace(/^\[账号:[^\]]+\]\s*/i, '')
|
||||
}
|
||||
|
||||
// formatLogLine 把一条日志还原成与后端日志文件一致的单行格式。
|
||||
// 面板用多个 span 渲染,直接复制会变成 5 行一条、还丢掉级别,
|
||||
// 所以"复制"走这里:时间(D斗鱼时间) [类别][级别][账号] 正文。
|
||||
const formatLogLine = (log: LogMessage): string => {
|
||||
if (log.source !== 'server') {
|
||||
return `[${log.time}] ${log.message}`
|
||||
}
|
||||
const time = log.rawTime || log.time || ''
|
||||
const douyu = log.douyuTime ? `(D${log.douyuTime})` : ''
|
||||
const category = log.category ? `[${log.category}]` : ''
|
||||
const level = `[${log.level || 'info'}]`
|
||||
const account = log.account ? `[账号:${log.account}]` : ''
|
||||
return `${time}${douyu} ${category}${level}${account} ${log.message}`.replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
|
||||
// 后端结果按“账号_第N包”返回,账号表按账号名展示,这里做一次归并。
|
||||
const normalizeResultStatuses = (data: Record<string, string>): Record<string, AccountStatus> => {
|
||||
const next: Record<string, AccountStatus> = {}
|
||||
@@ -111,7 +128,9 @@ export function useLogs() {
|
||||
|
||||
logs.value.push({
|
||||
time: formatServerLogTime(item.time || ''),
|
||||
rawTime: item.time || '',
|
||||
douyuTime: dyTime || undefined,
|
||||
level: item.level,
|
||||
type,
|
||||
message: cleanMsg,
|
||||
category: item.category,
|
||||
@@ -162,9 +181,13 @@ export function useLogs() {
|
||||
clearLocalResults()
|
||||
}
|
||||
|
||||
// exportLogsText 导出全部日志为单行文本,供"复制"按钮使用。
|
||||
const exportLogsText = (): string => logs.value.map(formatLogLine).join('\n')
|
||||
|
||||
return {
|
||||
logs,
|
||||
results,
|
||||
exportLogsText,
|
||||
addLocalLog,
|
||||
fetchServerLogs,
|
||||
checkResults,
|
||||
|
||||
Reference in New Issue
Block a user