跳到主要内容

观测与调试

这些执行器记录查询、导出指标或提供调试与测试辅助;应评估热路径开销和数据保留策略。

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_set provider。
  • 约束:必须是 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,最大 500
      • since_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,错误信息会明确说明历史已经清除;后续维护仍可重试空间回收。
  • 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 +1
    • inflight +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 阈值。
  • 人工制造慢路径验证观测链路。