Skip to content

HYPERFLEET-887 - feat: migrate Sentinel logger to slog with shared handler - #242

Open
kuudori wants to merge 2 commits into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-887-slog-migration
Open

HYPERFLEET-887 - feat: migrate Sentinel logger to slog with shared handler#242
kuudori wants to merge 2 commits into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-887-slog-migration

Conversation

@kuudori

@kuudori kuudori commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace custom pkg/logger (633-line logger + 824-line tests) with stdlib log/slog backed by the shared hyperfleet-logger handler
  • Context-based field enrichment (resource_type, topic, decision_reason, trace/span IDs) propagates automatically to all downstream log calls via the handler's context extraction using the generic Key[T] API
  • Delete internal/brokeradapter/ - broker v1.2 (HYPERFLEET-890) now accepts *slog.Logger directly, no adapter needed
  • Add internal/logctx/ for Sentinel-specific context field registration (topic, decision_reason)

What changed

Area Before After
Logger Custom pkg/logger.HyperFleetLogger (633 LOC) log/slog + hyperfleet-logger handler
Context fields Manual context.WithValue + extraction in buildEntry() hfl.Set(ctx, key, val) + handler auto-extraction
Broker adapter internal/brokeradapter/ wrapping custom Logger interface slog.Default() passed directly to broker
Field propagation Local logger only (slog.With(...)) Context-based - downstream code (client, payload builder, broker) gets fields automatically

Net

+376 / -1,961 lines across 22 files. Four packages deleted (pkg/logger/, internal/brokeradapter/), one added (internal/logctx/ - 15 lines).

Test plan

  • make verify - go vet + format check
  • make lint - golangci-lint, 0 issues
  • make test-unit - all unit tests pass
  • New TestTrigger_ContextFieldsPropagateToLogs verifies resource_type, topic, decision_reason appear in log output via context enrichment
  • New health handler log assertion tests (TestHealthzHandler_LogsOnInvalidConfig, TestHealthzHandler_LogsOnStalePoll, TestReadyzHandler_LogsOnCheckFailure)
  • make test-integration - requires Docker
  • make test-helm - no chart changes

@openshift-ci
openshift-ci Bot requested review from ma-hill and pnguyen44 August 5, 2026 20:25
@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ldornele for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
📝 Walkthrough

Summary by CodeRabbit

  • Improvements
    • Standardized application logging with structured output and consistent contextual details.
    • Improved visibility into sentinel decisions, topics, resource types, health checks, telemetry, and operational errors.
    • Centralized logging configuration across service startup, clients, broker integrations, and diagnostics.
  • Maintenance
    • Replaced the legacy logging system with the shared logging framework.
    • Simplified health and payload component initialization by removing logger configuration requirements.
    • Updated integration coverage to verify enriched diagnostic context.

Walkthrough

The change replaces the internal logger with Go’s log/slog and the shared hyperfleet-logger package. Service startup creates the shared handler from logging configuration. Components use structured fields and no longer receive logger instances. Sentinel context carries resource, topic, and decision fields. Telemetry uses shared trace and span context helpers. Unit and integration tests capture structured log output. The internal logger implementation and broker adapter are removed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers: ma-hill, pnguyen44


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Sec-02: Secrets In Log Output ❌ Error CWE-532: runServe logs yaml.Marshal(cfg.RedactedCopy()) as config, but RedactedCopy preserves arbitrary MessageData; a password or token entry is emitted. Remove configuration logging or recursively redact sensitive keys and values before both the slog debug record and fmt.Print config dump.
Docstring Coverage ⚠️ Warning Docstring coverage is 48.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (9 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hardcoded Secrets ✅ Passed PR additions contain no credential assignments, embedded-credential URLs, private-key markers, or encoded literals in configuration files; CWE-798 condition not found.
No Weak Cryptography ✅ Passed Complete PR diff and tracked Go scan found no MD5, DES, RC4, SHA-1, ECB, custom crypto, or secret comparisons; no CWE-327 or CWE-叫 timing issue identified.
No Injection Vectors ✅ Passed The PR adds no exec.Command, template.HTML, yaml.Unmarshal, or SQL query sink; YAML input uses Viper UnmarshalExact, and changed logging uses structured slog fields.
No Privileged Containers ✅ Passed No privileged settings appear in the PR diff. Dockerfile USER root is limited to the builder, documented for make installation, then switches to 1001; runtime and Helm defaults are non-root. No CWE...
No Pii Or Sensitive Data In Logs ✅ Passed No CWE-532 issue found: changed logs emit operational fields, IDs, counters, and errors, but no PII, session IDs, or raw request/response bodies; debug config output is disabled by default.
Title check ✅ Passed The title clearly identifies the Sentinel logger migration to slog and the shared handler.
Description check ✅ Passed The description directly explains the logger migration, context enrichment, removed packages, tests, and verification steps.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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

@hyperfleet-ci-bot

hyperfleet-ci-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

Risk Score: 5 — risk/high

Signal Detail Points
PR size 2397 lines (>500) +2
Sensitive paths cmd/ +2
Test coverage Missing tests for: cmd/sentinel internal/client internal/config internal/metrics +1

Computed by hyperfleet-risk-scorer

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/health/health.go (1)

63-68: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Pass the request context to writeJSON.

context.Background() discards request correlation fields when JSON encoding fails. Add a ctx context.Context parameter to writeJSON and pass req.Context() from both handlers.

As per coding guidelines: “Thread context.Context through calls and preserve correlation keys.” As per path instructions: “Flag context.Background() when parent context exists.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/health/health.go` around lines 63 - 68, Update
ReadinessChecker.writeJSON to accept a context.Context parameter and use it in
the encoding-error slog.ErrorContext call instead of context.Background().
Update both handler call sites to pass req.Context(), preserving the request
context and correlation fields.

Sources: Coding guidelines, Path instructions

🧹 Nitpick comments (1)
internal/metrics/metrics.go (1)

275-280: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Preserve caller context for metric validation logs.

These helpers create new background contexts. Their warning logs cannot include the poll operation, trace, or span fields. Thread ctx through the metric APIs, or return validation failures for Sentinel to log at its service boundary.

As per coding guidelines: “Thread context.Context through calls and preserve correlation keys” and “Log at service or system boundaries rather than deep in the call stack.” As per path instructions: “Flag context.Background() when parent context exists.”

Also applies to: 311-314, 344-347, 377-385, 413-416, 445-448, 468-469

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/metrics/metrics.go` around lines 275 - 280, Update the metric helper
APIs, including UpdatePendingResourcesMetric and the other validation helpers at
the referenced call sites, to accept and use the caller’s context instead of
creating context.Background(). Propagate ctx from Sentinel through every call so
warning logs preserve poll, trace, and span correlation fields; alternatively
return validation failures for Sentinel to log at its service boundary.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/config/config.go`:
- Around line 234-235: Move configuration diagnostics from LoadConfig to the
command boundary: remove both load-start and load-success slog.InfoContext calls
in internal/config/config.go, then after initLogging succeeds in
cmd/sentinel/main.go, emit the configuration-success log through the configured
default logger, preserving the existing context and file metadata.

In `@internal/logctx/logctx.go`:
- Around line 10-15: Add internal/logctx/logctx_test.go with a unit test for the
exported ContextFields function. Verify the returned fields register both
TopicKey ("topic") and DecisionReasonKey ("decision_reason"), preserving the
expected field order if the helper exposes it.

In `@pkg/telemetry/otel.go`:
- Around line 105-107: Add source comments at both intentional fallback
branches: the unrecognized sampler case in the sampler selection logic, and the
invalid or out-of-range OTEL_TRACES_SAMPLER_ARG handling that retains
defaultSamplingRate. Keep the existing logging and fallback behavior unchanged;
document that each branch intentionally degrades configuration and continues.

In `@test/integration/integration_test.go`:
- Around line 422-426: Add the logctx import and pass
hfl.WithContextFields(logctx.ContextFields()...) to the hfl.NewHandler options
so the integration handler registers decision_reason and topic on Published
event records.
- Around line 427-429: In the integration test setup, install the capture logger
before constructing the broker publisher so broker.NewPublisher receives and
stores that logger. Reorder the existing slog.SetDefault setup and publisher
creation while preserving restoration via prevDefault, ensuring publishing event
is emitted through the capture handler.

In `@test/integration/testcontainer.go`:
- Around line 62-65: Update the error path after broker.NewPublisher in the
container setup flow to check the error returned by container.Terminate(ctx) and
preserve both the publisher-creation and cleanup failures in the returned error.
Ensure every error return is handled without discarding the termination failure.
- Line 52: Update the RabbitMQ startup log in the testcontainer initialization
flow to stop logging the credential-bearing amqpURL value. Remove the "amqp_url"
field from the slog.InfoContext call, or replace it with a properly redacted URL
that cannot expose credentials.

---

Outside diff comments:
In `@internal/health/health.go`:
- Around line 63-68: Update ReadinessChecker.writeJSON to accept a
context.Context parameter and use it in the encoding-error slog.ErrorContext
call instead of context.Background(). Update both handler call sites to pass
req.Context(), preserving the request context and correlation fields.

---

Nitpick comments:
In `@internal/metrics/metrics.go`:
- Around line 275-280: Update the metric helper APIs, including
UpdatePendingResourcesMetric and the other validation helpers at the referenced
call sites, to accept and use the caller’s context instead of creating
context.Background(). Propagate ctx from Sentinel through every call so warning
logs preserve poll, trace, and span correlation fields; alternatively return
validation failures for Sentinel to log at its service boundary.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 90377db4-305f-4276-b11f-f383d035cb69

📥 Commits

Reviewing files that changed from the base of the PR and between e3c79d5 and e5170c2.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum, !**/go.sum
📒 Files selected for processing (21)
  • AGENTS.md
  • cmd/sentinel/main.go
  • go.mod
  • internal/client/client.go
  • internal/config/config.go
  • internal/health/health.go
  • internal/health/health_test.go
  • internal/logctx/logctx.go
  • internal/metrics/metrics.go
  • internal/payload/builder.go
  • internal/payload/builder_test.go
  • internal/sentinel/sentinel.go
  • internal/sentinel/sentinel_test.go
  • pkg/logger/broker_adapter.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/operationid_middleware.go
  • pkg/telemetry/otel.go
  • pkg/telemetry/otel_test.go
  • test/integration/integration_test.go
  • test/integration/testcontainer.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
💤 Files with no reviewable changes (4)
  • pkg/logger/operationid_middleware.go
  • pkg/logger/broker_adapter.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go

Comment thread internal/config/config.go Outdated
Comment thread internal/logctx/logctx.go
Comment thread pkg/telemetry/otel.go Outdated
Comment thread test/integration/integration_test.go
Comment thread test/integration/integration_test.go
Comment thread test/integration/testcontainer.go Outdated
Comment thread test/integration/testcontainer.go
kuudori and others added 2 commits August 5, 2026 15:47
…ndler

Replace custom pkg/logger with stdlib log/slog backed by the shared
hyperfleet-logger handler. Context-based field enrichment (resource_type,
topic, decision_reason, trace/span IDs) propagates automatically to all
downstream log calls via the handler's context extraction.

- Use hyperfleet-logger generic Key[T] API for type-safe context fields
- Delete pkg/logger/ (633-line custom logger + tests)
- Delete internal/brokeradapter/ (broker v1.2 accepts *slog.Logger directly)
- Add internal/logctx/ for Sentinel-specific context field registration
- Add context propagation and health handler log assertion tests
- Fix structured logging in testcontainer (fmt.Sprintf -> attrs)

Co-Authored-By: Claude <noreply@anthropic.com>
@kuudori
kuudori force-pushed the HYPERFLEET-887-slog-migration branch from e5170c2 to e3ddb3a Compare August 5, 2026 20:48
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/integration/integration_test.go`:
- Around line 529-530: Update the Sentinel event-log validation around the
resource_type check to preserve the documented subset compatibility field:
validate that entry["subset"] is present, or consistently migrate the contract
and all dependent consumers from subset to resource_type. Do not leave the test
asserting only resource_type while the established contract still requires
subset.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: e196e871-f29a-4391-bd64-10ad7d24cd75

📥 Commits

Reviewing files that changed from the base of the PR and between e3c79d5 and e3ddb3a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum, !**/go.sum
📒 Files selected for processing (22)
  • AGENTS.md
  • cmd/sentinel/main.go
  • go.mod
  • internal/client/client.go
  • internal/config/config.go
  • internal/health/health.go
  • internal/health/health_test.go
  • internal/logctx/logctx.go
  • internal/logctx/logctx_test.go
  • internal/metrics/metrics.go
  • internal/payload/builder.go
  • internal/payload/builder_test.go
  • internal/sentinel/sentinel.go
  • internal/sentinel/sentinel_test.go
  • pkg/logger/broker_adapter.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/operationid_middleware.go
  • pkg/telemetry/otel.go
  • pkg/telemetry/otel_test.go
  • test/integration/integration_test.go
  • test/integration/testcontainer.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
💤 Files with no reviewable changes (5)
  • pkg/logger/operationid_middleware.go
  • internal/config/config.go
  • pkg/logger/broker_adapter.go
  • pkg/logger/logger_test.go
  • pkg/logger/logger.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • go.mod
  • AGENTS.md
  • internal/logctx/logctx.go
  • internal/health/health.go
  • internal/client/client.go
  • internal/payload/builder_test.go
  • internal/metrics/metrics.go
  • pkg/telemetry/otel.go
  • cmd/sentinel/main.go
  • test/integration/testcontainer.go
  • internal/payload/builder.go
  • pkg/telemetry/otel_test.go
  • internal/health/health_test.go
  • internal/sentinel/sentinel.go
  • internal/sentinel/sentinel_test.go

Comment thread test/integration/integration_test.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant