MongoDB Integration
Monitor MongoDB operations, query performance, storage growth, index usage and replica set health from a single Watchlog agent.
The agent runs mongosh once per collection cycle and derives everything from that single round-trip — server status, per-database and per-collection storage, index usage, replication, and slow queries when you have profiling enabled.
Supported Platforms
Requirements
mongosh is required
Advanced collection needs mongosh, not the legacy mongo shell. The collection script uses the Promise-based shell API, which the old shell does not provide.
If only mongo is present the agent falls back to the basic collector automatically — you keep uptime, connections, memory and operation counters, but not the per-database, per-collection, index or slow-query detail. Install mongosh and the richer tabs appear on the next cycle.
| Requirement | Notes |
|---|---|
| MongoDB 4.4+ | Tested against 4.4, 5.x, 6.x and 7.x |
mongosh on the agent's host | Must be on PATH |
| A monitoring user | See below — administrator rights are not needed |
Required Privileges
The built-in clusterMonitor role covers almost everything. Add read on the databases you want storage and index detail for:
use admin
db.createUser({
user: "watchlog_monitor",
pwd: "your_password",
roles: [
{ role: "clusterMonitor", db: "admin" },
{ role: "readAnyDatabase", db: "admin" }
]
})
If you would rather not grant readAnyDatabase, grant read per database instead — the databases you do not grant simply do not appear.
What each privilege buys:
| Command | Needs | Without it |
|---|---|---|
serverStatus | clusterMonitor | The integration cannot report at all |
listDatabases, dbStats | clusterMonitor | No per-database storage |
collStats, listCollections | read on the database | No per-collection detail |
$indexStats | read on the database | No index usage — unused-index detection is off |
replSetGetStatus | clusterMonitor | No replication tab (a standalone rejects this normally — that is not an error) |
system.profile read | read on the database | No slow queries |
What Watchlog Collects
Server Version, uptime, current and available connections, resident and virtual memory, operation counters (insert, query, update, delete, command), network in/out and request count, and per-interval latency averages for reads, writes, commands and transactions.
WiredTiger Cache used against configured maximum, dirty cache percentage, and read/write ticket availability — the signal that the storage engine is the bottleneck rather than the query.
Databases and collections Per database: data size, storage size, index size, object count, average object size, collection and index counts. Per collection: documents, size, storage, index size, index count, and capped status.
Indexes Per index: size and accesses since the server started, with unused-index candidates flagged. Primary key and unique indexes are never proposed for removal — they enforce correctness, not performance.
Replication Set name, member states and health, elected primary, per-member replication lag, and election counts.
Slow queries (when profiling is enabled — see below) Namespace, operation, duration, documents examined against returned, plan summary, and the normalized query shape.
Health Score and Insights
Watchlog computes a 0–100 score server-side, with a written reason attached to every deduction:
| Signal | Judged on |
|---|---|
| Connection pool | Share of available connections in use — 70% warns, 90% is critical |
| WiredTiger cache | Cache fill, and dirty percentage separately — a full cache is normal, a dirty one is eviction pressure |
| Operation latency | Per-interval average, not the since-boot average a month-old server reports |
| Lock queue | Operations queued on the global lock |
| WiredTiger tickets | Read and write tickets remaining — exhaustion means requests are waiting for the engine |
| Replication | Per-member lag and any member reporting health 0 |
Insights add the interpretation: collections scanning far more documents than they return, indexes that recorded zero accesses, databases growing unusually fast, and replica members falling behind.
Slow Queries
MongoDB writes slow operations to system.profile, but only when the database profiler is enabled — and it is off by default.
Watchlog never enables the profiler
Profiling has a real write cost on a busy database. Watchlog will not turn it on for you, with or without a prompt. You enable it on the databases you want traced, and the agent collects what MongoDB writes from then on.
// Profile operations slower than 100ms on this database
use myapp
db.setProfilingLevel(1, { slowms: 100 })
Then enable collection in the agent config:
"slowQuery": {
"enabled": true,
"threshold": 100,
"maxPerScrape": 100
}
The agent tracks a high-water mark per instance, so the same profile document is never shipped twice, and never re-shipped after a restart.
Query text is normalized before it leaves your host. Literal values are replaced with placeholders, so the stored shape is { userId: "?", status: "?" } rather than your customers' data.
Collection Intervals
| Section | Interval |
|---|---|
| Server status, operations, latency, replication | every collection cycle (60s) |
| Per-database and per-collection storage | 300s |
| Index usage | 300s |
| Slow queries | every cycle, from the profiler high-water mark |
Walking every collection every minute is the main way a monitoring agent becomes the problem it was installed to detect — hence the throttles. Both are configurable.
Safety
Watchlog is read-only. It never runs any of the following:
enabling the profiler · dropDatabase / drop · createIndex / dropIndex · compact · reIndex · killOp · setParameter · fsync · any write to any collection
Arguments are passed to mongosh with execFile, never through a shell — so a password containing a quote or ; cannot break out into the command line.
Advanced Options
{
"service": "mongodb",
"monitor": true,
"host": "localhost",
"port": "27017",
"username": "watchlog_monitor",
"password": "your_password",
"authDatabase": "admin",
"tls": false,
"advanced": {
"enabled": true,
"storage": true,
"indexes": true,
"replication": true,
"maxDatabases": 50,
"maxCollectionsPerDatabase": 100,
"maxCollections": 300,
"storageIntervalSeconds": 300,
"indexIntervalSeconds": 300
},
"slowQuery": {
"enabled": false,
"threshold": 100,
"maxPerScrape": 100
}
}
| Field | Default | Purpose |
|---|---|---|
authDatabase | admin | Where the monitoring user is defined |
tls | false | Adds --tls to the shell invocation |
advanced.storage | true | Per-database and per-collection statistics |
advanced.indexes | true | Index usage and unused-index detection |
advanced.replication | true | Replica set status |
advanced.maxCollections | 300 | Total collections per scrape, across all databases |
slowQuery.enabled | false | Reads system.profile — needs the profiler on |
Large deployments
maxDatabases, maxCollectionsPerDatabase and maxCollections bound how much the agent walks per cycle. On a deployment with thousands of collections, raise storageIntervalSeconds before raising the caps — the traversal cost is what matters, not the payload.
Multiple Instances
Add one entry per instance. Each is identified by its host:port:
[
{
"service": "mongodb",
"monitor": true,
"host": "127.0.0.1",
"port": "27017",
"username": "watchlog_monitor",
"password": "your_password"
},
{
"service": "mongodb",
"monitor": true,
"host": "127.0.0.1",
"port": "27018",
"username": "watchlog_monitor",
"password": "your_password"
}
]
Troubleshooting
| Symptom | Cause |
|---|---|
| Only basic metrics appear | mongosh is not installed or not on the agent's PATH. The agent fell back to the legacy collector. |
| Replication tab missing | The instance is a standalone. replSetGetStatus rejecting on a standalone is normal, not an error. |
| No per-collection data | The monitoring user lacks read on that database, or advanced.storage is off. |
| Slow Queries tab empty | The profiler is not enabled, or slowQuery.enabled is false. Both are required. |
| Authentication failed | Check authDatabase — the user is usually defined in admin, not in the application database. |
| Storage numbers look stale | They refresh every 300s by design, not every 60s. |
