---
title: "Document Engine metrics reference | Nutrient"
canonical_url: "https://www.nutrient.io/guides/document-engine/monitoring/metrics-reference/"
md_url: "https://www.nutrient.io/guides/document-engine/monitoring/metrics-reference.md"
last_updated: "2026-06-11T00:00:00.000Z"
description: "Document Engine Metrics | Nutrient API documentation for Nutrient Document Engine SDK with methods, properties, and code examples."
---

# Metrics reference

This page lists the internal metrics Document Engine exports.

Document Engine uses the [DogStatsD protocol](https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics) format, which is a variant of StatsD. It sends metric updates to a compatible monitoring agent when an event happens, such as sending an HTTP response, or when it collects a periodic measurement, such as memory usage.

The agent aggregates metrics in fixed time windows and forwards them to your monitoring system for storage and analysis. Aggregation depends on the metric type and the agent implementation. For example, [Telegraf](https://www.influxdata.com/time-series-platform/telegraf/) and the [CloudWatch agent](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html) can aggregate metrics differently.

Refer to the [integration](https://www.nutrient.io/guides/document-engine/monitoring/enable-metrics-export.md) guide to learn how to export Document Engine metrics in different environments and deployment setups.

## Metric types

Document Engine exports three metric types:

- **Counters** — Each update increases a counter by the reported value.
  - Example: A file system cache hit increments a counter every time Document Engine finds an item in the cache.

- **Gauges** — Each update reports the latest value of a measurement.
  - Example: Memory usage.

- **Timings** — Each update reports how long an event took.
  - Example: HTTP request duration.
  - Agents usually aggregate timings into count, minimum, maximum, mean, percentiles, and similar values.

## Tags

Each metric update includes tags in addition to the metric name and value. Use these tags to group and filter measurements.

These tags are attached to every metric exported by Document Engine:

| Tag    | Description                                          |
| ------ | ---------------------------------------------------- |
| host   | Hostname of the Document Engine container            |
| node   | Unique ID of the Document Engine node in the cluster |
| family | Always set to `pspdfkit-document-engine`             |

## Metrics reference

The sections below describe the metrics Document Engine exports, grouped by category.

### HTTP performance

| Name                | Type   | Unit        |
| ------------------- | ------ | ----------- |
| http_server.req_end | timing | millisecond |

This metric reports how long Document Engine takes to process an HTTP request and send the response.

| Tag    | Description                                                                    |
| ------ | ------------------------------------------------------------------------------ |
| status | HTTP response status                                                           |
| method | HTTP request method                                                            |
| group  | `standard` for regular HTTP requests, or `long_poll` for long-polling requests |

When you analyze HTTP performance, separate metrics by the `group` tag and focus on `group=standard`. Long-polling requests stay open by design, so their durations don’t reflect performance.

### PostgreSQL performance

| Name                  | Type   | Unit        |
| --------------------- | ------ | ----------- |
| pg_client.query       | timing | millisecond |
| pg_client.queue       | timing | millisecond |
| pg_client.decode      | timing | millisecond |
| pg_client.result_size | gauge  | -           |

These metrics describe SQL query performance between Document Engine and PostgreSQL:

- `pg_client.query` — Time spent executing the query

- `pg_client.queue` — Time spent waiting for a database connection from the pool

- `pg_client.decode` — Time spent decoding the query result

- `pg_client.result_size` — Number of rows returned per query

To estimate total database query time, add `pg_client.query`, `pg_client.queue`, and `pg_client.decode`.

| Tag        | Description                                                                                    |
| ---------- | ---------------------------------------------------------------------------------------------- |
| result     | `success` or `error`, depending on whether the query succeeded                                 |
| command    | SQL command that ran: `select`, `update`, `delete`, `insert`, `begin`, `commit`, or `rollback` |
| error_code | PostgreSQL error code. Present only when `result` is `error`                                   |
| severity   | Error severity. Present only when `result` is `error`                                          |

### Asset storage

| Name               | Type   | Unit        |
| ------------------ | ------ | ----------- |
| assets.fetch_asset | timing | millisecond |
| assets.store_asset | timing | millisecond |

These metrics track how long it takes to fetch or store an asset in [asset storage](https://www.nutrient.io/guides/document-engine/configuration/asset-storage.md). Document Engine fetches an asset from storage only if it isn’t already in the [file system cache](#file-system-cache).

| Tag    | Description                                                        |
| ------ | ------------------------------------------------------------------ |
| result | `success` or `error`, depending on whether the operation succeeded |

### File system cache

| Name          | Type    | Unit        |
| ------------- | ------- | ----------- |
| cache.fs_hit  | counter | -           |
| cache.fs_miss | counter | -           |
| cache.fs_size | gauge   | byte        |
| cache.fs_free | timing  | millisecond |

These metrics describe the file system cache for document source files:

- `cache.fs_hit` and `cache.fs_miss` count cache hits and misses.

- `cache.fs_size` reports the current cache size.

- `cache.fs_free` reports how long it takes to clear a full cache.

The cache size is limited by the `ASSET_STORAGE_CACHE_SIZE` configuration option.

### In-memory cache

| Name              | Type    | Unit |
| ----------------- | ------- | ---- |
| cache.memory_hit  | counter | -    |
| cache.memory_miss | counter | -    |

These metrics describe the in-memory cache for PDF metadata:

- `cache.memory_hit` counts cache hits.

- `cache.memory_miss` counts cache misses.

### Redis cache

| Name              | Type   | Unit        |
| ----------------- | ------ | ----------- |
| cache.redis_hit   | timing | millisecond |
| cache.redis_miss  | timing | millisecond |
| cache.redis_set   | timing | millisecond |
| cache.redis_error | timing | millisecond |

These metrics describe the optional Redis cache used to share rendered-page cache entries across multiple Document Engine instances.

- `cache.redis_hit` reports how long it takes to fetch an item from Redis on a cache hit.

- `cache.redis_miss` reports how long the Redis request takes on a cache miss.

- `cache.redis_set` reports how long it takes to store an item in Redis.

- `cache.redis_error` reports how long a failed Redis operation takes.

| Tag | Description                                                   |
| --- | ------------------------------------------------------------- |
| op  | Redis operation that ran. Present only on `cache.redis_error` |

### Remote documents

| Name                      | Type   | Unit        |
| ------------------------- | ------ | ----------- |
| remote_doc.response_start | timing | millisecond |
| remote_doc.response_end   | timing | millisecond |

These metrics describe how long Document Engine takes to fetch documents from remote URLs:

- `remote_doc.response_start` — Time between sending the request and receiving the first byte

- `remote_doc.response_end` — Time spent transferring data after the remote server starts responding

To estimate total remote document fetch time, add both metrics.

| Tag    | Description                                                     |
| ------ | --------------------------------------------------------------- |
| result | `success`, `error`, or `timeout`, depending on the fetch result |

### Document conversion

| Name                        | Type   | Unit        |
| --------------------------- | ------ | ----------- |
| document_conversion.convert | timing | millisecond |

This metric reports how long Office document conversion takes.

| Tag    | Description                                              |
| ------ | -------------------------------------------------------- |
| result | `success` or `error`, depending on the conversion result |

### Async jobs

| Name                                 | Type    | Unit        |
| ------------------------------------ | ------- | ----------- |
| async_jobs.queued                    | counter | -           |
| async_jobs.status_transitions        | counter | -           |
| async_jobs.running                   | counter | -           |
| async_jobs.processed                 | counter | -           |
| async_jobs.failed                    | counter | -           |
| async_jobs.retries                   | counter | -           |
| async_jobs.missing_workers           | counter | -           |
| async_jobs.access_token_verification | counter | -           |
| async_jobs.queue_time                | timing  | millisecond |
| async_jobs.execution                 | timing  | millisecond |
| async_jobs.queue_state               | gauge   | job         |

These metrics describe async job admission, processing, failures, and current queue state:

- `async_jobs.queued` counts async jobs after they’re committed.

- `async_jobs.status_transitions` counts public async job status changes.

- `async_jobs.running` counts async Oban jobs when worker execution starts.

- `async_jobs.processed` counts async Oban jobs that finish processing.

- `async_jobs.failed` counts async Oban jobs that fail.

- `async_jobs.retries` counts failed async Oban jobs that will be retried.

- `async_jobs.missing_workers` counts async Oban jobs that fail because their worker module is missing.

- `async_jobs.access_token_verification` counts async job access token verification attempts by result.

- `async_jobs.queue_time` reports how long async Oban jobs wait before execution starts.

- `async_jobs.execution` reports async Oban worker execution duration.

- `async_jobs.queue_state` reports the current number of async Oban jobs grouped by queue, worker, and Oban state.

The queue-state gauge includes only current work states, such as `available`, `scheduled`, `executing`, and `retryable`. In clustered deployments, only the Oban leader reports non-zero queue-state values to avoid multiplying the same database-backed counts by the number of nodes.

Async job IDs and Oban job IDs aren’t metric tags. Use structured logs when you need to correlate metrics with a specific job.

| Metric                                 | Tags                                         |
| -------------------------------------- | -------------------------------------------- |
| `async_jobs.queued`                    | `type`, `queue`                              |
| `async_jobs.status_transitions`        | `type`, `previous_status`, `status`, `queue` |
| `async_jobs.running`                   | `queue`, `worker`, `state`                   |
| `async_jobs.processed`                 | `queue`, `worker`, `state`                   |
| `async_jobs.queue_time`                | `queue`, `worker`, `state`                   |
| `async_jobs.execution`                 | `queue`, `worker`, `state`                   |
| `async_jobs.failed`                    | `queue`, `worker`, `state`, `kind`           |
| `async_jobs.retries`                   | `queue`, `worker`, `state`, `kind`           |
| `async_jobs.missing_workers`           | `queue`, `worker`                            |
| `async_jobs.access_token_verification` | `type`, `queue`, `result`                    |
| `async_jobs.queue_state`               | `queue`, `state`, `worker`                   |

| Tag             | Description                                                                                                           |
| --------------- | --------------------------------------------------------------------------------------------------------------------- |
| type            | Async job type, such as a Build API async job                                                                         |
| queue           | Oban queue that holds or processed the job                                                                            |
| worker          | Oban worker module                                                                                                    |
| state           | Oban result state for lifecycle metrics, `unknown` for running jobs, or current Oban job state for queue-state gauges |
| status          | Public async job status after a status transition                                                                     |
| previous_status | Public async job status before a status transition                                                                    |
| kind            | Exception kind for failed jobs                                                                                        |
| result          | Access token verification result: `ok`, `missing_token`, `invalid_token`, or `expired_token`                          |

### PDF processing

| Name            | Type   | Unit        |
| --------------- | ------ | ----------- |
| pspdfkitd.queue | timing | millisecond |
| pspdfkitd.exec  | timing | millisecond |

These metrics cover Document Engine operations that work with PDFs, including rendering, content extraction, and preparing PDFs for download.

- `pspdfkitd.queue` reports how long an operation waits for an available worker.

- `pspdfkitd.exec` reports how long the operation takes once it starts.

| Tag     | Description            |
| ------- | ---------------------- |
| request | PDF operation that ran |

### Signing service

| Name                 | Type   | Unit        |
| -------------------- | ------ | ----------- |
| signing_service.sign | timing | millisecond |

This metric reports how long the [signing service](https://www.nutrient.io/guides/web/signatures/digital-signatures/signature-lifecycle/sign-a-pdf-document.md) takes to respond to a signing request.

| Tag    | Description                                                              |
| ------ | ------------------------------------------------------------------------ |
| result | `success` or `error`, depending on whether the signing request succeeded |

### Instant

| Metric Name      | Metric Type | Unit         | Description                                                      |
| ---------------- | ----------- | ------------ | ---------------------------------------------------------------- |
| layer.sync.hooks | timing      | milliseconds | Duration spent across the hooks registered for `sync` operations |
| layer.sync.total | timing      | milliseconds | Total duration of the sync operation                             |

These metrics track [Instant sync](https://www.nutrient.io/guides/web/instant-synchronization.md). For failed operations, Document Engine emits only `layer.sync.total`.

| Tag    | Description                                                                            |
| ------ | -------------------------------------------------------------------------------------- |
| result | Present only on `layer.sync.total`. `success` or `error`, depending on the sync result |

### Memory total

| Name            | Type  | Unit |
| --------------- | ----- | ---- |
| vm_memory.total | gauge | byte |

This metric reports the total memory allocated by the Document Engine process. The total memory used by the container is usually higher, because other processes also run inside the container.

### Compute resources utilization

| Name                          | Type   | Unit        |
| ----------------------------- | ------ | ----------- |
| vm_scheduler_wall_time.active | timing | millisecond |
| vm_scheduler_wall_time.total  | timing | millisecond |

These metrics describe Erlang VM scheduler usage:

- `vm_scheduler_wall_time.active` — Time the Erlang VM spent actively doing work during the last interval

- `vm_scheduler_wall_time.total` — Total Erlang VM uptime during the same interval

If you divide active time by total time, the result shows how much of the assigned compute capacity Document Engine used.

These metrics describe only the Document Engine process. Container-level CPU utilization can differ because other processes may also be running.

| Tag              | Description                               |
| ---------------- | ----------------------------------------- |
| scheduler_number | Internal Document Engine scheduler number |

Document Engine starts as many schedulers as there are logical CPU cores available. In most cases, average these metrics across schedulers.

### Clustering

When [clustering](https://www.nutrient.io/guides/document-engine/deployment/horizontal-scaling.md#clustering) is enabled and Prometheus export is configured, Document Engine emits cluster health and routing metrics.

| Name                                     | Type    | Unit |
| ---------------------------------------- | ------- | ---- |
| cluster_ring_size                        | gauge   | -    |
| cluster_peer_changes_total               | counter | -    |
| cluster_redirect_total                   | counter | -    |
| cluster_redirect_retries_total           | counter | -    |
| cluster_task_supervisor_overloaded_total | counter | -    |

These metrics help you monitor cluster membership and document-routing behavior:

- `cluster_ring_size` — Current number of routable nodes in the cluster.

- `cluster_peer_changes_total` — Count of cluster membership changes.

- `cluster_redirect_total` — Count of routing redirects by outcome.

- `cluster_redirect_retries_total` — Count of retries caused by stale routing information.

- `cluster_task_supervisor_overloaded_total` — Count of times the clustering task supervisor reached its child-process limit.

| Tag         | Description                                                                   |
| ----------- | ----------------------------------------------------------------------------- |
| erlang_node | Full Erlang node name — for example, `pssync@10.2.130.162`                    |
| event       | Present on `cluster_peer_changes_total`; values include `added` and `removed` |
| outcome     | Present on `cluster_redirect_total`; identifies the redirect outcome          |

Use `cluster_ring_size` as the first health signal. For example, alert when it stays below the expected replica count for several minutes. If routing looks wrong, inspect `cluster_redirect_total` and `cluster_redirect_retries_total` first.

## HTTP/2 shared rendering telemetry

When you enable [HTTP/2 shared rendering](https://www.nutrient.io/guides/document-engine/configuration/http2-shared-rendering.md), Document Engine emits additional telemetry events for the shared rendering path. These events use the same monitoring pipeline as the metrics above.

| Event                                | Meaning                                                               |
| ------------------------------------ | --------------------------------------------------------------------- |
| `http2.stream.worker_checkout`       | Document Engine checked out a rendering worker for a shared session   |
| `http2.stream.render_tile`           | Document Engine rendered a tile through the shared rendering path     |
| `http2.stream.render_process.new`    | Document Engine started a new connection-scoped rendering process     |
| `http2.stream.render_process.exists` | A tile request reused an existing rendering process on the connection |

When clustering is also enabled, the rendering process runs on the owner node for the document. Refer to the [HTTP/2 shared rendering](https://www.nutrient.io/guides/document-engine/configuration/http2-shared-rendering.md) guide for details.
---

## Related pages

- [Expose Document Engine metrics](/guides/document-engine/monitoring/enable-metrics-export.md)
- [Document Engine logs](/guides/document-engine/monitoring/logs.md)
- [Extra environment variables](/guides/document-engine/monitoring/opentelemetry.md)

