tune(logs): 每页条数默认 1000→200,上下文默认 5 条(依据实测数据)
=== 一、每页条数:1000 太多,实测依据 ===
1. 每次查询响应体 671 B/条 → 1000 条 = **655 KB**
2. 前端结果表**没有虚拟滚动**(无 react-window / tanstack virtual),
1000 行会全部渲染成 DOM 节点 → 滚动卡顿
3. 后端 maxLogQueryLimit 本来就是 1000,我上一版 UI 给了 2000/5000 选项
是"假选项"(会被静默收敛成 1000),本次去掉
4. 密度参考:cex-ipublic-gateway 每天 3.28 亿条 ≈ **3800 条/秒**,
1000 条只覆盖 0.26 秒 —— 靠翻页浏览无意义,应靠时间范围/LogQL 收窄
调整:默认 1000 → **200**(后端自身默认值,约 131KB);选项 [100/200/500/1000]
提示文案改为"日志量大时先收窄时间范围或加过滤,比调大每页条数更有效"
=== 二、上下文档数:1 条不够,默认用 5 ===
实测一个 SpringBoot 异常被拆成 **4 条独立日志**:
16:15:35.259 [reactor-http-epoll-3] ERROR ...AbstractErrorWebExceptionHandler
org.springframework.web.reactive.resource.NoResourceFoundException: 404 NOT_FOUND
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
*__checkpoint ⇢ HTTP HEAD "/" [ExceptionHandlingWebHandler]
→ 前后各 1 条(共 2 条)连一个完整异常都拼不出来
→ 前后各 5 条(共 10 条)能看到"异常 + 前后业务日志",是排障的最小可用集
→ 完整 Java 堆栈(20+ 帧)需要 20-50 条
调整:默认 2 → **5**;选项增加 1 → [1/2/5/10/20/50]
镜像:lghost/lokistack:latest + v0.1 = sha256:2bcc86b8e30d
This commit is contained in:
1 parent
3191af8b6a
commit
6364a70215
5 files changed
+12
-7
No files matched your search
@@ -23,6 +23,9 @@ import (
|
|||||||
"lokistack/repository"
|
"lokistack/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// maxLogQueryLimit 单页硬上限。依据:实测每条日志约 671B——
|
||||||
|
// 1000 条 ≈ 655KB 响应;而前端结果表**没有虚拟滚动**,1000 行会全部渲染成
|
||||||
|
// DOM 节点导致卡顿。前端下拉只给到 1000,超过会被这里静默收敛。
|
||||||
const maxLogQueryLimit = 1000
|
const maxLogQueryLimit = 1000
|
||||||
const logQueryTimeout = 120 * time.Second
|
const logQueryTimeout = 120 * time.Second
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
sourceAria: 'Data source',
|
sourceAria: 'Data source',
|
||||||
sourceEmptyOption: 'No data sources available',
|
sourceEmptyOption: 'No data sources available',
|
||||||
limitLabel: 'Per page',
|
limitLabel: 'Per page',
|
||||||
limitHint: 'Up to 1000 entries per page; paging keeps only the current page.',
|
limitHint: 'Default 200 entries (~0.7KB each). For very dense logs, narrow the time range or add filters instead of raising the page size.',
|
||||||
rangeInvalid: 'Select a valid start and end time',
|
rangeInvalid: 'Select a valid start and end time',
|
||||||
queryFailed: 'Query failed',
|
queryFailed: 'Query failed',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default {
|
|||||||
sourceAria: '数据源',
|
sourceAria: '数据源',
|
||||||
sourceEmptyOption: '暂无可用数据源',
|
sourceEmptyOption: '暂无可用数据源',
|
||||||
limitLabel: '每页条数',
|
limitLabel: '每页条数',
|
||||||
limitHint: '每页最多 1000 条,翻页仅保留当前页。',
|
limitHint: '默认 200 条(每条约 0.7KB)。日志量很大时先收窄时间范围或加过滤条件,比调大每页条数更有效。',
|
||||||
rangeInvalid: '请选择有效的起止时间',
|
rangeInvalid: '请选择有效的起止时间',
|
||||||
queryFailed: '查询失败',
|
queryFailed: '查询失败',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function LogContextDialog({ context, terms, lines, onLinesChange, onClose
|
|||||||
<Select value={String(lines)} onValueChange={value => onLinesChange(Number(value))}>
|
<Select value={String(lines)} onValueChange={value => onLinesChange(Number(value))}>
|
||||||
<SelectTrigger className="h-6 w-16 px-2 text-xs"><SelectValue /></SelectTrigger>
|
<SelectTrigger className="h-6 w-16 px-2 text-xs"><SelectValue /></SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{[2, 5, 10, 20, 50].map(value => <SelectItem key={value} value={String(value)}>{value}</SelectItem>)}
|
{[1, 2, 5, 10, 20, 50].map(value => <SelectItem key={value} value={String(value)}>{value}</SelectItem>)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -68,7 +68,9 @@ export default function LogsPage() {
|
|||||||
const [executedRange, setExecutedRange] = useState<{ start: number; end: number } | null>(null)
|
const [executedRange, setExecutedRange] = useState<{ start: number; end: number } | null>(null)
|
||||||
const [start, setStart] = useState(() => toLocal(new Date(Date.now() - 300000)))
|
const [start, setStart] = useState(() => toLocal(new Date(Date.now() - 300000)))
|
||||||
const [end, setEnd] = useState(() => toLocal(new Date()))
|
const [end, setEnd] = useState(() => toLocal(new Date()))
|
||||||
const [limit, setLimit] = useState(1000)
|
// 默认 200:实测 671B/条,200 条约 131KB、DOM 200 行渲染顺畅。
|
||||||
|
// 后端 maxLogQueryLimit=1000,所以下拉不给 2000/5000(否则静默截断成 1000,是假选项)
|
||||||
|
const [limit, setLimit] = useState(200)
|
||||||
const [queryHistory, setQueryHistory] = useState(readQueryHistory)
|
const [queryHistory, setQueryHistory] = useState(readQueryHistory)
|
||||||
const [entries, setEntries] = useState<LogEntry[]>([])
|
const [entries, setEntries] = useState<LogEntry[]>([])
|
||||||
const [searched, setSearched] = useState(false)
|
const [searched, setSearched] = useState(false)
|
||||||
@@ -198,10 +200,10 @@ export default function LogsPage() {
|
|||||||
return () => window.clearInterval(timer)
|
return () => window.clearInterval(timer)
|
||||||
}, [tail, sourceId, query, limit])
|
}, [tail, sourceId, query, limit])
|
||||||
|
|
||||||
/** 上下文前后条数:默认 2 条(原来写死 5),选择后记住,弹窗内可随时改 */
|
/** 上下文前后条数:默认 5 条(Java 一个异常常拆成 4 条日志,2 条拼不完整),选择后记住 */
|
||||||
const [contextLines, setContextLines] = useState<number>(() => {
|
const [contextLines, setContextLines] = useState<number>(() => {
|
||||||
const saved = Number(localStorage.getItem('logContextLines'))
|
const saved = Number(localStorage.getItem('logContextLines'))
|
||||||
return saved > 0 && saved <= 50 ? saved : 2
|
return saved > 0 && saved <= 50 ? saved : 5
|
||||||
})
|
})
|
||||||
/** 记住当前查看上下文的那一行,切换条数时原地重新拉取 */
|
/** 记住当前查看上下文的那一行,切换条数时原地重新拉取 */
|
||||||
const [contextRow, setContextRow] = useState<LogEntry | null>(null)
|
const [contextRow, setContextRow] = useState<LogEntry | null>(null)
|
||||||
@@ -273,7 +275,7 @@ export default function LogsPage() {
|
|||||||
<Select value={String(limit)} onValueChange={value => setLimit(Number(value))}>
|
<Select value={String(limit)} onValueChange={value => setLimit(Number(value))}>
|
||||||
<SelectTrigger className="h-9 w-24" aria-label={t('toolbar.limitLabel')}><SelectValue /></SelectTrigger>
|
<SelectTrigger className="h-9 w-24" aria-label={t('toolbar.limitLabel')}><SelectValue /></SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{[100, 500, 1000, 2000, 5000].map(value => <SelectItem key={value} value={String(value)}>{value}</SelectItem>)}
|
{[100, 200, 500, 1000].map(value => <SelectItem key={value} value={String(value)}>{value}</SelectItem>)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
Reference in new issue
Block a user