NATS
Monitor NATS server metrics with OpenTelemetry and Last9 using the prometheus-nats-exporter
Monitor NATS from two angles: server infrastructure metrics scraped via prometheus-nats-exporter, and distributed traces across your Java publish/subscribe operations via a zero-code OTel agent extension.
Prerequisites
Before setting up NATS monitoring, ensure you have:
- NATS server 2.x running with HTTP monitoring enabled (
http_port: 8222) - Administrative access to the server running the collector
- OpenTelemetry Collector installation access
- Last9 account with integration credentials
-
Enable NATS HTTP Monitoring
NATS exposes monitoring data over HTTP on port 8222. Add the following to your NATS server configuration:
# nats-server.confport: 4222http_port: 8222Restart the server and verify the endpoint is reachable:
curl http://localhost:8222/varz -
Install prometheus-nats-exporter
The prometheus-nats-exporter reads NATS monitoring endpoints and exposes them as Prometheus metrics. Install it on the same host as your NATS server or any host with network access to port 8222.
wget https://github.com/nats-io/prometheus-nats-exporter/releases/latest/download/prometheus-nats-exporter-linux-amd64.zipunzip prometheus-nats-exporter-linux-amd64.zipsudo mv prometheus-nats-exporter /usr/local/bin/docker run -d --name nats-exporter \-p 7777:7777 \natsio/prometheus-nats-exporter:latest \-varz -connz -routez -subz -jsz=all \http://localhost:8222Start the exporter and verify it exposes metrics:
# Start with common monitoring endpointsprometheus-nats-exporter -varz -connz -routez -subz -jsz=all http://localhost:8222# Verify metrics are availablecurl http://localhost:7777/metrics | grep gnatsd_varz_in_msgsFlags used above:
-varz— general server stats (messages, bytes, connections, CPU, memory)-connz— per-connection stats (connection-level throughput and subscriptions)-routez— cluster route stats (route throughput, pending bytes; relevant for clustered NATS)-subz— subscription routing stats-jsz=all— JetStream stats (if JetStream is enabled)
-
Install OpenTelemetry Collector
wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.118.0/otelcol-contrib_0.118.0_linux_amd64.debsudo dpkg -i otelcol-contrib_0.118.0_linux_amd64.debwget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.118.0/otelcol-contrib_0.118.0_linux_amd64.rpmsudo rpm -ivh otelcol-contrib_0.118.0_linux_amd64.rpmMore options: OpenTelemetry Collector installation docs.
-
Configure OpenTelemetry Collector
Create the collector configuration file:
sudo nano /etc/otelcol-contrib/config.yamlAdd the following configuration. It scrapes NATS metrics from prometheus-nats-exporter and also accepts any OTLP data (traces, metrics, logs) from application services sending to port 4318:
receivers:# Scrapes NATS server metrics via prometheus-nats-exporterprometheus:config:scrape_configs:- job_name: natsscrape_interval: 15sstatic_configs:- targets: ["localhost:7777"]labels:service: nats-server# Accepts OTLP from application services (e.g., Java app on port 4318)otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318hostmetrics:collection_interval: 60sscrapers:cpu:memory:disk:network:processors:batch:timeout: 20ssend_batch_size: 10000send_batch_max_size: 10000resourcedetection/system:detectors: ["system"]system:hostname_sources: ["os"]resourcedetection/cloud:detectors: ["aws", "gcp", "azure"]exporters:otlp/last9:endpoint: "{{ .Logs.WriteURL }}"headers:"Authorization": "{{ .Logs.AuthValue }}"debug:verbosity: detailedservice:pipelines:metrics:receivers: [prometheus, otlp, hostmetrics]processors: [batch, resourcedetection/system, resourcedetection/cloud]exporters: [otlp/last9]traces:receivers: [otlp]processors: [batch, resourcedetection/system]exporters: [otlp/last9]logs:receivers: [otlp]processors: [batch, resourcedetection/system]exporters: [otlp/last9]Replace the
exportersplaceholder values with your actual Last9 credentials from the Last9 Integrations page. -
Start and Enable the Service
sudo systemctl daemon-reloadsudo systemctl enable otelcol-contribsudo systemctl start otelcol-contrib
Understanding the Setup
NATS HTTP Monitoring
NATS exposes a built-in HTTP monitoring server (default port 8222) with JSON endpoints for server stats, connections, subscriptions, and JetStream. This is the data source for all NATS metrics.
prometheus-nats-exporter
The exporter translates NATS JSON monitoring endpoints into Prometheus-format metrics. The OTel Collector’s prometheus receiver then scrapes those metrics and converts them to OTLP before forwarding to Last9.
OTLP Receiver for Application Metrics
The otlp receiver allows application services — such as Java services using io.nats — to send their own OTel data (traces, metrics, logs) through the same collector to Last9. Configure the Java app with:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318OTEL_EXPORTER_OTLP_PROTOCOL=http/protobufApplication Tracing
The opentelemetry-nats-java extension instruments the NATS Java client (io.nats:jnats) via the OTel Java agent. No changes to your application code — just add the extension JAR at startup:
java \ -javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.javaagent.extensions=/path/to/opentelemetry-nats-java-0.1.0.jar \ -Dotel.service.name=my-service \ -jar your-app.jarEach publish/subscribe pair becomes a linked distributed trace in Last9:
| Span | Kind | Trigger |
|---|---|---|
{subject} publish | PRODUCER | connection.publish() |
{subject} process | CONSUMER | Message handler invocation |
Spans are linked via W3C traceparent header injected into the outgoing NATS message and extracted on receive. The full attribute set includes messaging.destination.name, messaging.operation.type, messaging.message.body.size, server.address, and messaging.client.id.
Key Metrics to Monitor
Server Throughput
| Metric | Description |
|---|---|
gnatsd_varz_in_msgs | Total messages received by the server |
gnatsd_varz_out_msgs | Total messages sent by the server |
gnatsd_varz_in_bytes | Total bytes received |
gnatsd_varz_out_bytes | Total bytes sent |
Connections and Subscriptions
| Metric | Description |
|---|---|
gnatsd_connz_num_connections | Current active client connections |
gnatsd_varz_total_connections | Total connections since server start |
gnatsd_varz_slow_consumers | Slow consumer count (consumers falling behind) |
gnatsd_varz_subscriptions | Active subscription count |
Cluster Routes
Available when -routez flag is passed and NATS is running in cluster mode.
| Metric | Description |
|---|---|
gnatsd_routez_num_routes | Number of active routes in the cluster |
gnatsd_routez_in_msgs | Messages received on cluster routes |
gnatsd_routez_out_msgs | Messages sent on cluster routes |
gnatsd_routez_in_bytes | Bytes received on cluster routes |
gnatsd_routez_out_bytes | Bytes sent on cluster routes |
gnatsd_routez_pending_bytes | Bytes pending on cluster routes |
Server Health
| Metric | Description |
|---|---|
gnatsd_varz_mem | Server memory usage (bytes) |
gnatsd_varz_cpu | Server CPU usage (fraction) |
gnatsd_varz_uptime_seconds | Time since server start |
gnatsd_varz_max_connections | Configured max connections |
gnatsd_varz_remotes | Currently connected remote servers |
gnatsd_varz_routes | Current route count (cluster) |
JetStream (if enabled)
| Metric | Description |
|---|---|
gnatsd_varz_jetstream_enabled | Whether JetStream is enabled |
gnatsd_varz_jetstream_memory | JetStream memory store usage |
gnatsd_varz_jetstream_storage | JetStream file store usage |
gnatsd_varz_jetstream_streams | Number of active streams |
gnatsd_varz_jetstream_consumers | Number of active consumers |
Configuration Tips
prometheus-nats-exporter as systemd Service
sudo nano /etc/systemd/system/prometheus-nats-exporter.service[Unit]Description=Prometheus NATS ExporterAfter=network.target
[Service]ExecStart=/usr/local/bin/prometheus-nats-exporter -varz -connz -routez -subz -jsz=all http://localhost:8222Restart=always
[Install]WantedBy=multi-user.targetMonitoring Multiple NATS Servers
To monitor multiple NATS nodes, add each as a separate scrape target:
prometheus: config: scrape_configs: - job_name: nats scrape_interval: 15s static_configs: - targets: - "nats-node-1:7777" - "nats-node-2:7777" - "nats-node-3:7777"Run a separate prometheus-nats-exporter instance per NATS node, each on a unique port.
Verification and Monitoring
-
Check Collector Service Status
sudo systemctl status otelcol-contrib -
Monitor Collector Logs
sudo journalctl -u otelcol-contrib -f -
Verify prometheus-nats-exporter
curl http://localhost:7777/metrics | grep gnatsd -
Verify NATS Monitoring Endpoint
# Server variablescurl http://localhost:8222/varz | jq '.connections, .in_msgs, .out_msgs'# Active connectionscurl http://localhost:8222/connz | jq '.num_connections' -
Verify Data in Last9
Log into your Last9 account and check that NATS metrics are appearing in Grafana. Search for
gnatsd_varz_in_msgsto confirm data is flowing.
Troubleshooting
Exporter Cannot Reach NATS Monitoring Port
# Test connectivitycurl http://localhost:8222/healthz
# Verify NATS is listening on 8222ss -tlnp | grep 8222
# Check NATS config has http_port setgrep http_port /path/to/nats-server.confNo Metrics in Collector
# Validate configsudo /usr/bin/otelcol-contrib --config /etc/otelcol-contrib/config.yaml --dry-run
# Check collector can reach exportercurl http://localhost:7777/metrics
# View collector logs for scrape errorssudo journalctl -u otelcol-contrib --no-pager | grep -i natsSlow Consumers Growing
High gnatsd_varz_slow_consumers values indicate subscribers that can’t keep up with message rate. Check subscriber application performance and consider increasing NATS pending limits or scaling subscribers horizontally.
Need Help?
If you encounter any issues or have questions:
- Join our Discord community for real-time support
- Contact our support team at support@last9.io