Observability
Every queue event the framework emits targets nest_rs::queue. One
target, every transport-layer log filterable by RUST_LOG=nest_rs::queue=debug,
every span attaching the same structured fields. The service-level
logs your #[process] method emits keep their own target (e.g.
features::audio) — same convention as the rest of the framework.
Targets and levels
Section titled “Targets and levels”| Target | What | Default level |
|---|---|---|
nest_rs::queue | Framework events: discovery, registration, job start/end, retries, fails. | info on success, warn on retry, error on terminal failure. |
nest_rs::transport | Boot: attached module-contributed transport transport=QueueWorker. | info. |
features::<feature> | Your service-level logs inside the #[process] method. | Your call. |
The level guarantee from the project’s posture: hot paths respect
RUST_LOG=info. Per-job framework logs sit at info (one line per
ack), debug lines exist for the dispatch path you only want under
investigation. Failures are warn/error so they survive aggressive
filtering.
Structured fields
Section titled “Structured fields”Every framework log carries the same field set so a downstream processor can group, count, or alert without parsing strings:
| Field | Type | Notes |
|---|---|---|
processor | &'static str | The processor host name, e.g. AudioProcessor::transcode. |
queue | &'static str | The Redis queue name. |
concurrency | usize | Fetch buffer (the in-flight ceiling), present on boot lines. |
retries | usize | The configured budget, present on boot lines. |
job_id | String | apalis-assigned id, present on per-job lines. |
attempt | u32 | Attempt counter (1 on first try). |
elapsed_ms | u64 | Wall time of the handler call. |
Prefer the structured form (queue = %name, job_id = %id) over
formatted strings. The OTLP appender propagates them as span
attributes.
What boot looks like
Section titled “What boot looks like”2026-06-03T10:18:41Z INFO nest_rs::transport: attached module-contributed transport transport=QueueWorker2026-06-03T10:18:41Z INFO nest_rs::queue: registered queue processor processor=AudioProcessor::transcode queue=audio concurrency=5 retries=32026-06-03T10:18:41Z DEBUG nest_rs::queue: skipped #[process] method: provider unreachable from app's module tree processor=ReportJobs::weekly queue=reportsTwo lines per active processor (one attached, one registered) plus
one debug skip for each #[process] method that compiled in but
wasn’t imported into this app — useful to confirm a shared features
crate isn’t accidentally activating handlers the binary doesn’t want.
What a job’s life looks like
Section titled “What a job’s life looks like”A successful job, one info line at start, one at end:
2026-06-03T10:18:46Z INFO nest_rs::queue: job started processor=AudioProcessor::transcode queue=audio job_id=01HFEX… attempt=12026-06-03T10:18:46Z INFO features::audio: transcoded file=track-1717405126521.mp32026-06-03T10:18:46Z INFO nest_rs::queue: job ok processor=AudioProcessor::transcode queue=audio job_id=01HFEX… attempt=1 elapsed_ms=342A retried job:
2026-06-03T10:19:02Z INFO nest_rs::queue: job started processor=AudioProcessor::transcode queue=audio job_id=01HFFA… attempt=12026-06-03T10:19:02Z WARN nest_rs::queue: job failed; retrying processor=AudioProcessor::transcode queue=audio job_id=01HFFA… attempt=1 elapsed_ms=12 error="connection refused"2026-06-03T10:19:02Z INFO nest_rs::queue: job started processor=AudioProcessor::transcode queue=audio job_id=01HFFA… attempt=22026-06-03T10:19:02Z INFO nest_rs::queue: job ok processor=AudioProcessor::transcode queue=audio job_id=01HFFA… attempt=2 elapsed_ms=298A job that exhausts its budget:
2026-06-03T10:19:30Z WARN nest_rs::queue: job failed; retrying processor=AudioProcessor::transcode queue=audio job_id=01HFFB… attempt=3 error="…"2026-06-03T10:19:30Z ERROR nest_rs::queue: job failed; budget exhausted processor=AudioProcessor::transcode queue=audio job_id=01HFFB… attempts=4 error="…"The error line is the one to alert on — the budget is gone, the job
is now in apalis’s failed list, no further attempt is coming on its
own.
Span structure
Section titled “Span structure”The worker opens one span per job, target nest_rs::queue, name
job. The handler runs inside it, so any tracing::info! your
service emits is automatically tagged with the job’s job_id,
processor, queue, attempt. The OTLP appender from
nest-rs-opentelemetry exports them as span attributes — the
OpenTelemetry / traces page covers
attribute mapping. The corresponding log-to-OTLP path is in
OpenTelemetry / logs.
Filtering recipes
Section titled “Filtering recipes”RUST_LOG=info,nest_rs::queue=debug nestrs run dev workerinfo everywhere, debug on the queue path: gives you the
boot-time skip lines plus the per-job dispatch decisions without
turning the rest of the framework loud.
RUST_LOG=nest_rs::queue=warn nestrs run dev workerStrictly retries and failures — useful for tailing a healthy worker where the only thing you care about is “did anything go wrong.”
See also
Section titled “See also”- OpenTelemetry — installing the OTLP appender so these spans and structured logs reach a backend.
- OpenTelemetry / traces — how
nest_rs::queuespans appear in a trace UI, attribute conventions. - OpenTelemetry / logs — structured-log export, severity mapping.
- Retries and failure — the policy
behind the
attemptfield and thefailedoutcome.