观测与调试
这些执行器记录查询、导出指标或提供调试与测试辅助;应评估热路径开销和数据保留策略。
learn_domain
实验性插件(v1.2.0 引入)
learn_domain 在 v1.2.0 首次发布,目前处于实验阶段:过滤条件、写入触发时机与配套 dynamic_domain_set 的接口可能在后续版本调整。生产部署前请评估学习速率与磁盘写入对持久化层的影响。
作用
观察 DNS 流水线中的请求域名,并把命中的 qname 写入指定 dynamic_domain_set。它只产生副作用,不修改请求或响应。
配置示例
- tag: learned_allow
type: dynamic_domain_set
args:
path: "/etc/oxidns/learned-allow.txt"
- tag: learn_allow
type: learn_domain
args:
provider: learned_allow
phase: after
questions: first
qtypes: ["A", "AAAA"]
success_only: true
answer_required: true
rule_kind: full
async: true
error_mode: continue
timeout: 1s
配置项
provider
- 类型:
string;必填:是 - 作用:引用目标
dynamic_domain_setprovider。 - 约束:必须是
dynamic_domain_set,不能引用普通domain_set。
phase
- 类型:
string;必填:否;默认值:after - 可选值:
before、after - 作用:
before:在后续 executor 执行前学习 request question。after:先执行后续链路,再根据响应结果决定是否学习。
questions
- 类型:
string;必填:否;默认值:first - 可选值:
first、all - 作用:控制学习第一个 question 或所有 question。
qtypes
- 类型:
array;必填:否;默认值:["A", "AAAA"] - 作用:只学习指定 DNS 查询类型。
success_only
- 类型:
bool;必填:否;默认值:true - 作用:仅
phase: after生效,要求响应 RCODE 为NOERROR。
answer_required
- 类型:
bool;必填:否;默认值:true - 作用:仅
phase: after生效,要求响应包含 answer。
rule_kind
- 类型:
string;必填:否;默认值:full - 可选值:
full、domain - 作用:控制学习到
dynamic_domain_set的规则类型。
async
- 类型:
bool;必填:否;默认值:true - 作用:控制是否只入队后继续执行。设为
false时会等待 provider 写入完成。
error_mode
- 类型:
string;必填:否;默认值:continue - 可选值:
continue、stop、fail - 作用:控制学习失败后的执行结果。
timeout
- 类型:
duration;必填:否;默认值:1s - 作用:仅
async: false时用于限制等待 provider 写入的时间。
行为说明
- 学习域名会规范化为小写并移除尾部
.。 - 默认生成
full:example.com精确规则,避免意外扩大匹配范围。 phase: after默认只学习成功且有 answer 的A/AAAA响应。phase: before不检查响应条件。- v1 只学习请求 question 的 qname,不学习 CNAME target。
典型用途
- 把成功解析过的域名加入动态放行列表。
- 把某个分支中的域名沉淀到本地文件,供后续
qname $learned_allow或父级domain_set使用。
query_summary
作用
在后续链路执行完后输出紧凑查询摘要。
配置示例
- tag: summary_main
type: query_summary
args:
# 日志标题;便于区分不同链路
msg: "main pipeline"
配置项
msg
- 类型:
string;必填:否;默认值:"query summary" - 作用:定义摘要日志标题。
quick setup
- exec: "query_summary main"
行为说明
- 正向阶段记录开始时间。
- 回程阶段输出:
- 来源地址
- qname
- qtype
- rcode
- elapsed_ms
典型用途
- 低成本链路追踪。
- 分支延时对比。
query_recorder
作用
记录 DNS 查询、响应和执行路径,帮助排查解析异常、分析插件命中情况,并提供历史统计和实时查询日志。
自动合并重复内容并无损压缩较大的响应,无需额外配置。实际空间收益取决于查询内容,低重复率场景也可能增加占用。
升级到 v2
升级后自动使用新存储,配置和现有 API 保持兼容。查询历史将重新积累,旧历史不再显示。 旧数据不会自动删除,仍占用磁盘空间;“清空历史”和保留期清理也不会删除它们。
要手动释放空间:先确认 path 的实际位置(相对路径以运行工作目录为基准),停止 OxiDNS 并备份数据库。如果该 SQLite 文件只供目标 recorder 使用,删除数据库文件及同名 -wal、-shm 文件,再启动服务;这样会同时清空该 recorder 的 v1 和 v2 历史。若多个 recorder 共用文件,不要删除整个文件;需要在备份后按 tag 辨识并单独清理旧 v1 表,避免丢失其他 recorder 的记录。
配置示例
- tag: query_recorder_main
type: query_recorder
args:
# SQLite 文件路径;多个 recorder 可以共用同一文件
path: "./data/query-recorder-main.sqlite"
# 热路径入队缓冲大小
queue_size: 8192
# 后台批量写入条数
batch_size: 256
# 后台批量 flush 间隔,单位毫秒
flush_interval_ms: 200
# 内存中保留多少条最近记录,供 SSE tail 回放
memory_tail: 1024
# 日志保留天数;最小 1
retention_days: 7
# 定时清理周期,单位小时;最小 1
cleanup_interval_hours: 1
# SQLite 读取侧最大并发数;最小 1
reader_concurrency: 2
配置项
path
- 类型:
string;必填:是 - 作用:指定当前 recorder 的 SQLite 文件路径。
queue_size
- 类型:
integer;必填:否;默认值:8192 - 作用:定义热路径到后台写线程的有界队列大小。
batch_size
- 类型:
integer;必填:否;默认值:256 - 作用:定义后台批量写入 SQLite 的单批记录数。
flush_interval_ms
- 类型:
integer;必填:否;默认值:200 - 作用:定义后台写线程的批量 flush 间隔。
memory_tail
- 类型:
integer;必填:否;默认值:1024 - 作用:定义最近记录的内存 tail 长度,用于
stream?tail=n回放。
retention_days
- 类型:
integer;必填:否;默认值:7 - 最小值:
1 - 作用:定义日志保留天数;过期数据会被定时实际删除。
cleanup_interval_hours
- 类型:
integer;必填:否;默认值:1 - 最小值:
1 - 作用:定义过期清理任务的执行周期。
reader_concurrency
- 类型:
integer;必填:否;默认值:2 - 最小值:
1 - 作用:限制 WebUI / API 统计与历史查询同时运行的 SQLite reader 数量,避免突发读取在大库上占用过多阻塞线程和内存。
行为说明
- 通过
retention_days控制保留天数,过期记录按cleanup_interval_hours定时清理。少量删除后文件可能不会立即变小,释放的空间可供后续记录复用。 - 多个 recorder 可以共用数据库文件;记录按 tag 隔离,清空一个不会删除其他 recorder 的历史。
client_ip是 OxiDNS 看到的来源地址。经过本机转发时可能显示127.0.0.1,而非真实终端 IP。- 较旧数据库首次回收空间时可能需要额外临时磁盘空间,并短暂影响历史查询和记录写入;DNS 解析继续运行。
数据结构约定
API 返回字段示例
questions_json固定为 question 数组,例如:
[
{ "name": "www.example.com.", "qtype": "A", "qclass": "IN" }
]
answers_json、authorities_json、additionals_json、signature_json固定为 RR 数组,例如:
[
{
"name": "www.example.com.",
"class": "IN",
"ttl": 300,
"rr_type": "A",
"payload_kind": "A",
"payload_text": "192.0.2.1",
"payload": { "ip": "192.0.2.1" }
}
]
req_edns_json、resp_edns_json固定为 EDNS 对象或NULL。
API
GET /plugins/<tag>/records- 按
created_at_ms倒序分页返回主表记录。 - 查询参数:
cursor=<created_at_ms>:<id>limit=<n>,默认100,最大500since_ms=<unix_ms>until_ms=<unix_ms>qname=<text>,按请求问题名包含匹配client_ip=<text>,按客户端 IP 字符串包含匹配qtype=<type>/rcode=<rcode>/status=all|error|has_response|no_response
- 按
GET /plugins/<tag>/records/<id>- 返回单条完整记录,并附带
steps。
- 返回单条完整记录,并附带
DELETE /plugins/<tag>/records- 清空当前 recorder 的 v2 历史和实时回放缓存,保留旧版历史及其他 recorder 的数据。返回
cleared_records表示删除的记录数。 - 若历史已删除但磁盘回收失败,接口返回
query_recorder_clear_failed,错误信息会明确说明历史已经清除;后续维护仍可重试空间回收。
- 清空当前 recorder 的 v2 历史和实时回放缓存,保留旧版历史及其他 recorder 的数据。返回
GET /plugins/<tag>/stats/plugins- 返回按
matcher / executor / builtin聚合的命中统计。 - 支持
since_ms、until_ms、kind=matcher|executor|builtin|all和 records 的过滤参数。
- 返回按
GET /plugins/<tag>/stats/top_clients/stats/top_qnames- 返回客户端 IP 或 QNAME 排行。
- 支持
limit=<n>,默认20;后端不再强制200上限。 - 支持 records 的时间范围与过滤参数。
GET /plugins/<tag>/stats/qtype/stats/rcode- 返回 QTYPE 或 RCODE 分布。
- 支持 records 的时间范围与过滤参数。
GET /plugins/<tag>/stats/latency- 返回延迟摘要、直方图和慢查询排行。
- 支持
slow_limit=<n>或limit=<n>,默认20;后端不再强制200上限。
GET /plugins/<tag>/stats/timeseries- 返回按分钟或小时聚合的查询趋势。
- 支持
bucket=minute|hour和buckets=<n>(默认60,最大720)。
GET /plugins/<tag>/stream- 以 SSE 实时推送新写入记录。
- 支持
tail=<n>回放最近n条内存 tail。 - 客户端应发送
Accept: text/event-stream,并容忍 heartbeat、错误事件、空 payload 和短暂断连。
典型用途
- 持久化审计和问题排查。
- 分析
sequence执行路径、插件命中率和异常分支。 - 给控制面或外部面板提供实时查询日志流。
注意事项
- 想要拿到完整主链路路径,推荐把 recorder 放在入口附近。
- 如果前置分支在 recorder 之前就短路返回,该请求不会被当前 recorder 记录。
- 若
next报错而server后续补发了兜底响应,数据库里仍只记录插件视角下的error和空 response。 - 若未启用管理 API,recorder 仍会写库,但不会暴露查询与 SSE 路由。
- 若需要真实终端 IP,请让客户端直连 OxiDNS,或在 HTTP/DoH 反向代理场景配置可信的
src_ip_header。
metrics_collector
作用
收集轻量级请求计数与延时指标,并导出 Prometheus 格式。
配置示例
- tag: metrics_main
type: metrics_collector
args:
# 指标名称标签;导出到 /api/metrics 时会带上它
name: "main"
配置项
name
- 类型:
string;必填:否;默认值:"default" - 作用:定义当前指标收集器的名称标签。
quick setup
- exec: "metrics_collector main"
行为说明
- 正向阶段:
query_total +1inflight +1- 记录开始时间
- 回程阶段:
inflight -1- 若无响应则
err_total +1 - 若有响应则累计延时
API
GET /api/metrics- Prometheus 文本格式,全局唯一;其它插件的内置 metrics 也会汇总到同一接口。
典型用途
- 主链路观测。
- 多条策略入口延时对比。
debug_print
作用
打印请求与响应对象,便于调试。
配置示例
- tag: debug_main
type: debug_print
args:
# 日志标题;未配置时默认是 "debug print"
msg: "before forward"
msg- 可选日志标题。
- 默认
"debug print"。
配置项
msg
- 类型:
string;必填:否;默认值:"debug print" - 作用:定义日志输出标题。
quick setup
- exec: "debug_print cache branch"
典型用途
- 排查 sequence 分支。
- 验证请求和响应在插件前后是否被改写。
sleep
作用
异步延迟,用于测试和策略实验。
配置示例
- tag: sleep_100ms
type: sleep
args:
# 额外异步延迟 100ms
duration: 100
配置项
duration
- 类型:
integer;必填:否;默认值:0 - 单位:毫秒
- 作用:定义当前请求在该执行器上的额外异步等待时间。
quick setup
- exec: "sleep 100"
典型用途
- 测试
fallback阈值。 - 人工制造慢路径验证观测链路。