Skip to content

CLI

The main CLI command is nats-sink. It is intended for operators and developers who want to run a sink process from a terminal, container, or service manager without writing Python code. The CLI reads the same JSON configuration model that the Python API uses.

The project also ships a companion metrics command named nats-sink-metrics. That command does not run a sink. It reads a local JSON metrics snapshot and prints status in formats that are easy for humans, shell scripts, and simple monitoring jobs to consume.

The project also ships an observability policy command named nats-sink-observe. That command manages what may be shared with external observability platforms. It can generate a disabled Prometheus policy from the core config, list metric names and subject hints, validate policy, and render policy-filtered Prometheus textfile output or run the optional native Prometheus HTTP endpoint. It can also export approved metrics to an OpenTelemetry Collector through OTLP/HTTP JSON, including the Elastic Observability and Grafana Alloy profiles, approved aggregate metric events through Splunk HEC, approved custom metrics to OCI Monitoring, Amazon CloudWatch, and Azure Monitor, approved best-effort datagrams to StatsD-compatible aggregators or a Datadog Agent, and RFC 5424-style messages to syslog pipelines.

For readers new to this project, the CLI does not implement a separate delivery engine. It validates configuration, creates the selected sink, builds JetStreamSinkRunner, and then the core runner performs commit-then-ACK processing.

For operational teams, this means the same command can be used during local tests, lab validation, and controlled service deployments. The behavior should be reviewed through configuration and logs rather than through ad hoc scripts that might accidentally weaken ACK ordering or secret handling.

nats-sink run config.json
nats-sink validate config.json
nats-sink show-effective-config config.json
nats-sink export-catalogue-manifest config.json --dataset-name orders-events
nats-sink test-sink config.json
nats-sink inspect-ordered config.json --max-messages 5 --format jsonl
nats-sink stream-plan config.json
nats-sink query-lineage config.json --field mission_id --value MISSION-ALPHA --dry-run
nats-sink replay-spool spool-config.json target-config.json --dry-run
nats-sink-metrics show .local/nats-sinks/metrics.json
nats-sink-observe init-prometheus-policy config.json observability.prometheus.json
nats-sink-observe prometheus-http .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe otlp-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe elastic-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe grafana-alloy-config observability.prometheus.json
nats-sink-observe grafana-alloy-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe splunk-hec-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe oci-monitoring-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe statsd-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe datadog-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe cloudwatch-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe azure-monitor-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe syslog-export .local/nats-sinks/metrics.json observability.prometheus.json --dry-run
nats-sink-observe nats-monitoring-poll observability.prometheus.json --dry-run

Commands

nats-sink validate

Validates JSON syntax, Pydantic configuration models, and sink-specific configuration. This is the safest first command to run because it does not need to connect to NATS or the configured destination.

nats-sink validate examples/file-basic/config.json

When the configuration contains a top-level sinks registry, validate also checks every named sink and reports which route names reference which target names. The report is intentionally safe to paste into tickets or release evidence because it includes target names and sink types, not passwords, connection credentials, or payloads.

nats-sink validate examples/named-multi-sink/config.json

Example output:

Configuration is valid.
Active sink: file
ACK policy: commit-then-acknowledge
Named sinks: file_audit (file), oracle_secret (oracle), oracle_unclass (oracle)
Route target references:
  - nato_secret_sensor_audit: oracle_secret (required), file_audit (optional, minimum_wait_ms=250, timeout_ms=1000)
  - nato_unclass_sensor_audit: oracle_unclass (required)

nats-sink export-catalogue-manifest

Exports a redacted data-product or catalogue manifest from a validated configuration. The command does not connect to NATS or any sink destination and does not export payloads.

nats-sink export-catalogue-manifest config.json \
  --dataset-name orders-events \
  --output .local/catalogue/orders-events.json

Existing output files are not replaced unless --overwrite is set. See Catalogue Manifest Export for the manifest shape and governance boundary.

nats-sink show-effective-config

Displays the validated configuration as redacted JSON. Use this when you want to confirm defaults and environment-backed field names without printing resolved secrets.

This is especially useful in reviewed environments because it lets operators confirm NATS subjects, sink type, message metadata defaults, encryption policy, and DLQ settings without exposing passwords, tokens, Oracle wallet passwords, or encryption keys.

nats-sink show-effective-config examples/file-basic/config.json

nats-sink test-sink

Starts the configured sink and runs a health check when the sink supports it. This command opens destination connections, so use it only in environments where that is expected.

nats-sink test-sink examples/file-basic/config.json

Named sink health checks use the same sink-specific validation and startup path as the active sink:

nats-sink test-sink examples/named-multi-sink/config.json --sink-name file_audit
nats-sink test-sink examples/named-multi-sink/config.json --all-named-sinks

--sink-name is useful when the configuration contains Oracle targets and file targets but an operator only wants to check the local file audit path. Use --all-named-sinks only when opening every configured destination is expected.

nats-sink inspect-ordered

Inspects JetStream messages through a NATS ordered consumer when the installed NATS Python client exposes ordered-consumer support. This is an inspection tool, not a sink worker: it does not build a sink, does not write to Oracle Database, Oracle MySQL, file, spool, fan-out, or plugin destinations, and does not ACK production durable work.

Use it for bounded local troubleshooting when an operator needs to inspect a small in-order view of a subject without advancing the configured durable sink consumer:

nats-sink inspect-ordered examples/file-basic/config.json --max-messages 5

Example text output:

Ordered inspection result
inspection_only=true
messages_seen=1
payload_bytes_seen=24
stopped_reason=timeout
record stream_sequence=7 consumer_sequence=1 subject='orders.created' priority=null classification=null labels='' payload_bytes=24 payload_redacted=true

Payloads are redacted by default. For local troubleshooting files, write sanitized JSONL under an approved output root:

nats-sink inspect-ordered examples/file-basic/config.json \
  --max-messages 5 \
  --max-payload-bytes 1048576 \
  --max-headers 32 \
  --max-header-value-bytes 256 \
  --output-root .local/nats-sinks/inspection \
  --output orders.jsonl

Example JSONL record:

{"inspection_only":true,"subject":"orders.created","stream":"ORDERS","consumer":"_ordered","stream_sequence":7,"consumer_sequence":1,"timestamp":null,"received_at":"2026-05-26T10:00:00Z","priority":null,"classification":null,"labels":[],"headers":{"Authorization":"<redacted>","X-Trace":"visible"},"payload":{"redacted":true,"bytes":24,"sha256":"..."}}

Use --format jsonl when shell tooling should consume the records from standard output. Use --include-payload only in controlled local environments where the payload is approved for display; binary payloads are encoded as Base64, and text payloads are emitted as UTF-8. The command enforces hard limits for message count, payload bytes, pending messages, pending bytes, timeouts, header count, header value length, and JSONL output paths before or during inspection. If ordered-consumer support is not available in the active client, the command exits with a configuration error rather than falling back to durable pull or ordinary push delivery. The compatibility check uses the public JetStreamContext.subscribe API and reports only a short sanitized reason, such as a missing ordered_consumer option or an unreadable client signature.

See Ordered Consumer Evaluation for the design decision and replay boundaries.

nats-sink stream-plan

Generates an offline JetStream stream-management plan from the runtime JSON configuration. This command is deliberately separate from nats-sink run: it does not connect to NATS, does not create streams, does not update consumers, does not resolve credentials, and does not need NATS administrator permissions.

Use it when an operator wants to review stream retention, discard policy, storage type, replica count, duplicate-window settings, and runtime versus administration permission boundaries before applying changes with the NATS CLI, Terraform, Ansible, or another approved platform process.

nats-sink stream-plan examples/file-basic/config.json \
  --retention limits \
  --discard old \
  --storage file \
  --replicas 3 \
  --duplicate-window-seconds 600

Use JSON output for scripts and review artifacts:

nats-sink stream-plan examples/file-basic/config.json --format json

Example JSON excerpt:

{
  "stream": "ORDERS",
  "subjects": ["orders.*"],
  "durable_consumer": "file-orders-sink",
  "recommended_stream_settings": {
    "retention": "limits",
    "discard": "old",
    "storage": "file",
    "replicas": 3,
    "duplicate_window_seconds": 600
  },
  "runtime_permissions": [
    "$JS.API.CONSUMER.MSG.NEXT.ORDERS.file-orders-sink",
    "$JS.API.CONSUMER.INFO.ORDERS.file-orders-sink",
    "$JS.ACK.ORDERS.file-orders-sink.>",
    "_INBOX.>"
  ]
}

See JetStream Stream Management Planning for the full operator guide and permission discussion.

nats-sink query-lineage

Queries already persisted Oracle rows by a small set of allow-listed lineage fields. This command is read-only: it does not connect to NATS, does not ACK messages, does not write to Oracle, and does not alter sink state.

Start with dry-run mode to validate the configured table, field, limit, and SQL shape without opening an Oracle connection:

nats-sink query-lineage examples/oracle-jetstream/config.json \
  --field mission_id \
  --value MISSION-ALPHA \
  --limit 10 \
  --format json \
  --dry-run

The dry-run output prints bind names but not the lookup value:

{
  "field": "mission_id",
  "table": "NATS_SINK_EVENTS",
  "limit": 10,
  "payload_included": false,
  "binds": ["lineage_value"],
  "sql": "select ... where json_value(MISSION_METADATA_JSON, '$.mission_id') = :lineage_value ... fetch first 10 rows only"
}

Supported fields are correlation_id, causation_id, mission_id, tasking_id, track_id, message_id, and subject. Payload output is omitted by default. See Lineage Query Helpers for the security model, Oracle examples, and output reference.

nats-sink replay-spool

Replays committed records from an encrypted edge spool into a final destination sink. The first argument must be a normal configuration file whose sink.type is spool. The second argument must be a normal configuration file for the target sink, such as file or oracle.

nats-sink replay-spool /etc/nats-sinks/spool.json /etc/nats-sinks/oracle.json --dry-run

Example dry-run output:

Dry run complete; 128 committed spool record(s) eligible.

Replay a bounded number of records:

nats-sink replay-spool /etc/nats-sinks/spool.json /etc/nats-sinks/oracle.json --max-records 100

Example replay output:

Replay complete: scanned=100 replayed=100 deleted=100 failed=0

Replay does not ACK JetStream messages. The original ACK already happened when the spool record was committed by nats-sink run. During replay, files are deleted only after the target sink returns success and the spool config keeps delete_after_replay enabled. See Edge Spool Sink for the full delivery and security model.

nats-sink run

Starts the JetStream runner. This command opens NATS and destination connections and begins processing messages.

nats-sink run examples/file-basic/config.json --log-level INFO

Use --dry-run to validate and construct runtime objects without opening NATS or sink connections.

When metrics.enabled is true and metrics.snapshot_file is set in configuration, run also writes a local metrics snapshot for nats-sink-metrics:

{
  "metrics": {
    "enabled": true,
    "namespace": "nats_sinks",
    "snapshot_file": ".local/nats-sinks/metrics.json",
    "event_freshness_enabled": true,
    "event_stale_after_seconds": 300,
    "event_future_skew_tolerance_seconds": 5
  }
}

nats-sink-metrics show

Shows the status of counters, gauges, and timing observations from a local JSON snapshot. The default output is a table:

nats-sink-metrics show .local/nats-sinks/metrics.json

Example output:

KIND         METRIC                         VALUE  DESCRIPTION
counter      messages_fetched_total           256  Raw JetStream messages fetched by the pull consumer.
counter      messages_written_total           256  Messages reported durable by the destination sink.
counter      messages_acked_total             256  Messages acknowledged to JetStream after durable success or DLQ success.
observation  sink_batch_write_seconds.count     4  Elapsed seconds spent inside sink.write_batch for successful batches.

Script-friendly formats are available:

nats-sink-metrics show .local/nats-sinks/metrics.json --format shell
nats-sink-metrics show .local/nats-sinks/metrics.json --format json
nats-sink-metrics show .local/nats-sinks/metrics.json --format jsonl
nats-sink-metrics show .local/nats-sinks/metrics.json --format prometheus
nats-sink-metrics show .local/nats-sinks/metrics.json --format names

Filter and sort output:

nats-sink-metrics show .local/nats-sinks/metrics.json --kind counter
nats-sink-metrics show .local/nats-sinks/metrics.json --metric "*error*" --metric "*failed*"
nats-sink-metrics show .local/nats-sinks/metrics.json --sort value --reverse

Fail when the snapshot has gone stale:

nats-sink-metrics show .local/nats-sinks/metrics.json --stale-after-seconds 60

nats-sink-metrics get

Prints one value, which is useful in shell scripts:

failed=$(nats-sink-metrics get .local/nats-sinks/metrics.json messages_failed_total --default 0)
if [ "$failed" -gt 0 ]; then
  echo "nats-sinks has failed messages"
  exit 2
fi

get exits with code 4 when a metric is missing and no --default value is provided.

nats-sink-metrics describe

Lists the metrics emitted by the framework:

nats-sink-metrics describe
nats-sink-metrics describe --format names
nats-sink-metrics describe --format json

The full metrics reference, Python hooks, staleness behavior, exit codes, and Prometheus text output examples are documented in Metrics.

nats-sink-observe init-prometheus-policy

Generates a disabled observability policy from a runtime configuration. The generated policy includes metric-sharing defaults, the configured namespace, and subject hints discovered from the config. It does not enable Prometheus sharing.

nats-sink-observe init-prometheus-policy \
  /etc/nats-sinks/config.json \
  /etc/nats-sinks/observability.prometheus.json \
  --output-file /var/lib/node_exporter/textfile_collector/nats_sinks.prom

nats-sink-observe validate-policy

Validates a policy file before a service or operator relies on it:

nats-sink-observe validate-policy /etc/nats-sinks/observability.prometheus.json

Example output:

Observability policy is valid.
schema=nats_sinks.observability.policy.v1
enabled=false
namespace=nats_sinks
prometheus_enabled=false
otlp_enabled=false
elastic_enabled=false
grafana_alloy_enabled=false
splunk_hec_enabled=false
statsd_enabled=false
cloudwatch_enabled=false
syslog_enabled=false
nats_server_monitoring_enabled=false
nats_server_monitoring_prometheus_enabled=false
allowed_metrics=0
allowed_metric_patterns=0
denied_metrics=0
denied_metric_patterns=0
subjects=1

nats-sink-observe list-metrics

Lists metric names that can be used in an observability allow list:

nats-sink-observe list-metrics --format names
nats-sink-observe list-metrics --format json

nats-sink-observe list-subjects

Lists subject hints copied from the runtime configuration:

nats-sink-observe list-subjects \
  /etc/nats-sinks/observability.prometheus.json \
  --format shell

Example output:

NATS_SINKS_SUBJECT_1_ORDERS=orders.*

Current metrics are not subject-labeled. This command helps operators review policy and prepares the extension point for future subject-aware connectors.

nats-sink-observe prometheus-textfile

Renders Prometheus textfile output after applying the observability policy:

nats-sink-observe prometheus-textfile \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --output /var/lib/node_exporter/textfile_collector/nats_sinks.prom

Use --dry-run to print to stdout:

nats-sink-observe prometheus-textfile \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

The command writes only a comment when the policy is disabled. See Observability for the sharing model and its Prometheus Integration sub-page for service deployment guidance.

nats-sink-observe prometheus-http

Runs the optional native Prometheus HTTP endpoint or renders one response for review. The endpoint is disabled unless both the top-level policy and prometheus.http_endpoint.enabled are true:

nats-sink-observe prometheus-http \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

# HELP nats_sinks_messages_fetched_total Raw JetStream messages fetched by the pull consumer.
# TYPE nats_sinks_messages_fetched_total counter
nats_sinks_messages_fetched_total 256

Run the endpoint as a foreground process:

nats-sink-observe prometheus-http \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json

Example startup output:

Serving Prometheus metrics on 127.0.0.1:9108/metrics

Use this command as a separate service, not inside the sink worker, unless an embedding application deliberately accepts that coupling. The endpoint never ACKs messages and never connects to NATS or a destination sink.

nats-sink-observe otlp-export

Exports policy-approved metrics to an OpenTelemetry Collector through OTLP/HTTP JSON. The command is disabled unless both the top-level observability policy and otlp.enabled are true. It reads only the local metrics snapshot and policy file; it does not connect to NATS, Oracle, file sink directories, DLQ subjects, or future destination backends.

Dry-run mode prints the OTLP JSON request body without opening a network connection:

nats-sink-observe otlp-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

{"resourceMetrics":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"nats-sinks"}},{"key":"nats_sinks.namespace","value":{"stringValue":"nats_sinks"}}]},"scopeMetrics":[{"metrics":[{"description":"Raw JetStream messages fetched by the pull consumer.","name":"nats_sinks_messages_fetched_total","sum":{"aggregationTemporality":2,"dataPoints":[{"asDouble":256.0,"timeUnixNano":"1790000000000000000"}],"isMonotonic":true},"unit":"1"}],"scope":{"name":"nats-sinks.observability.otlp"}}]}]}

Live export uses the endpoint, timeout, retry, request-size, and optional header environment-variable settings from the policy:

nats-sink-observe otlp-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json

Example success output:

OTLP export: attempted=true delivered=true attempts=1 status=200 message=OTLP export delivered

Example bounded failure output:

OTLP export: attempted=true delivered=false attempts=3 status=none message=OTLP export failed with URLError

The output is intentionally sanitized. It does not print the collector URL, header values, payload bodies, subjects, table names, file paths, labels, classification values, or other sensitive deployment detail. Full connector guidance is documented in OpenTelemetry OTLP Integration.

nats-sink-observe elastic-export

Exports policy-approved metrics through the Elastic Observability OTLP profile. The command is disabled unless both the top-level observability policy and elastic.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, and redaction posture as the other observability connectors.

Dry-run mode prints the Elastic-profiled OTLP JSON body without opening a network connection:

nats-sink-observe elastic-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

{"resourceMetrics":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"nats-sinks"}},{"key":"nats_sinks.namespace","value":{"stringValue":"nats_sinks"}},{"key":"data_stream.dataset","value":{"stringValue":"nats_sinks.metrics"}},{"key":"data_stream.namespace","value":{"stringValue":"default"}},{"key":"nats_sinks.observability.profile","value":{"stringValue":"elastic"}}]},"scopeMetrics":[{"metrics":[{"description":"Raw JetStream messages fetched by the pull consumer.","name":"nats_sinks_messages_fetched_total","sum":{"aggregationTemporality":2,"dataPoints":[{"asDouble":256.0,"timeUnixNano":"1790000000000000000"}],"isMonotonic":true},"unit":"1"}],"scope":{"name":"nats-sinks.observability.elastic"}}]}]}

Example success output:

Elastic Observability export: attempted=true delivered=true attempts=1 status=200 message=Elastic Observability export delivered

The command is an observability connector profile, not a delivery feature. It does not ACK messages and does not write directly to Elasticsearch. Full connector guidance is documented in Elastic Observability Profile.

nats-sink-observe grafana-alloy-config

Renders a minimal Grafana Alloy River configuration snippet from the observability policy. The snippet configures an Alloy OTLP receiver, batch processor, and OTLP HTTP exporter using environment-variable references for upstream Grafana settings.

nats-sink-observe grafana-alloy-config \
  /etc/nats-sinks/observability.prometheus.json

Example output:

otelcol.receiver.otlp "nats_sinks" {
  http {
    endpoint = "127.0.0.1:4318"
  }

  output {
    metrics = [otelcol.processor.batch.nats_sinks_batch.input]
  }
}

The rendered config is a starter snippet for operator review. It does not start Alloy and does not validate a whole Alloy deployment.

nats-sink-observe grafana-alloy-export

Exports policy-approved metrics to a Grafana Alloy OTLP receiver. The command is disabled unless both the top-level observability policy and grafana_alloy.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, request-size bounds, and redaction posture as the other observability connectors.

Dry-run mode prints the Grafana Alloy-profiled OTLP JSON body without opening a network connection:

nats-sink-observe grafana-alloy-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

{"resourceMetrics":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"nats-sinks"}},{"key":"nats_sinks.namespace","value":{"stringValue":"nats_sinks"}},{"key":"nats_sinks.observability.profile","value":{"stringValue":"grafana_alloy"}},{"key":"telemetry.collector","value":{"stringValue":"grafana_alloy"}}]},"scopeMetrics":[{"metrics":[{"description":"Raw JetStream messages fetched by the pull consumer.","name":"nats_sinks_messages_fetched_total","sum":{"aggregationTemporality":2,"dataPoints":[{"asDouble":256.0,"timeUnixNano":"1790000000000000000"}],"isMonotonic":true},"unit":"1"}],"scope":{"name":"nats-sinks.observability.grafana_alloy"}}]}]}

Example success output:

Grafana Alloy export: attempted=true delivered=true attempts=1 status=200 message=Grafana Alloy export delivered

The command is an observability connector profile, not a delivery feature. It does not ACK messages, manage Alloy, or hold downstream Grafana credentials. Full connector guidance is documented in Grafana Alloy Profile.

nats-sink-observe splunk-hec-export

Exports policy-approved aggregate metrics to Splunk HTTP Event Collector. The command is disabled unless both the top-level observability policy and splunk_hec.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, request-size bounds, and redaction posture as the other observability connectors.

Dry-run mode prints the Splunk HEC JSON event body without opening a network connection or requiring the HEC token to be present:

nats-sink-observe splunk-hec-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

{"event":"metric","fields":{"metric_name:nats_sinks_messages_fetched_total":256,"nats_sinks_namespace":"nats_sinks","nats_sinks_observability_profile":"splunk_hec"},"host":"nats-sinks","source":"nats-sinks","sourcetype":"nats_sinks:metrics","time":1790000000.0}

Example success output:

Splunk HEC export: attempted=true delivered=true attempts=1 status=200 message=Splunk HEC export delivered

The command is an observability connector, not a delivery feature. It does not ACK messages, write payloads to Splunk, or expose the HEC endpoint or token in result summaries. Full connector guidance is documented in Splunk HEC Integration.

nats-sink-observe oci-monitoring-export

Exports policy-approved aggregate metrics to OCI Monitoring as custom metrics. The command is disabled unless both the top-level observability policy and oci_monitoring.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, request-size bounds, and redaction posture as the other observability connectors.

Dry-run mode prints a sanitized OCI PostMetricData request body without importing the OCI SDK or opening a network connection:

nats-sink-observe oci-monitoring-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

[{"batch_atomicity":"ATOMIC","metric_data":[{"compartment_id":"<redacted>","datapoints":[{"count":1,"timestamp":"2026-05-27T12:00:00.000Z","value":256.0}],"dimensions":{"deployment":"edge"},"name":"mission_ops_messages_fetched_total","namespace":"nats_sinks_metrics"}]}]

Example success output:

OCI Monitoring export: attempted=true delivered=true attempts=1 requests=1 metrics=1 message=OCI Monitoring export delivered

The command is an observability connector, not a delivery feature. It does not ACK messages, write payloads to OCI Monitoring, expose compartment OCIDs in dry-run output, or manage OCI IAM policies. Full connector guidance is documented in OCI Monitoring Integration.

nats-sink-observe statsd-export

Exports policy-approved metrics to a StatsD-compatible UDP listener or Unix datagram socket. The command is disabled unless both the top-level observability policy and statsd.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, and redaction posture as the other observability connectors.

Dry-run mode prints StatsD lines without opening a socket:

nats-sink-observe statsd-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

nats_sinks.messages_fetched_total:256|g
nats_sinks.messages_acked_total:256|g

Example success output:

StatsD export: attempted=true delivered=true attempts=1 datagrams=2 message=StatsD export delivered

The command is an observability connector, not a delivery feature. StatsD transport is best-effort, so successful local sending must not be treated as durable telemetry custody. Full connector guidance is documented in StatsD Integration.

nats-sink-observe datadog-export

Exports policy-approved metrics as DogStatsD datagrams to a local or explicitly approved Datadog Agent listener. The command is disabled unless both the top-level observability policy and datadog.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, datagram-size bounds, and redaction posture as the other observability connectors.

Dry-run mode prints DogStatsD lines without opening a socket:

nats-sink-observe datadog-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

nats_sinks.messages_fetched_total:256|g|#environment:test,service:nats-sinks
nats_sinks.messages_acked_total:256|g|#environment:test,service:nats-sinks

Example success output:

Datadog export: attempted=true delivered=true attempts=1 datagrams=2 message=Datadog export delivered

The command is an observability connector, not a delivery feature. DogStatsD transport is best-effort, Datadog tags are opt-in and bounded, and successful local sending must not be treated as durable telemetry custody. Full connector guidance is documented in Datadog Integration.

nats-sink-observe cloudwatch-export

Exports policy-approved metrics to Amazon CloudWatch custom metrics through PutMetricData. The command is disabled unless both the top-level observability policy and cloudwatch.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, and redaction posture as the other observability connectors.

Dry-run mode prints the CloudWatch request list without importing boto3, loading AWS credentials, or calling AWS:

nats-sink-observe cloudwatch-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

[
  {
    "MetricData": [
      {
        "MetricName": "nats_sinks_messages_fetched_total",
        "StorageResolution": 60,
        "Unit": "None",
        "Value": 256.0
      }
    ],
    "Namespace": "nats-sinks/metrics"
  }
]

Example success output:

Amazon CloudWatch export: attempted=true delivered=true attempts=1 requests=1 metrics=1 message=Amazon CloudWatch export delivered

The command is an observability connector, not a delivery feature. Successful local export means the AWS SDK accepted the PutMetricData call; it does not prove alert evaluation, dashboard rendering, or downstream retention. Full connector guidance is documented in Amazon CloudWatch Integration.

nats-sink-observe azure-monitor-export

Exports policy-approved metrics to Azure Monitor custom metrics through the regional Azure Monitor REST endpoint for one reviewed Azure resource. The command is disabled unless both the top-level observability policy and azure_monitor.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, request-size bounds, and redaction posture as the other observability connectors.

Dry-run mode prints the Azure Monitor request bodies without loading a bearer token or calling Azure:

nats-sink-observe azure-monitor-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

[
  {
    "data": {
      "baseData": {
        "dimNames": [
          "deployment"
        ],
        "metric": "nats_sinks_messages_fetched_total",
        "namespace": "nats-sinks/metrics",
        "series": [
          {
            "count": 1,
            "dimValues": [
              "edge"
            ],
            "max": 256.0,
            "min": 256.0,
            "sum": 256.0
          }
        ]
      }
    },
    "time": "2026-05-28T12:00:00.000Z"
  }
]

Example success output:

Azure Monitor export: attempted=true delivered=true attempts=1 requests=1 metrics=1 status=200 message=Azure Monitor export delivered

The command is an observability connector, not a delivery feature. Successful local export means Azure Monitor accepted the HTTP request; it does not prove alert evaluation, dashboard rendering, or downstream retention. Full connector guidance is documented in Azure Monitor Integration.

nats-sink-observe syslog-export

Exports policy-approved metrics as RFC 5424-style syslog messages over UDP or a Unix datagram socket. The command is disabled unless both the top-level observability policy and syslog.enabled are true. It uses the same local snapshot, allow and deny lists, stale-snapshot checks, timeout bounds, retry bounds, and redaction posture as the other observability connectors.

Dry-run mode prints syslog messages without opening a socket:

nats-sink-observe syslog-export \
  /var/lib/nats-sink/metrics.json \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

<134>1 2026-09-21T14:13:20.000Z - nats-sinks - metrics [nats_sinks metric="messages_fetched_total" kind="counter" value="256" namespace="nats_sinks" profile="syslog"] -
<134>1 2026-09-21T14:13:20.000Z - nats-sinks - metrics [nats_sinks metric="messages_acked_total" kind="counter" value="256" namespace="nats_sinks" profile="syslog"] -

Example success output:

Syslog export: attempted=true delivered=true attempts=1 messages=2 message=Syslog export delivered

The command is an observability connector, not a delivery feature. Syslog transport is best-effort, messages are bounded and sanitized, and successful local sending must not be treated as durable telemetry custody. Full connector guidance is documented in Syslog Bridge.

nats-sink-observe nats-monitoring-poll

Polls policy-approved NATS server monitoring endpoints and writes a sanitized local snapshot. This command is disabled unless the top-level observability policy and nats_server_monitoring.enabled are true.

nats-sink-observe nats-monitoring-poll \
  /etc/nats-sinks/observability.prometheus.json \
  --output /var/lib/nats-sink/nats-monitoring.json

Use --dry-run to review the snapshot without writing a file:

nats-sink-observe nats-monitoring-poll \
  /etc/nats-sinks/observability.prometheus.json \
  --dry-run

Example dry-run output:

{
  "schema": "nats_sinks.observability.nats_monitoring.snapshot.v1",
  "generated_at_epoch_seconds": 1797820000.0,
  "endpoints": [
    {
      "endpoint": "/jsz",
      "status_code": 200,
      "fields": {
        "jetstream.stats.messages": 42,
        "jetstream.stats.consumer_count": 3
      }
    }
  ]
}

The snapshot does not include the configured monitoring base URL. It includes only endpoint paths and the scalar fields selected by policy.

nats-sink-observe nats-monitoring-prometheus

Renders selected numeric NATS monitoring values as Prometheus text. This command is disabled unless nats_server_monitoring.prometheus_enabled is true.

nats-sink-observe nats-monitoring-prometheus \
  /var/lib/nats-sink/nats-monitoring.json \
  /etc/nats-sinks/observability.prometheus.json \
  --output /var/lib/node_exporter/textfile_collector/nats_sinks_nats_monitoring.prom

Example output:

# HELP nats_sinks_nats_monitoring_jsz_jetstream_stats_messages NATS server monitoring value for /jsz field jetstream.stats.messages
# TYPE nats_sinks_nats_monitoring_jsz_jetstream_stats_messages gauge
nats_sinks_nats_monitoring_jsz_jetstream_stats_messages 42

String values such as server identifiers are not rendered to Prometheus. They remain in the local snapshot only when explicitly allowed by policy.

CLI Flow

sequenceDiagram
    participant U as User
    participant C as CLI
    participant CFG as JSON Config
    participant S as Sink Registry
    participant R as Runner

    U->>C: nats-sink run config.json
    C->>CFG: Load and validate
    C->>S: Create selected sink
    C->>R: Build runner
    R->>R: Connect, consume, write, ACK last

The CLI returns non-zero for validation and runtime failures. It never prints resolved passwords.

nats-sink-metrics returns 0 on success, 2 for invalid snapshot or display input, 3 for stale snapshots when staleness is enforced, and 4 when get cannot find a metric without a default value.

nats-sink-observe returns 0 on success, 2 for invalid configuration, policy, snapshot, textfile output errors, disabled native endpoint startup, or profile render errors, and 3 when an enabled Prometheus HTTP dry-run returns an error response, a stale snapshot is rejected, or an enabled OTLP, Elastic, Grafana Alloy, Splunk HEC, OCI Monitoring, StatsD, Datadog, Amazon CloudWatch, Azure Monitor, or syslog export exhausts bounded delivery attempts.