← 文档目录

搜索页用法与 LogsQL 速查

2026-10-11 · 适用于 Osmanthe 开发预览版 · 查询语言是 VictoriaLogs 的 LogsQL

一句话:以前只看到 200 条,是因为网页每次只取 200 条,不是数据只有 200 条。现在页面会显示“匹配多少条”和随时间的分布图,可以一页页往下加载,点柱子能缩小时间范围。显示方式有列表、表格、JSON 三种,表格的列可以自己选。查询语法看第 4 节,所有例子都在演示数据上跑过。

1. 为什么之前只看到 200 条

旧页面每次请求都写死了 limit=200,而且只显示“返回了多少条”,没有显示“一共匹配多少条”,看起来就像只有 200 条。数据一直都在,用 * | stats count() 可以看到 demo 租户里有五百多万条。

现在的做法和 Splunk、Kibana 一样:

2. 搜索页怎么用

地址:https://coding.lab.sigmax-group.com,用 demo 租户的账号登录(账号由管理员开)。默认时间范围是“最近 24 小时”。

功能怎么用
语法提示点搜索框旁边的“语法”,弹出常用写法,点任意一个例子就直接搜
时间分布图搜索后出现柱状图,每根柱子是一个时间段的条数。电脑上鼠标移上去看具体数字;点一根柱子,时间范围就缩小到这一段
列表视图每条日志一张卡片:时间、级别、服务、消息。点“全部字段”展开所有字段
表格视图一行一条,适合横向对比。手机上可以左右滑动。统计类查询(带 stats)会自动用表格显示
JSON 视图每行一条原始 JSON,方便复制给开发或贴进工单
选列点“字段”,列出这次结果里所有字段和出现次数。勾选的字段会成为表格里的一列,选择会记在浏览器里,下次还在。“恢复默认列”可以还原
看字段的常见值在“字段”面板里点字段名,显示出现最多的 10 个值和条数
一键加过滤字段值旁边的 + 表示“只看这个值”,− 表示“排除这个值”,会自动加到查询里并重新搜索。展开日志的“全部字段”里也有这两个按钮
时区默认按手机/电脑的本地时间显示,勾选 UTC 改为 UTC
分享查询查询和时间范围会写进网址 # 后面,把网址发给别人(对方要有 API Key)就能打开同一个搜索

3. 显示形式能改吗

能改,这一层完全是我们自己的代码,和 VictoriaLogs 无关。这次已经做了三种视图和自选列。后面还可以按需要加,例如:

你想先要哪种,告诉我就行。

4. LogsQL 速查

下面的例子都基于演示数据(见第 6 节字段表),在 2026-10-11 用 VictoriaLogs v1.53.0 实际跑过。查询框里写的内容会和页面上选的时间范围同时生效。

4.1 找日志(过滤)

写法意思
*全部
timeout消息里有单词 timeout。按整词匹配,time 匹配不到 timeout;区分大小写
i(TIMEOUT)不区分大小写
"card declined"精确短语
*clined*子串匹配(慢一些,数据量大时少用)
~"timeout|refused"正则
level:=ERROR字段完全等于某值
service:payment字段里有这个单词(: 是按词匹配,:= 是完全相等)
http.path:"/api/pay"*前缀匹配
service:in(payment, checkout)等于其中任意一个
http.status_code:>=500数值比较,也可以用 > < <=
duration_ms:range[1000, 5000]数值区间(含两端)
client.ip:ipv4_range(10.0.0.0/8)IP 段
error.type:*有这个字段(值不为空)
{host="payment-1"}按日志流过滤,最快。HEC 写入时 index、sourcetype、host、source 是流字段;OTLP 写入时 service.name、host.name 等是流字段
_time:1h最近 1 小时(和页面选的时间范围取交集)

4.2 组合条件

写法意思
service:=payment level:=ERROR空格就是 AND
service:=payment AND level:=ERROR同上,写明 AND
"timeout" OR "refused"或
failed -service:=gateway排除,-、!、NOT 都可以
(service:=payment OR service:=user) level:=ERROR括号分组

4.3 统计和加工(管道 |)

过滤条件后面接 |,把结果交给下一步处理,和 Splunk 的写法很像。

写法意思
level:=ERROR | stats by (service) count() as n | sort by (n desc)每个服务的错误数,从多到少
* | stats by (http.status_code) count() as n状态码分布
* | stats by (service) avg(duration_ms) as avg_ms, quantile(0.99, duration_ms) as p99平均和 P99 延迟(分位数是近似值,每次可能略有差别)
* | stats by (service) count() as total, count() if (level:=ERROR) as errors | math errors*100/total as pct | sort by (pct desc)每个服务的错误率(%)
service:=payment | stats by (_time:1h) count() as n | sort by (_time desc)按小时统计条数
* | stats by (service) count() as n | filter n:>40000统计后再过滤
level:=ERROR | top 5 by (error.type)最常见的 5 种错误
* | stats count_uniq(user.id) as users不同用户数
* | fields _time, service, user.id, _msg只保留这几个字段
level:=ERROR | sort by (duration_ms desc)按耗时从大到小
排序规则:普通搜索默认按时间从新到旧。只要查询里有 sort、stats、top、uniq、limit 这类决定顺序的管道,就按你写的顺序返回,网关不会再按时间重排。如果只用了 fields 这类管道又想按时间排,自己加 | sort by (_time desc)。

4.4 从 Splunk SPL 过来

Splunk SPLLogsQL
index=main error{index="main"} error
status=500status:=500
status>=500status:>=500
NOT host=web-1-host:=web-1
| stats count by service| stats by (service) count()
| stats dc(user) as users| stats count_uniq(user) as users
| stats perc95(duration)| stats quantile(0.95, duration)
| timechart span=1h count| stats by (_time:1h) count()
| top 5 error_type| top 5 by (error_type)
| table _time host msg| fields _time, host, _msg
| sort -count| sort by (count desc)
| where n > 100| filter n:>100
| eval pct=errors*100/total| math errors*100/total as pct
| head 10| limit 10

SPL 兼容(让客户直接写 SPL)还没做,这张表就是将来翻译器要做的事情的大致范围。

4.5 常见坑

完整语法:VictoriaLogs 官方文档 docs.victoriametrics.com/victorialogs/logsql/(英文)。

5. 用接口查(curl)

网页能做的,接口都能做。先登录拿令牌(API Key 只能写日志,不能查),令牌放在 X-API-Key 头里:

# 登录,12 小时不用就失效
TOKEN=$(curl -s https://域名/api/v1/login -H 'Content-Type: application/json' \
  -d '{"username":"你的用户名","password":"你的密码"}' | python3 -c 'import sys,json; print(json.load(sys.stdin)["token"])')

# 第 2 页,每页 100 条
curl -G https://域名/api/v1/search -H "X-API-Key: $TOKEN" \
  --data-urlencode 'q=level:=ERROR' -d limit=100 -d offset=100 \
  -d start=2026-10-10T00:00:00Z

# 总数和每小时分布
curl -G https://域名/api/v1/hits -H "X-API-Key: $TOKEN" \
  --data-urlencode 'q=level:=ERROR' -d step=1h -d start=2026-10-10T00:00:00Z

# 字段列表 / 某字段最常见的值
curl -G https://域名/api/v1/fields -H "X-API-Key: $TOKEN" --data-urlencode 'q=*'
curl -G https://域名/api/v1/field_values -H "X-API-Key: $TOKEN" -d field=service -d limit=10

现在的网址有一层密码保护,从外部用 curl 要先过那层认证;在服务器本机可以直接用 http://127.0.0.1:18101。

6. 演示数据

为了让上面的例子能查到东西,用 tools/demo_data.py 往 demo 租户写了 20 万条模拟的业务日志,分布在 2026-10-10 晚到 10-11 白天的 24 小时里,白天多、夜里少。另外还有之前压测留下的约 570 万条(内容基本都是 “the message”,service.name 是 tg-load 等),选“全部”时会混在一起。

字段例子说明
servicepaymentcheckout / payment / user / search / gateway;payment 的错误率故意设得高一些(约 6%)
levelERRORDEBUG / INFO / WARN / ERROR
http.method http.path http.status_codePOST /api/pay 502
duration_ms165.6耗时,出错时明显变长
user.idu00042约 2 万个不同用户
trace_id32 位十六进制每条都不同,高基数
client.ip region10.119.83.49 cn-hongkong
error.typetimeout只有 ERROR 有。注意:这批数据里的值是从错误信息取的第一个词(如 upstream、connect()),之后已把生成器改成规范的类型名(timeout、card_declined 等),重新灌数据后生效
流字段index=demo, sourcetype=app/nginx, host=payment-1可以用 {index="demo"} 只看演示数据

想再灌一批:python3 tools/demo_data.py --events 200000 --hours 24。