MongoDB
Monitor MongoDB - operations, latency, replication, sharding, the WiredTiger cache, and the log.
Your MongoDB servers show up alongside the rest of your telemetry, on dashboards that are already built. You can see how hard each server is working and where it is struggling - latency, connections, queues, and the WiredTiger cache - across your replica sets and sharded clusters, with the servers' logs, and get alerted when a server stops reporting, a member goes down, a secondary falls behind, or operations start to queue.
What this integration does
It provisions dashboards and alert rules. It does not collect anything itself - Grafana Alloy has a MongoDB exporter built in, so collecting metrics needs a user on the server and a few lines of Alloy config, and the log needs a few more. This covers MongoDB 7.0 and later - standalone servers, replica sets, and sharded clusters. Until Alloy is collecting, the dashboards are empty.
Navigate to Integrations from the left-hand sidebar, then select MongoDB.
Permission tiers
MongoDB runs Read-only, the default. It requires a MongoDB user with the clusterMonitor role, read access to the MongoDB log for Alloy, and an OpsPilot API key.
Its capabilities are Dashboards and Alerts.
Grafana's own docs cover the exporter in full: see prometheus.exporter.mongodb for every option, and install Alloy on each MongoDB host if you want the log (Alloy reads it from disk), or anywhere that can reach each server's port for metrics alone.
1. Create a monitoring user
Alloy logs in to read the server's status. Give it a user of its own with MongoDB's built-in read-only clusterMonitor role, rather than an administrator or an application's user. In mongosh:
db.getSiblingDB("admin").createUser({
user: "opspilot_exporter",
pwd: passwordPrompt(),
roles: [{ role: "clusterMonitor", db: "admin" }],
})
Run it once on each replica set's primary; it reaches the other members by replication. In a sharded cluster, run it through a mongos, and once more on each shard's primary - a connection straight to a shard member checks the shard's own users.
2. Configure Alloy
Alloy's config file is in a different place on each system:
| OS | Config file | After a change |
|---|---|---|
| Linux | /etc/alloy/config.alloy |
sudo systemctl restart alloy |
| Windows | C:\Program Files\GrafanaLabs\Alloy\config.alloy |
restart the Alloy service in services.msc |
| macOS | $(brew --prefix)/etc/alloy/config.alloy |
brew services restart grafana/grafana/alloy |
Keep the password in a file of its own beside it, readable only by Alloy. URL-encode it, because it goes inside a mongodb:// URI - a raw @ fails the login, and a raw :, #, /, ?, or % stops the exporter starting.
On Linux, this asks for the password and writes it encoded:
python3 -c 'import getpass, urllib.parse; print(urllib.parse.quote(getpass.getpass(), safe=""), end="")' | sudo tee /etc/alloy/mongodb-password >/dev/null
sudo chown root:alloy /etc/alloy/mongodb-password
sudo chmod 640 /etc/alloy/mongodb-password
On Windows, in an administrator PowerShell:
Set-Content -NoNewline -Path "$env:ProgramFiles\GrafanaLabs\Alloy\mongodb-password" -Value ([uri]::EscapeDataString((Read-Host "Password")))
On macOS, the first line alone, writing to $(brew --prefix)/etc/alloy/mongodb-password without sudo.
Warning
The file must hold the encoded password and nothing else: a trailing newline, which most editors add, makes the login fail.
Then add to the config file, with one exporter per mongod and mongos:
local.file "mongodb_password" {
// Windows: "C:/Program Files/GrafanaLabs/Alloy/mongodb-password"
filename = "/etc/alloy/mongodb-password"
is_secret = true
}
prometheus.exporter.mongodb "db" {
mongodb_uri = "mongodb://opspilot_exporter:" + local.file.mongodb_password.content + "@dbhost:27017/admin"
direct_connect = true
collect_all = false
enable_diagnostic_data = true
enable_db_stats = true
}
prometheus.scrape "db" {
targets = prometheus.exporter.mongodb.db.targets
scrape_interval = "30s"
forward_to = [prometheus.relabel.mongodb.receiver]
}
prometheus.relabel "mongodb" {
forward_to = [prometheus.remote_write.opspilot.receiver]
rule {
source_labels = ["__name__"]
regex = "mongodb_(ss|sys|oplog_stats|dbstats|config|local|admin)_.*"
action = "drop"
}
}
A few things matter here:
collect_all = false. Left at its default, the exporter also collects statistics for every collection and index, with the collection's name in the metric's name - thousands of series per server, and more with every collection you add. The two collectors enabled here are what the dashboards read.- The relabel rule drops raw duplicates. The diagnostic data arrives twice: as the named metrics the dashboards read, and as some 5,500 raw series per server that nothing here uses. Dropping them leaves 200 to 350 per server.
direct_connect = truefor each server. Without it, pointed at one replica set member, the exporter finds the primary and reports the primary's numbers under that member's name.- Leave
jobalone. Alloy labels these metricsjob="integrations/mongodb"whatever you call the blocks, and the dashboards and alerts select on that, so add nojob_nameand no relabel rule forjob. Each server appears as thehost:portin its URI. - One exporter per server. For each further
mongodormongos, add another exporter and scrape with different names, all forwarding to the same relabel block.
3. Send data to OpsPilot
You need an OpsPilot API key, from Data and Licenses > API Keys. Put it in a file the same way, as opspilot-api-key beside the config file, and add:
local.file "opspilot_api_key" {
// Windows: "C:/Program Files/GrafanaLabs/Alloy/opspilot-api-key"
filename = "/etc/alloy/opspilot-api-key"
}
prometheus.remote_write "opspilot" {
endpoint {
url = "https://api.opspilot.com/v1/metrics"
headers = {
"authorization" = string.trim_space(local.file.opspilot_api_key.content),
}
}
}
Using environment variables instead
Environment variables work in place of files if you already manage Alloy's settings that way: write sys.env("MONGODB_EXPORTER_PASSWORD") in place of local.file.mongodb_password.content, and likewise for the key. Alloy reads its environment from /etc/default/alloy (Debian, Ubuntu), /etc/sysconfig/alloy (RHEL, SUSE), $(brew --prefix)/etc/alloy/config.env (macOS), or on Windows the Environment value of the registry key HKEY_LOCAL_MACHINE\SOFTWARE\GrafanaLabs\Alloy.
4. Collect the log
This needs Alloy on the same machine as the server, since it reads the file. The log's path is systemLog.path in the server's config file (/etc/mongod.conf on Linux, mongod.cfg beside mongod.exe on Windows); the packages use /var/log/mongodb/mongod.log. Use it here, with the same instance the metrics have - dbhost:27017 - so the dashboards line up:
loki.source.file "mongodb_log" {
targets = [{
// Windows: "C:/Program Files/MongoDB/Server/8.0/log/mongod.log"
__path__ = "/var/log/mongodb/mongod.log",
job = "integrations/mongodb",
instance = "dbhost:27017",
}]
forward_to = [loki.process.mongodb_log.receiver]
}
loki.process "mongodb_log" {
stage.json {
expressions = { ts = "t.\"$date\"", s = "s", component = "c", id = "id" }
}
stage.drop {
source = "id"
expression = "^(22943|22944|51800|5286306|6788604|6788700|10483900)$"
}
stage.timestamp {
source = "ts"
format = "RFC3339"
}
stage.drop {
older_than = "24h"
}
stage.template {
source = "level"
template = "{{ $s := .s }}{{ if eq $s \"F\" }}fatal{{ else if eq $s \"E\" }}error{{ else if eq $s \"W\" }}warning{{ else if eq $s \"I\" }}info{{ else }}debug{{ end }}"
}
stage.labels {
values = { level = "", component = "" }
}
forward_to = [loki.write.opspilot.receiver]
}
loki.write "opspilot" {
endpoint {
url = "https://api.opspilot.com/logs/v1/"
headers = {
"authorization" = string.trim_space(local.file.opspilot_api_key.content),
}
}
}
Keep the stages as they are. MongoDB writes its log as JSON; the stages take each entry's time from it, turn its severity and component into the labels the log dashboard filters on, and drop connection churn - every client connecting, authenticating, and leaving, the exporter's own scrapes included - which is most of the log by volume. Failed logins are kept. The last 24 hours are sent when Alloy first starts, and nothing older.
On Linux, let Alloy read the file. MongoDB creates its log readable by its own user only. Add this to /etc/mongod.conf and restart MongoDB, so the log is readable by its group:
Then add Alloy to that group and restart Alloy: sudo usermod -aG mongodb alloy on Debian and Ubuntu, sudo usermod -aG mongod alloy on RHEL and its relatives. On Windows, Alloy runs as LocalSystem and can read the log as it is; write the path with forward slashes, as in the comment.
5. Confirm the data arrived
In OpsPilot, open Explore, select the Metrics data source, and run:
You should get one series per server, reading 1. 0 means Alloy cannot log in, and no result at all that it cannot reach the server - either way the Alloy log for prometheus.exporter.mongodb says why.
For the log, select the Logs data source and run {job="integrations/mongodb"}. If nothing comes back, the Alloy log for loki.source.file says whether it could open the file.
Once data is flowing, the Dashboard data column on Your installation (for example 4 of 4 with data) links straight to the provisioned dashboards.
Need more help?
Contact support in the chat bubble and let us know how we can assist.