Skip to content

feat(xtcp): stdout destination + envelope JSON/text marshallers#35

Open
randomizedcoder wants to merge 1 commit into
mainfrom
feat/stdout-destination
Open

feat(xtcp): stdout destination + envelope JSON/text marshallers#35
randomizedcoder wants to merge 1 commit into
mainfrom
feat/stdout-destination

Conversation

@randomizedcoder

Copy link
Copy Markdown
Owner

Summary

Adds a stdout destination so xtcp2 can print socket data to its own stdout — e.g.:

xtcp2 -dest stdout -marshal protoJson -d 1

streams one JSON Envelope per poll cycle as NDJSON. Great for local development, debugging, and piping to jq. In Docker, the daemon's records appear directly in docker logs (logs go to stderr, so stdout carries only the JSON).

What's included

  • Reusable destination — backed by an io.Writer-based writerDest (default os.Stdout) instead of copying the null/udp Send/Close boilerplate. A future stderr/file sink is a one-line factory over the same type. The io.Writer seam is also the test seam (inject a bytes.Buffer).
  • Latent bug fix — the destination pipeline is envelope-based, but only protobufList was registered as an EnvelopeMarshaller. So -marshal protoJson|protoText|msgpack with any destination nil-deref panicked at flushEnvelope. This registers envelope-level marshallers for all three; protoJson uses protojson.Marshal (compact, one object per line).
  • Validationstdout is treated like null (both bare stdout and stdout: accepted).
  • -dest help mentions stdout.

Tests

  • writerDest framing (payload + newline, no buffer mutation), both write-error branches, and factory wiring — all via the io.Writer seam, no os.Stdout juggling.
  • Envelope marshaller resolution for protoJson/protoText/msgpack, and that the JSON output is valid one-line JSON with a row array.
  • Validation happy-paths for stdout / stdout:.

Verification

  • nix build .#test-pkg-xtcp, .#test-cmd-xtcp2, .#checks.x86_64-linux.golangci-lint all pass.
  • End-to-end in a container: -dest stdout -marshal protoJson -d 1 printed one-line JSON envelopes of real host sockets (105 rows, full tcp_info / congestion / skmem / cgroup fields) to stdout.

🤖 Generated with Claude Code

Add a `stdout` destination so the daemon can print socket data to its own
stdout — e.g. `xtcp2 -dest stdout -marshal protoJson` streams one JSON
Envelope per poll as NDJSON, ideal for local dev, debugging, and piping to
jq. The destination is backed by a reusable, io.Writer-based `writerDest`
(default os.Stdout) rather than copying the null/udp boilerplate; the
io.Writer seam also makes it unit-testable with a bytes.Buffer.

Fix a latent bug this exposed: the destination pipeline is envelope-based,
but only protobufList was registered as an EnvelopeMarshaller, so
`-marshal protoJson|protoText|msgpack -dest <any>` nil-deref panicked at
flushEnvelope. Register envelope-level marshallers for all three; protoJson
uses protojson.Marshal (compact, one object per line).

- pkg/xtcp/destinations_stdout.go: writerDest (io.Writer seam) + stdout factory
- pkg/xtcp/destinations_core.go: schemeStdout const + knownSchemes
- pkg/xtcp/input_validation.go: treat stdout like null (bare + ":"-suffixed)
- pkg/xtcp/marshallers.go: envelope protoJson/protoText/msgpack marshallers
- cmd/xtcp2: mention stdout in -dest help
- tests for the writer seam, error paths, factory, validation, and envelope
  JSON output (valid one-line JSON with a row array)

Verified end-to-end in a container: `-dest stdout -marshal protoJson -d 1`
prints one-line JSON envelopes of real host sockets to stdout (logs stay on
stderr; config dump only at -d >10).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant