MongoDB慢查询需先在服务端启用profiling:db.setProfilingLevel(1, { slowms: 100 }),日志写入system.profile;该集合不支持changeStream,须轮询并建ts索引;Node.js驱动可监听commandStarted/Succeeded事件实现客户端耗时统计;APM集成需匹配版本、显式开启查询详情采集,并手动注入trace上下文。

如何开启 MongoDB 的慢查询日志(serverStatus + profile)
Node.js 本身不直接捕获 MongoDB 慢查询,真正起作用的是 MongoDB 服务端的 profiling 机制。必须先在数据库侧打开慢操作记录,否则任何 Node.js 层的监听都无从谈起。
常见错误是只在应用里加监听,却没开 db.setProfilingLevel(),结果永远收不到慢查询事件。
- 连接到目标数据库后执行:
db.setProfilingLevel(1, { slowms: 100 })</li> <li><code>slowms是毫秒阈值,设为100表示记录所有 >100ms 的操作(生产建议从 200–500 开始,避免日志爆炸) - 级别
1只记录慢操作;2记录全部(仅调试用,严禁上生产) - 配置生效后,慢查询会写入
system.profile集合,可通过db.system.profile.find()查看
用 changeStream 监听 system.profile 是否可行?
不行。MongoDB 的 system.profile 是一个特殊 capped collection,不支持 changeStream —— 尝试监听会直接报错 NamespaceNotFound 或 CommandNotSupported。
这是最容易踩的坑:看到“能监听集合变更”,就想当然套用到 system.profile 上。
- 替代方案只有轮询:
db.system.profile.find({ ts: { $gt: lastSeenTs } }).sort({ ts: 1 }) - 每次查询后更新
lastSeenTs,避免重复读取 - 注意加索引:
db.system.profile.createIndex({ ts: 1 }),否则轮询性能极差 - 轮询间隔建议 ≥1s,太频繁会增加数据库压力
在 Node.js 中用 driver 做轻量级慢查询拦截(driver-level hook)
MongoDB Node.js Driver 4.0+ 支持命令监控(commandStartedEvent 和 commandSucceededEvent),可在驱动层统计耗时,无需依赖服务端 profiling。
适合快速定位本应用发出的慢查询,但无法捕获其他客户端或 shell 执行的操作。
- 初始化 client 时传入
monitorCommands: true - 监听
commandStarted记下event.requestId和event.connectionId对应的开始时间 - 在
commandSucceeded中用当前时间减去开始时间,判断是否超阈值(如 >200ms) - 注意:
commandFailed也要监听,否则超时/中断的请求无法计算真实耗时 - 示例关键片段:
client.on('commandStarted', event => { startTimes.set(event.requestId, Date.now()) });
APM 工具集成(DataDog / New Relic / Sentry)要注意什么?
APM 不是“装上就灵”。MongoDB 驱动版本、APM SDK 版本、是否启用命令监控,三者必须匹配,否则根本看不到 query 耗时详情。
最常被忽略的是:默认情况下 APM 只采集事务或 span 名称,不自动展开 query 内容和执行时间,需显式开启。
- DataDog:确保
mongodb插件已启用,且service配置正确;检查dd-trace版本 ≥2.10(旧版对 driver 5.x 支持不全) - New Relic:必须设置
attributes.include = ["db.statement", "db.collection"],否则只显示 “mongodb” 而不是具体命令 - Sentry:需手动 wrap
collection.find等方法,官方 SDK 对 MongoDB 的自动 instrumentation 支持有限 - 所有工具都要确认:是否采集了
duration字段?是否把filter或update参数脱敏?否则可能泄露敏感数据
真正难的不是接入,而是让每条慢查询都能关联到具体代码行、用户 ID 和请求上下文——这需要你在业务逻辑里主动注入 trace context,不能只靠 APM 自动抓。

















