# MongoDB

> Monitor MongoDB database performance, slow queries, and memory usage with OpenTelemetry and Last9

Source: https://last9.io/docs/integrations/databases/mongodb/

Use OpenTelemetry to instrument your self-hosted MongoDB database and send telemetry data to Last9. This integration collects metrics, parses structured JSON logs, and extracts slow query details into structured attributes for analysis.

## Prerequisites

Before setting up MongoDB monitoring, ensure you have:

- MongoDB 4.x or 5.x+ installed and running
- Administrative access to create MongoDB users and roles
- OpenTelemetry Collector binary or container runtime
- Last9 account with integration credentials

## Database Setup

The setup process varies slightly between MongoDB versions. Choose the appropriate section for your MongoDB version:

**MongoDB 4.x**

1. **Create Monitoring Role and User**

   Log into your MongoDB instance and create a custom role for index access metrics and a least-privilege monitoring user:

   ```javascript
   use admin

   // Custom role for index access metrics (mongodb.index.access.count)
   db.createRole({
       role: "indexStatsRole",
       privileges: [
           {
               resource: { db: "admin", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "config", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "local", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           }
       ],
       roles: []
   })

   // Create monitoring user with least-privilege roles (NO root access)
   db.createUser({
       user: "otel",
       pwd: "YOUR_SECURE_PASSWORD",
       roles: [
           { role: "clusterMonitor", db: "admin" },  // Required: serverStatus, dbStats, top
           { role: "read", db: "local" },             // Required: replica set oplog monitoring
           { role: "indexStatsRole", db: "admin" }    // Required: index access metrics
       ],
       mechanisms: [ "SCRAM-SHA-1" ]
   })
   ```

2. **Configure MongoDB Settings**

   Edit `/etc/mongod.conf` to enable monitoring features:

   ```yaml
   storage:
     dbPath: /var/lib/mongodb
     journal:
       enabled: true

   systemLog:
     destination: file
     logAppend: true
     path: /var/log/mongodb/mongod.log

   net:
     port: 27017
     bindIp: 0.0.0.0

   processManagement:
     timeZoneInfo: /usr/share/zoneinfo

   security:
     authorization: enabled

   operationProfiling:
     mode: all
     slowOpThresholdMs: 100

   setParameter:
     diagnosticDataCollectionEnabled: true
   ```

3. **Restart MongoDB Service**

   ```bash
   sudo systemctl restart mongod
   ```

**MongoDB 5.x+**

1. **Create Monitoring Role and User**

   Log into your MongoDB instance and create a custom role for index access metrics and a least-privilege monitoring user:

   ```javascript
   use admin

   // Custom role for index access metrics (mongodb.index.access.count)
   db.createRole({
       role: "indexStatsRole",
       privileges: [
           {
               resource: { db: "admin", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "config", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "local", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           },
           {
               resource: { db: "", collection: "system.profile" },
               actions: [ "indexStats", "find" ]
           }
       ],
       roles: []
   })

   // Create monitoring user with least-privilege roles (NO root access)
   db.createUser({
       user: "otel",
       pwd: "YOUR_SECURE_PASSWORD",
       roles: [
           { role: "clusterMonitor", db: "admin" },  // Required: serverStatus, dbStats, top
           { role: "read", db: "local" },             // Required: replica set oplog monitoring
           { role: "indexStatsRole", db: "admin" }    // Required: index access metrics
       ],
       mechanisms: [ "SCRAM-SHA-1", "SCRAM-SHA-256" ]
   })
   ```

2. **Configure MongoDB Settings**

   Add the following to `/etc/mongod.conf`:

   ```yaml
   operationProfiling:
     mode: all
     slowOpThresholdMs: 100

   setParameter:
     diagnosticDataCollectionEnabled: true
   ```

3. **Restart MongoDB Service**

   ```bash
   sudo systemctl restart mongod
   ```

## Install OpenTelemetry Collector

Choose the appropriate binary for your system architecture:

**AMD64**

```bash
sudo apt-get update
sudo apt-get -y install wget systemctl
wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.144.0/otelcol-contrib_0.144.0_linux_amd64.deb
sudo dpkg -i otelcol-contrib_0.144.0_linux_amd64.deb
```

**ARM64**

```bash
sudo apt-get update
sudo apt-get -y install wget systemctl
wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.144.0/otelcol-contrib_0.144.0_linux_arm64.deb
sudo dpkg -i otelcol-contrib_0.144.0_linux_arm64.deb
```

## Configure OpenTelemetry Collector

1. **Create Collector Configuration**

   Create the collector configuration file at `/etc/otelcol-contrib/config.yaml`.

   **Note:** The MongoDB connection string format varies based on version:

   - For MongoDB 4.0-4.3: `"127.0.0.1:27017/?authSource=admin&tls=false&directConnection=true"`
   - For MongoDB ≥ 4.4 and 5.x+: `"127.0.0.1:27017/?authSource=admin&directConnection=true"`

   Replace `MONGODB_USERNAME` and `MONGODB_PASSWORD` with your actual MongoDB credentials.

   ```yaml
   receivers:
     filelog:
       include: [/var/log/mongodb/*.log]
       include_file_path: true
       start_at: end
       retry_on_failure:
         enabled: true
       operators:
         - type: json_parser
           if: body matches "^\\{"
           timestamp:
             parse_from: attributes.t.$$date
             layout_type: gotime
             layout: "2006-01-02T15:04:05.999-07:00"
           severity:
             parse_from: attributes.s
             mapping:
               fatal: F
               error: E
               warn: W
               info: I
               debug: D1
     hostmetrics:
       collection_interval: 60s
       scrapers:
         cpu:
           metrics:
             system.cpu.logical.count:
               enabled: true
         memory:
           metrics:
             system.memory.utilization:
               enabled: true
             system.memory.limit:
               enabled: true
         load:
         disk:
         filesystem:
           metrics:
             system.filesystem.utilization:
               enabled: true
         network:
         paging:
     mongodb:
       hosts:
         - endpoint: "127.0.0.1:27017/?authSource=admin&directConnection=true"
       username: "MONGODB_USERNAME"
       password: "MONGODB_PASSWORD"
       collection_interval: 60s
       initial_delay: 1s
       timeout: 30s
       tls:
         insecure: true
       metrics:
         mongodb.operation.latency.time:
           enabled: true
         mongodb.page_faults:
           enabled: true
         mongodb.active.reads:
           enabled: true
         mongodb.active.writes:
           enabled: true
         mongodb.health:
           enabled: true
         mongodb.uptime:
           enabled: true
         mongodb.lock.acquire.count:
           enabled: true
         mongodb.lock.acquire.time:
           enabled: true

   processors:
     batch:
       timeout: 5s
       send_batch_size: 10000
       send_batch_max_size: 10000
     resourcedetection/system:
       detectors: ["system", "ec2"]
       system:
         hostname_sources: ["os"]
     transform/add_timestamp:
       flatten_data: true
       log_statements:
         - context: log
           statements:
             - set(observed_time, Now())
             - set(time_unix_nano, observed_time_unix_nano) where time_unix_nano == 0
     transform/add_service:
       flatten_data: true
       log_statements:
         - context: log
           statements:
             - set(resource.attributes["service.name"], "mongodb")
     transform/slow_queries:
       log_statements:
         - context: log
           conditions:
             - IsMatch(body, "Slow query")
           statements:
             - set(attributes["db.namespace"], attributes["attr"]["ns"]) where attributes["attr"]["ns"] != nil
             - set(attributes["db.operation.duration_ms"], attributes["attr"]["durationMillis"]) where attributes["attr"]["durationMillis"] != nil
             - set(attributes["db.plan_summary"], attributes["attr"]["planSummary"]) where attributes["attr"]["planSummary"] != nil
             - set(attributes["db.keys_examined"], attributes["attr"]["keysExamined"]) where attributes["attr"]["keysExamined"] != nil
             - set(attributes["db.docs_examined"], attributes["attr"]["docsExamined"]) where attributes["attr"]["docsExamined"] != nil
             - set(attributes["db.rows_affected"], attributes["attr"]["nreturned"]) where attributes["attr"]["nreturned"] != nil
             - set(attributes["db.query_hash"], attributes["attr"]["queryHash"]) where attributes["attr"]["queryHash"] != nil
             - set(attributes["db.system"], "mongodb")
             - set(attributes["slow_query"], true)
             - set(severity_text, "WARN") where attributes["attr"]["durationMillis"] != nil and attributes["attr"]["durationMillis"] > 100
     transform/hostmetrics:
       metric_statements:
         - context: datapoint
           statements:
             - set(attributes["host.name"], resource.attributes["host.name"])
             - set(attributes["database"], resource.attributes["database"])
             - set(attributes["server.address"], resource.attributes["server.address"])
             - set(attributes["cloud.account.id"], resource.attributes["cloud.account.id"])
             - set(attributes["cloud.availability_zone"], resource.attributes["cloud.availability_zone"])
             - set(attributes["cloud.platform"], resource.attributes["cloud.platform"])
             - set(attributes["cloud.provider"], resource.attributes["cloud.provider"])
             - set(attributes["cloud.region"], resource.attributes["cloud.region"])
             - set(attributes["host.type"], resource.attributes["host.type"])
             - set(attributes["host.image.id"], resource.attributes["host.image.id"])

   exporters:
     otlp/last9:
       endpoint: "{{ .Logs.WriteURL }}"
       headers:
         "Authorization": "{{ .Logs.AuthValue }}"
     debug:
       verbosity: detailed

   service:
     pipelines:
       logs:
         receivers: [filelog]
         processors:
           [
             batch,
             resourcedetection/system,
             transform/add_timestamp,
             transform/add_service,
             transform/slow_queries,
           ]
         exporters: [otlp/last9]
       metrics:
         receivers: [mongodb, hostmetrics]
         processors: [batch, resourcedetection/system, transform/hostmetrics]
         exporters: [otlp/last9]
   ```

2. **Start the Collector**

   ```bash
   otelcol-contrib --config /etc/otelcol-contrib/config.yaml --feature-gates transform.flatten.logs
   ```

## Memory Metrics

The MongoDB receiver collects `mongodb.memory.usage` by default with `resident` and `virtual` breakdowns. Combined with `hostmetrics` system memory, you can calculate MongoDB memory percentage:

| Metric                      | Description                                | Unit       |
| --------------------------- | ------------------------------------------ | ---------- |
| `mongodb.memory.usage`      | MongoDB process memory (resident, virtual) | By         |
| `mongodb.page_faults`       | Page faults indicating memory pressure     | \{faults\} |
| `system.memory.utilization` | System memory utilization ratio            | 1          |
| `system.memory.limit`       | Total system memory                        | By         |

**Calculating memory usage percentage:**

- MongoDB memory % = `mongodb.memory.usage{memory_type="resident"}` / `system.memory.limit` \* 100

## Slow Query Monitoring

MongoDB 4.4+ outputs structured JSON logs. The `filelog` receiver parses these and the `transform/slow_queries` processor extracts slow query fields:

| Attribute                  | Source Field          | Description                                  |
| -------------------------- | --------------------- | -------------------------------------------- |
| `db.namespace`             | `attr.ns`             | Database and collection (e.g., `mydb.users`) |
| `db.operation.duration_ms` | `attr.durationMillis` | Total execution time in milliseconds         |
| `db.plan_summary`          | `attr.planSummary`    | Execution plan (`COLLSCAN`, `IXSCAN`, etc.)  |
| `db.keys_examined`         | `attr.keysExamined`   | Number of index keys scanned                 |
| `db.docs_examined`         | `attr.docsExamined`   | Number of documents scanned                  |
| `db.rows_affected`         | `attr.nreturned`      | Number of documents returned                 |
| `db.query_hash`            | `attr.queryHash`      | Hash identifying the query shape             |
| `db.system`                | —                     | Always set to `mongodb`                      |
| `slow_query`               | —                     | Always set to `true` for slow query logs     |

Slow queries (> 100ms) are automatically elevated to `WARN` severity. The threshold is controlled by `slowOpThresholdMs` in `mongod.conf`.

## Verification

1. **Check Collector Status**

   ```bash
   sudo systemctl status otelcol-contrib
   ```

2. **View Collector Logs**

   ```bash
   sudo journalctl -u otelcol-contrib -f
   ```

3. **Verify Metrics in Last9**

   Log into your Last9 account and check that MongoDB metrics are being received. Look for the `mongodb` service name.

## Best Practices

- **Security**: Use strong passwords for the monitoring user. The configuration above uses least-privilege roles — avoid granting `root` access.
- **Performance**: Adjust `slowOpThresholdMs` based on your application's performance requirements.
- **Storage**: Monitor log file sizes and implement log rotation to prevent disk space issues.
- **Monitoring**: Set up alerts for critical MongoDB metrics like connection count and replication lag.

## Need Help?

If you encounter any issues or have questions:

- Join our [Discord community](https://discord.com/channels/652153247672729619/652153247672729621) for real-time support
- Contact our support team at [support@last9.io](mailto:support@last9.io)
