Dozzle SQL Engine 实战指南:用 DuckDB WebAssembly 在浏览器中对容器日志执行 SQL 分析
2026/9/14 17:14:39 网站建设 项目流程

Dozzle SQL Engine 实战指南:用 DuckDB WebAssembly 在浏览器中对容器日志执行 SQL 分析

【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle

Dozzle 的 SQL Engine(SQL Analytics)让你可以直接在浏览器中对容器 JSON 日志执行 SQL 查询,底层由 DuckDB 编译为 WebAssembly 运行,所有数据始终留在本机。本文以 docs/guide/sql-engine.md 为主线,结合前端分析组件、SQL 编辑器与后端日志接口的源码实现,完整讲解启用前提、工作原语、示例查询与限制边界,帮助你在不接触外部数据库的前提下快速上手实时日志分析。

功能定位与适用场景

SQL Engine 是 Dozzle 内置的一项面向日志数据的 SQL 分析能力:针对已经熟悉 SQL 的用户,把日志查看从"滚动翻页"升级为"按需查询"。它处于 beta 阶段并对所有用户开放,核心价值在于:

  • 用你熟悉的SELECT / WHERE / GROUP BY语法直接分析容器日志;
  • 全程在浏览器本地执行,数据不离开你的机器,无需把日志同步到外部数据库;
  • 适合临时性的聚合、过滤、分组与时间窗口统计等分析场景。

启用前提与快速开始

前提:日志必须是 JSON 格式

SQL Engine 只能查询结构化(JSON)日志。如果你的容器输出的是纯文本日志,需要先让应用以 JSON 形式输出日志(例如让日志行带有levelmessagetimestamp等字段),引擎才会解析出可查询的列。这一限制同时决定了:日志行解析得到的字段越多,SQL 分析能做的文章就越大。

入口:下拉菜单与快捷键

准备好 JSON 日志后:

  1. 在对应容器的日志视图上展开下拉菜单,选择SQL Analytics
  2. 也可以直接使用快捷键Ctrl+Shift+F(macOS 为Cmd+Shift+F)快速打开。

打开后默认查询为SELECT * FROM logs LIMIT 100,即先预览前 100 行,便于确认表结构和字段命名。

工作原理:WebAssembly + DuckDB 的本地 SQL 引擎

整体流程

SQL Engine 的完整链路是"后端取数 → 前端建表 → 浏览器内查询":

  1. 打开 SQL Analytics 时,前端通过/api/hosts/{host}/containers/{containerId}/logs?stdout=1&stderr=1&everything&jsonOnly接口拉取该容器的全量日志(见 LogAnalytics.vue),jsonOnly查询参数保证只返回 JSON 日志;
  2. 浏览器首次加载@duckdb/duckdb-wasm,把 DuckDB 的 WASM 模块下载并初始化到本地;
  3. 日志流被完整读取并注册为 DuckDB 的虚拟文件logs.json,随后执行建表语句,把日志展开成一张名为logs的表;
  4. 此后所有conn.query()都在浏览器进程内对这张内存表执行,结果实时呈现。

建表语句的源码细节

文档中给出的初始建表语句是:

CREATE TABLE logs AS SELECT unnest(m) FROM 'logs.json'

而 LogAnalytics.vue 中实际执行的语句更为完整:

CREATE TABLE logs AS SELECT unnest(m) FROM read_json('logs.json', ignore_errors = true, format = 'newline_delimited', map_inference_threshold = -1)

几个关键参数的语义:

  • read_json(...):以 DuckDB 的 JSON 读取器读取logs.json虚拟文件;
  • format = 'newline_delimited':按 NDJSON(每行一个 JSON 对象)解析容器日志流;
  • ignore_errors = true:跳过个别无法解析的行,避免单条坏日志中断建表;
  • map_inference_threshold = -1:让 DuckDB 在推断嵌套字段类型时不做数量截断,确保深层嵌套字段也能被展开成独立列;
  • unnest(m):把每行 JSON 展开(unnest)成表的一行记录,m是日志事件中承载消息载荷的字段。

建表完成后,前端还会执行DESCRIBE logs获取列名与列类型(LogAnalytics.vue),用于编辑器自动补全、列名列表展示以及示例查询的动态生成。

DuckDB 实例与清理

DuckDB 的加载位于 duckdb.ts:

  • 通过duckdb.getJsDelivrBundles()selectBundle()选定 WASM 资源包,再以 Blob URL 创建 Worker 线程承载AsyncDuckDB
  • 首次打开时下载 WASM 模块可能需要等待,网络较慢时尤其明显;
  • 组件卸载时依次执行conn.close()db.terminate()worker.terminate()释放内存与 Worker(duckdb.ts),避免重复打开造成资源泄漏。

这也解释了文档"内存不足时需要刷新页面"的建议:刷新页面会重建整个 DuckDB 实例,从而彻底清空内存表。

安全策略佐证

DuckDB WASM 需要从 CDN 加载并在浏览器中运行,internal/web/csp.go 中 Dozzle 的 Content-Security-Policy 为此显式放行了https://cdn.jsdelivr.nethttps://*.duckdb.orgblob:以及'wasm-unsafe-eval',进一步印证了"查询全部在浏览器本地执行"的架构。

查询编辑器:补全、语法高亮与运行

SQL 编辑器基于 CodeMirror 6 构建,实现在 sqlEditor.ts,为日志分析场景做了针对性增强:

  • 表结构与列补全:自动补全源会读取getColumns()(即DESCRIBE logs的产物),把logs表的列名、类型作为补全项;对包含.@、空格等字符的列名,会按 DuckDB 规则自动加双引号(quoteColumn,sqlEditor.ts),例如message.path这类嵌套字段;
  • 常用分析函数提示:内置count(DISTINCT ...)median()quantile_cont(..., 0.95)epoch_ms()date_trunc('minute', ...)regexp_extract(...)等面向日志的函数模板(sqlEditor.ts),按 Tab 即可填充;
  • SQL 关键字高亮:用轻量 tokenizer 对SELECT/FROM/WHERE/GROUP BY/HAVING/LIMIT/JOIN等关键字、字符串、注释、数字与操作符做语法着色;
  • Ctrl/Cmd + Enter运行:该快捷键被绑定为执行当前查询(sqlEditor.ts),而普通Enter仍用于换行;
  • 错误展示:查询出错时,会在编辑器下方以等宽字体完整展示 DuckDB 返回的错误信息(例如未加引号的非法列名),错误行采用可换行的样式以免关键信息被截断(LogAnalytics.vue)。

编辑器由 useSQLEditorField.ts 负责挂载与销毁:CodeMirror 是懒加载的,若在编辑器就绪前就点击了示例芯片,待编辑器挂载完成后会先应用待写入内容再继续使用,避免竞态问题。

示例查询实战

以下示例均以建表后的logs表为对象。日志 JSON 通常包含levelmessagetimestamp等顶层字段,以及以message.*形式展开的嵌套字段。

统计日志总数

SELECT COUNT(*) FROM logs

logs表中每一行对应一条日志,这是最快验证建表是否成功、总数据量级如何的查询。

按字段过滤

SELECT * FROM logs WHERE level = 'error'

仅返回level字段为error的日志。在 UI 上,这等价于把错误日志单独抽出来做进一步分析。

按字段分组

SELECT level, COUNT(*) FROM logs GROUP BY level

按日志级别分组统计数量,快速回答"错误、警告、信息各有多少条"。

查询嵌套 JSON 字段

SELECT message.path, message.status, message.duration FROM logs WHERE message.status >= 400 ORDER BY message.duration DESC

利用 DuckDB 的嵌套字段展开能力,直接对message对象内部的字段做过滤与排序——例如找出所有状态码 ≥ 400 的请求,并按耗时降序排列。需要注意:字段名中若含有.等特殊字符,DuckDB 要求用双引号包裹(编辑器的自动补全会自动处理,手工输入时请留意)。

按时间窗口聚合

SELECT date_trunc('minute', timestamp) AS minute, COUNT(*) AS error_count FROM logs WHERE level = 'error' GROUP BY minute ORDER BY minute DESC

date_trunc('minute', timestamp)把时间戳截断到分钟粒度,再按分钟分组统计错误数,并按时间倒序排列,非常适合观察错误随时间的分布趋势。date_trunc支持秒/分钟/小时/天等粒度,是日志时序分析最常用的函数之一。

其他高频函数

结合编辑器内置提示,以下函数在日志场景中非常实用(sqlEditor.ts):

函数用途
count(DISTINCT col)统计去重后的取值个数
avg() / min() / max() / median()数值字段的分布统计
quantile_cont(col, 0.95)95 分位数,观察长尾耗时
epoch_ms() / to_timestamp()毫秒/秒时间戳转时间
strftime(ts, '%H:%M')时间格式化
regexp_matches() / regexp_extract()正则匹配与捕获
coalesce(col, default)空值兜底
cast(col AS VARCHAR)类型转换

结果查看与导出

查询结果展示在编辑器下方的结果区域(LogAnalytics.vue):

  • 顶部会显示"共 N 条记录",如果结果超过分页上限(每页 1000 行),会提示"仅显示前 1000 条";
  • 查询执行中、建表过程中都有对应加载状态提示("Fetching container logs..."/"Creating temporary table..."/"Evaluating query...");
  • 结果表支持导出为 CSVJSON:导出按钮仅在查询有结果且非执行中时可用,导出文件名格式为{容器名}-query.{csv|json},CSV 导出会正确处理含逗号、引号、换行的字段转义(LogAnalytics.vue);
  • 点击Examples(示例)芯片可一键填入并执行内置查询:"All logs"(SELECT * FROM logs LIMIT 100)、"Row count"(SELECT count(*) AS total FROM logs)、"Count by {column}"(按level/severity/status等检测到的级别字段分组计数,自动选择第一个命中的级别列)(LogAnalytics.vue);
  • 点击Columns(列)区域可展开当前表的全部列,点击任一列名即插入到光标处,插入时同样遵循"合法标识符不加引号、否则加引号"的规则(LogAnalytics.vue)。

限制与注意事项

文档明确指出了三类限制,结合实现可以这样理解:

  • 仅支持结构化数据:SQL Engine 只能分析 JSON 日志;纯文本日志无法建表查询。这是jsonOnly接口参数与newline_delimited解析方式的必然结果;
  • 查询仅在浏览器内执行:DuckDB 运行在浏览器沙箱中,无法访问外部数据库、网络资源或其他文件。因此不要期望用 SQL 引擎 JOIN 外部数据源——它只服务于本容器日志的内存分析;
  • 最多约 4GB 内存:WebAssembly 内存上限为 4GB。日志量极大或查询聚合开销很高时可能耗尽内存,此时需要刷新页面重建 DuckDB 实例以释放内存(DuckDB 实例在组件卸载时会自动terminate,但页内无法手动回收单次查询占用的内存)。

小结

Dozzle 的 SQL Engine 用"JSON 日志 + DuckDB WASM + 浏览器内存表"的组合,把容器日志分析变成了一条即开即用的 SQL 工作流:无需部署外部数据库、无需导出数据、数据全程不出本机。上手时只需记住三个要点:日志必须是 JSON;用Ctrl+Shift+FCmd+Shift+F)打开入口;嵌套字段查询注意加引号。想深入实现细节,可以继续阅读 LogAnalytics.vue、duckdb.ts、sqlEditor.ts 以及后端日志接口 logs.go。

【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询