Skip to content

feat(observability): expose net/http/pprof endpoints on an admin port - #843

Merged
taitelee merged 5 commits into
mainfrom
claude/143-pprof-admin-port-d3djaw
Oct 14, 2026
Merged

taitelee merged 5 commits into
mainfrom
claude/143-pprof-admin-port-d3djaw

Conversation

@taitelee

@taitelee taitelee commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Requested by Taite · project thread

Summary

Before: to diagnose memory growth, a goroutine leak or a CPU hotspot in a running process, you had to rebuild it with debug instrumentation. WaveHouse exposed no net/http/pprof endpoints.

After: with profiling.enabled: true (WH_PROFILING_ENABLED, default false), every process serves Go's pprof endpoints under /debug/pprof/ on profiling.addr (WH_PROFILING_ADDR, default 127.0.0.1:6060). This applies to every process whatever its roles, and the listener is separate from the API port. Covered: heap, CPU, goroutine, allocs, threadcreate, block, mutex, the execution trace, cmdline and symbol. The endpoints are unauthenticated, so the default address is loopback. kubectl port-forward still reaches it. Boot logs a WARN for any address that is not loopback. make dev turns profiling on unless WH_PROFILING_ENABLED is already set.

How:

  • observability.PprofHandler mounts pprof's handlers on a mux of its own. It is never added to the API router, and nothing serves http.DefaultServeMux, where the package's import also registers them.
  • internal/app/wire_profiling.go (new) runs the listener through the existing serve. A bind failure is logged and not fatal, the same as the metrics sidecar.
  • The listener has no WriteTimeout, because pprof refuses a ?seconds= longer than one.
  • Its BaseContext is canceled as the drain begins, so a CPU profile or trace in flight ends then instead of holding the stop for the whole server.shutdown_timeout.
  • config.Validate refuses an address that is not host:port, and a port that is server.port or the enabled Prometheus sidecar's port.

Call site in a shared file: internal/app/app.go gains one line, a.wireProfiling(), at the end of New. wire.go is untouched, to stay clear of #712 and #770.

Not included: block and mutex profiles return empty, because WaveHouse sets no sampling rate for either. The docs say so. Setting a rate would add a knob and runtime cost, so I left it for a follow-up if someone wants it.

Docs: configuration.mdx (new Profiling section, plus the YAML and env examples), deployment.md (new Profiling section with the commands), development.md (make dev), architecture.md, AGENTS.md, config.yaml, CHANGELOG.

Test plan

  • make build, go vet ./...
  • go test -race for internal/config, internal/observability and internal/app: config validation and warning cases, the default and zero-value cases, every pprof endpoint served, no other path served, the listener wired only when enabled, pprof returning 404 on the API router whether profiling is on or off, a live listener serving, a 60s CPU profile ending at the stop (this test fails without the shutdown cancel), and a bind failure that is not fatal
  • golangci-lint v2.11.4 on the touched packages, and markdownlint on the changed docs
  • Pre-push reviewers: code ship_it, docs ship_it
  • GitHub CI green on the head commit

Related Issues

Closes #143
Part of #777

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q9hHKxkKwmj22yP4Uu8fJR

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 40b003c4-fa39-4d3d-88ef-a083de7f7a15
📥 Commits

Reviewing files that changed from the base of the PR and between 9773db6 and 40f919c.

📒 Files selected for processing: 18
  • AGENTS.md
  • CHANGELOG.md
  • Makefile
  • config.yaml
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/configuration.mdx
  • docs/src/content/docs/deployment.md
  • docs/src/content/docs/development.md
  • internal/app/app.go
  • internal/app/wire_profiling.go
  • internal/app/wire_profiling_test.go
  • internal/config/backends.go
  • internal/config/config.go
  • internal/config/defaults_test.go
  • internal/config/profiling.go
  • internal/config/profiling_test.go
  • internal/observability/pprof.go
  • internal/observability/pprof_test.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
🧰 Additional context used
📚 Code guidelines: 5
.github/prompts/docs-review.md — auto-discovered
AGENTS.md — auto-discovered
.github/copilot-instructions.md — auto-discovered
CONTRIBUTING.md — auto-discovered
docs/src/content/docs/development.md — auto-discovered
📓 Path-based instructions: 6
Applicability reference: AGENTS.md: # AGENTS.md — AI Agent Instructions for WaveHouse Documentation *prose* — accuracy against the code, runnable examples, clarity, completeness — **and code↔docs sync** (code that changed but whose docs did...

📄 CodeRabbit inference engine (.github/prompts/docs-review.md)

Files:

  • docs/src/content/docs/development.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/configuration.mdx
  • docs/src/content/docs/deployment.md
Source excerpt: Add the field to the appropriate struct in `internal/config/config.go` with `yaml` and `env` tags, and put a non-zero default in `defaults()` there.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • internal/config/config.go
See [AGENTS.md](../AGENTS.md) for project conventions, architecture notes, and AI agent instructions.

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • AGENTS.md
Applicability reference: AGENTS.md: # AGENTS.md — AI Agent Instructions for WaveHouse **Scope** is the canonical docs-prose set from `scripts/docs-prose.sh` — a *denylist*: every tracked `.md`/`.mdx` EXCEPT `.claude/**`, `.github/**`, `CHAN...

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Files:

  • docs/src/content/docs/development.md
  • docs/src/content/docs/architecture.md
  • AGENTS.md
  • docs/src/content/docs/configuration.mdx
  • docs/src/content/docs/deployment.md
  • CHANGELOG.md
Applicability reference: AGENTS.md: # AGENTS.md — AI Agent Instructions for WaveHouse Tooling notes (the non-obvious bits `make help` won't tell you): **GNU Make 4+** required (uses `--output-sync=target`); macOS ships GNU Make 3.81, which...

📄 CodeRabbit inference engine (docs/src/content/docs/development.md)

Files:

  • internal/config/config.go
  • internal/config/backends.go
  • internal/app/app.go
  • docs/src/content/docs/development.md
  • docs/src/content/docs/architecture.md
  • AGENTS.md
  • internal/observability/pprof.go
  • docs/src/content/docs/configuration.mdx
  • internal/config/defaults_test.go
  • internal/app/wire_profiling.go
  • docs/src/content/docs/deployment.md
  • internal/config/profiling.go
  • internal/config/profiling_test.go
  • CHANGELOG.md
  • internal/observability/pprof_test.go
  • internal/app/wire_profiling_test.go
Source excerpt: **In MDX, leave a blank line between a JSX tag and a code fence.**

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • docs/src/content/docs/configuration.mdx
🧠 Learnings: 2
📓 Common learnings
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-10-14T19:22:18.193Z
Learning: Source excerpt:
# AGENTS.md — AI Agent Instructions for WaveHouse

## Operating Rules

3. **Every code change updates its docs + `CHANGELOG.md` in the same PR** — a code change without its doc update is incomplete ([§Documentation Sync](#documentation-sync)).
📚 Learning: 2026-06-26T12:23:22.696Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 346
File: internal/stream/subscriber_test.go:9-28
Timestamp: 2026-06-26T12:23:22.696Z
Learning: In this Go repository, prefer table-driven tests (e.g., `[]struct{...}` with `t.Run(...)`) only for tests that cover multiple scenarios/inputs and can be cleanly enumerated. Do not artificially rewrite a clear single-scenario sequential behavioral-flow test into a table-driven form just to fit the pattern; if there’s only one meaningful scenario, keep the test as a straightforward linear flow (as in `TestSubscriber_SendDeliversThenDropsWhenFull`).

Applied to files:

  • internal/config/profiling_test.go
🪛 LanguageTool
CHANGELOG.md

[typographical] ~13-~13: Consider using an em dash in dialogues and enumerations.
Context: - **Go's pprof endpoints on a listener of...

(DASH_RULE)

🔇 Additional comments: 1
internal/config/profiling_test.go: 1

14-14: 🎯 Functional Correctness

The package-level TestMain sets WH_SETTINGS_DIR=./settings before running these tests, so Load("nonexistent.yaml") receives a valid settings directory. The proposed test setup is unnecessary.

📝 Summary

Summary by CodeRabbit

  • New Features
    • Added optional Go profiling endpoints on a dedicated listener, disabled by default and bound to 127.0.0.1:6060 when enabled.
    • Added profiling configuration, address validation, and a warning when endpoints are exposed beyond the host. Profiling requests end when graceful shutdown begins.
    • Development mode enables profiling by default; it can be disabled with an environment setting.
  • Documentation
    • Added configuration, deployment, and development guidance for accessing and securing profiling endpoints.

The change adds configurable Go pprof endpoints on a separate HTTP listener. It adds address validation and warnings, wires the listener into application startup and shutdown, and documents configuration, deployment, and development use.

Changes: Profiling Listener

Layer / File(s) Summary
Profiling configuration and validation
internal/config/..., config.yaml, docs/src/content/docs/configuration.mdx
Adds profiling enablement and address settings, defaults the address to 127.0.0.1:6060, validates enabled addresses and port conflicts, and warns for non-loopback addresses. Tests cover defaults, validation, and warnings.
Dedicated pprof listener and integration
internal/observability/pprof.go, internal/observability/pprof_test.go, internal/app/..., docs/src/content/docs/architecture.md, docs/src/content/docs/deployment.md, docs/src/content/docs/development.md, Makefile, CHANGELOG.md, AGENTS.md
Adds a dedicated handler and conditionally starts its listener across application roles. Shutdown cancels in-flight profiling requests. Tests check endpoint responses, API-router isolation, shutdown, and bind failures. Documentation and make dev describe the listener and its use.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Config
  participant AppNew as app.New
  participant WireProfiling as wireProfiling
  participant PprofHandler
  participant ProfilingListener
  participant PprofClient
  AppNew->>WireProfiling: configure profiling component
  WireProfiling->>Config: read enabled setting and address
  WireProfiling->>PprofHandler: create dedicated handler
  WireProfiling->>ProfilingListener: start listener when enabled
  PprofClient->>ProfilingListener: request /debug/pprof/ endpoint
  ProfilingListener->>PprofHandler: route request
  WireProfiling->>ProfilingListener: cancel requests when shutdown begins
Loading

Suggested reviewers: ericandrechek

Merge Risk: ⚪ Minimal · up to 40f91

No identified issue blocks merging. If the profiling port is unavailable, the application continues running without profiling.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 10 files. (8 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed The changes satisfy the coding requirements in #143. Profiling adds WH_PROFILING_ENABLED and WH_PROFILING_ADDR, with profiling disabled by default and a loopback default address. PprofHandler …
Out of Scope Changes check Passed The changed source, tests, configuration, Makefile, changelog, and documentation all support #143. The configuration validation, loopback warning, lifecycle behavior, API-router exclusion, and deploym…
Title check Passed The title clearly and concisely identifies the main change: exposing net/http/pprof endpoints through an observability admin port.
Description check Passed The description is directly related to the changeset and explains the profiling listener, configuration, lifecycle behavior, testing, and documentation updates.
Full details: Docstring Coverage

Explanation

Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 10 files. (8 skipped: 8 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added documentation Improvements or additions to documentation go Pull requests that update go code area/observability Metrics, logs, traces, health, profiling area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release area/app Process wiring (internal/app): component build, run, release labels Oct 13, 2026
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

📚 Docs preview

✅ Live: https://pr-843-wavehouse-docs.wave-rf.workers.dev (follows this PR)
This commit (40f919c): https://dfc7d14a-wavehouse-docs.wave-rf.workers.dev (exactly this commit; open it if the link above looks stale)

  • Commit: 40f919c docs(configuration): list the profiling boot warning
  • Author: @taitelee
  • Committed: 2026-10-14 14:47 EDT
  • Uploaded: 2026-10-14 15:31 EDT (run)
Earlier commits (2)
Commit Preview (that commit only) Uploaded
69cd2a8 https://e6cb93a1-wavehouse-docs.wave-rf.workers.dev 2026-10-13 15:22 EDT
76aa54a https://fde6ef2e-wavehouse-docs.wave-rf.workers.dev 2026-10-13 15:19 EDT

@github-code-quality

github-code-quality Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Go

Go

main 221866e claude/143-pprof-adm... 40f919c +/-
93% 93% 0%
View coverage of the 8 most impacted files.
File main 221866e claude/143-pprof-adm... 40f919c +/-
internal/mq/external.go 85% 85% 0%
internal/ingest/worker.go 97% 97% 0%
internal/config/config.go 97% 97% 0%
internal/app/app.go 97% 97% 0%
internal/mq/nats_topology.go 91% 92% +1%
internal/config/profiling.go 0% 94% +94%
internal/app/wire_profiling.go 0% 100% +100%
internal/observ...bility/pprof.go 0% 100% +100%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 14, 2026 19:32 UTC

…n-port-d3djaw

# Conflicts:
#	AGENTS.md
#	CHANGELOG.md
#	docs/src/content/docs/configuration.mdx
#	docs/src/content/docs/deployment.md
#	docs/src/content/docs/development.md
#	internal/config/config.go
#	internal/config/defaults_test.go
@taitelee

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taitelee

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taitelee
taitelee marked this pull request as ready for review October 14, 2026 19:28
@taitelee
taitelee requested review from a team and EricAndrechek October 14, 2026 19:28
@taitelee
taitelee merged commit 731d54e into main Oct 14, 2026
35 checks passed
@taitelee
taitelee deleted the claude/143-pprof-admin-port-d3djaw branch October 14, 2026 19:33
@github-project-automation github-project-automation Bot moved this from Backlog to Done in WaveHouse Task Board Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/app Process wiring (internal/app): component build, run, release area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release area/observability Metrics, logs, traces, health, profiling documentation Improvements or additions to documentation go Pull requests that update go code

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat(observability): expose net/http/pprof endpoints on admin port

1 participant