Skip to content

Add DNS logs to railway logs - #1025

Merged
m-abdelwahab merged 3 commits into
masterfrom
mahmoud/dns-logs
Jul 27, 2026
Merged

Add DNS logs to railway logs#1025
m-abdelwahab merged 3 commits into
masterfrom
mahmoud/dns-logs

Conversation

@m-abdelwahab

@m-abdelwahab m-abdelwahab commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds railway logs --dns for viewing the DNS query logs that shipped in the dashboard this week (deployment → Network tab → DNS). Streams live queries by default, or fetches history with --lines, --since, or --until.

DNS joins --deployment, --build, --http, and --network in the mutually exclusive log-type group, and follows the same conventions: typed filter flags mirror the filter attributes, and compose with a raw --filter expression.

API

railway logs --dns                                              # Stream live DNS queries
railway logs --dns --status failed                              # Failed lookups only
railway logs --dns --rcode NXDOMAIN                             # Names that don't exist
railway logs --dns --zone internal                              # Private network lookups
railway logs --dns --domain example.com --qtype AAAA            # IPv6 lookups for a domain
railway logs --dns --qname backend.railway.internal --lines 50  # History for an exact name

Typed flags (all require --dns):

Flag Filter attribute Values
--domain @domain domain including subdomains
--qname @qname exact name looked up
--qtype @qtype any record type, normalized to uppercase (e.g. A, AAAA, CNAME, PTR, SOA)
--rcode @rcode any response code, normalized to uppercase (e.g. NOERROR, NXDOMAIN, FORMERR, plus synthetic TIMEOUT/ERROR)
--zone @zone internal, external
--status @status ok, failed (shared flag, mode-validated like --network)

--qtype and --rcode are open string values rather than closed enums so registered DNS values and future backend additions work without a CLI release. --zone stays a closed enum since it mirrors the API's DnsQueryZone enum.

Output is a table (Time, Zone, Type, Rcode, Name, Answers) with --json emitting one object per row including answers, cnameChain, and IDs.

What changed

  • src/gql/schema.json: adds the DnsQueryLog type, DnsQueryZone enum, and dnsQueryLogs query/subscription fields (both are on the public subgraph in backboard).
  • src/gql/{queries,subscriptions}/strings/DnsQueryLogs.graphql + codegen registration.
  • src/controllers/deployment.rs:
    • fetch_dns_query_logs mirrors fetch_network_flow_logs (same anchor-window semantics).
    • New stream_anchored_logs helper drives both the network flow and DNS subscriptions with the same reconnect policy as stream_http_logs_inner: mid-stream errors are retried with backoff instead of aborting, every reconnect waits at least the initial delay (no hot reconnect loops on short-lived connections), and retry state only resets once a connection proves stable. This also fixes the pre-existing retry gaps in --network streaming.
    • DNS rows carry no unique ID, so reconnect replays are recognized by full serialized row contents — but deduplication only applies to rows at or before the previous connection's watermark. Identical queries arriving live on a healthy connection are all emitted. A server-provided query ID would make this exact; worth a follow-up in backboard.
    • Shared helpers renamed for the two anchored log types (anchored_log_window, StreamedLogDedupe, stream_before_date, update_max_stream_timestamp, should_reset_stream_retry_state).
  • src/util/logs.rs: DnsQueryLogLike trait, table header/row formatters, JSON output with a timestamp alias matching the network flow convention.
  • src/commands/logs.rs: --dns mode, typed flags, filter composition, validation, help text, and examples.

Validation

  • cargo test --bin railway (482 passed), including unit tests for filter composition, invalid --status values, mode mutual exclusion, typed-flag mode validation, uncommon --qtype/--rcode values, and replay-cutoff detection
  • cargo fmt --all -- --check
  • cargo clippy — no warnings in changed files
  • Not yet verified against production; draft until I run --dns streaming and history against a live service

🤖 Generated with Claude Code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m-abdelwahab m-abdelwahab added the release/minor Author minor release label Jul 24, 2026
@m-abdelwahab
m-abdelwahab marked this pull request as ready for review July 24, 2026 18:24
…/rcode

- Extract stream_anchored_logs, giving network flow and DNS streams the
  same reconnect policy as stream_http_logs_inner: mid-stream errors are
  retried with backoff instead of aborting, every reconnect waits at
  least the initial delay, and retry state only resets once a connection
  proves stable
- Scope DNS row deduplication to reconnect replays (rows at or before
  the previous connection's watermark); identical queries arriving live
  on a healthy connection are all emitted, and serialization failures
  fail open instead of collapsing rows
- Accept any --qtype/--rcode value as an uppercase-normalized string so
  registered DNS values the enums omitted (PTR, SOA, CAA, FORMERR, ...)
  and future backend values work without a CLI release

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m-abdelwahab

Copy link
Copy Markdown
Collaborator Author

Addressed all three review findings in c550f09:

1. Stream retry policy — Extracted a stream_anchored_logs helper that drives both the network flow and DNS subscriptions with the same reconnect policy as stream_http_logs_inner: mid-stream errors are retried with backoff instead of propagating out, every reconnect sleeps at least the initial delay (no hot loop on short-lived connections), and retry state only resets after a stable connection (received logs or ≥30s connected). Note this defect was inherited verbatim from the shipped --network stream, so the fix covers both.

2. Full-row deduplication — Dedupe is now replay-scoped: a row is only suppressed when it was already seen and its timestamp is at or before the previous connection's watermark (i.e. it falls in the reconnect lookback replay window). Identical queries arriving live on a healthy connection are all emitted, and serialization failures now fail open instead of collapsing rows onto a shared empty key. The residual gap is an out-of-order duplicate landing inside the 30s replay window right after a reconnect — a server-provided query ID (like flowId on network flows) would make this exact; I'll raise that with backboard as a follow-up.

3. Closed enums--qtype and --rcode now accept any value as an uppercase-normalized string (--qtype ptr@qtype:PTR), so registered DNS values the enums omitted (PTR, SOA, CAA, FORMERR, NOTIMP, …) and future backend values work without a CLI release. --zone stays a closed enum since it mirrors the API's DnsQueryZone enum.

Validation: 482 tests pass (new coverage for replay-cutoff detection and uncommon qtype/rcode values), fmt clean, clippy has no warnings in the changed files.

🤖 Generated with Claude Code

@m-abdelwahab
m-abdelwahab merged commit 1a2fc80 into master Jul 27, 2026
6 checks passed
@m-abdelwahab
m-abdelwahab deleted the mahmoud/dns-logs branch July 27, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/minor Author minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant