-
Notifications
You must be signed in to change notification settings - Fork 7
HYPERFLEET-363 | feat(logger): Align HyperFleet API component with logging specification #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughReplaces legacy glog logging with a centralized slog-based logger and adds a LoggingConfig to ApplicationConfig (flags + env binding). Introduces pkg/logger (global init, HyperFleetHandler, OCM bridge, HTTP attrs, context keys), pkg/telemetry (InitTraceProvider, Shutdown), and middleware: masking and OTel instrumentation. CLI/server startup now initializes logging, optionally initializes OpenTelemetry with deferred shutdown, and starts API, Metrics, and Health servers. Request logging was reworked to accept a masking middleware, capture response status/duration, and emit structured logs. Multiple files updated to use context-aware logging; legacy HTTP log formatter/writer types removed. Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI (serve/migrate)
participant Config as Config Loader
participant Logger as pkg/logger
participant Telemetry as pkg/telemetry
participant Router as API Router
participant Middleware as pkg/middleware
participant Server as Servers (API/Metrics/Health)
CLI->>Config: parse flags & bind env (incl. Logging)
CLI->>Logger: initLogger(cfg.Logging)
Logger-->>CLI: global logger ready
alt OTel enabled
CLI->>Telemetry: InitTraceProvider(service, version, samplingRate)
Telemetry-->>CLI: TracerProvider (deferred Shutdown)
end
CLI->>Router: register middleware (OTel?, Masking, RequestLogging)
Server->>Middleware: incoming HTTP request
alt OTel enabled
Middleware->>Telemetry: otelhttp -> start span
Telemetry-->>Middleware: span context (trace_id/span_id)
Middleware->>Logger: inject trace/span IDs into context
end
Middleware->>Middleware: mask headers/body (if enabled)
Middleware->>Logger: emit structured request log
Middleware->>Server: forward to handler
Server->>Logger: handler logs enriched with context fields
Middleware->>Logger: emit structured response log (status, duration)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (54)
Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @pkg/config/logging_test.go:
- Around line 309-344: Rename the test function to reflect observed behavior:
change TestLoggingConfig_FlagsPrecedenceOverEnv to
TestLoggingConfig_EnvPrecedenceOverFlags (or a similar name indicating env
overrides flags), and update any test comments to match; leave the test body and
assertions as-is (they correctly verify that cfg.BindEnv() causes the LOG_LEVEL
env var to override the parsed flag), ensuring the new function name is unique
and the test still runs.
🧹 Nitpick comments (5)
cmd/hyperfleet-api/servecmd/cmd.go (1)
37-49: Consider usingApplicationConfig.Logginginstead of hardcoded values.The logger is initialized with hardcoded configuration while
ApplicationConfignow includes aLoggingfield that supports CLI flags and environment variables. Even for demonstration purposes, wiring this properly would validate the configuration integration.// Example integration approach: cfg := environments.Environment().Config cfg.Logging.BindEnv() level, _ := logger.ParseLogLevel(cfg.Logging.Level) format, _ := logger.ParseLogFormat(cfg.Logging.Format) output, _ := logger.ParseLogOutput(cfg.Logging.Output) logConfig := &logger.LogConfig{ Level: level, Format: format, Output: output, Component: "api", Version: "dev", Hostname: hostname, }pkg/config/logging.go (1)
64-101: Consider validating SamplingRate bounds.
OTEL_SAMPLING_RATEaccepts any float value, but sampling rates are typically constrained to [0.0, 1.0]. Invalid values like -1.0 or 2.0 would silently become the configured rate.🔎 Proposed fix
if val := os.Getenv("OTEL_SAMPLING_RATE"); val != "" { rate, err := strconv.ParseFloat(val, 64) - if err == nil { + if err == nil && rate >= 0.0 && rate <= 1.0 { l.OTel.SamplingRate = rate } }pkg/logger/context.go (1)
64-100: Inconsistent getter return signatures.
GetOperationIDreturns onlystring, while all other getters (GetTraceID,GetSpanID, etc.) return(string, bool). Consider aligning the signatures for API consistency.🔎 Proposed fix
// GetOperationID retrieves operation ID from context -func GetOperationID(ctx context.Context) string { - if opID, ok := ctx.Value(OpIDKey).(string); ok { - return opID - } - return "" +func GetOperationID(ctx context.Context) (string, bool) { + opID, ok := ctx.Value(OpIDKey).(string) + return opID, ok }pkg/logger/logger.go (2)
45-81: Type assertion may panic if slog passes unexpected Level type.Line 56 uses a direct type assertion
a.Value.Any().(slog.Level)which will panic if the value isn't aslog.Level. While slog should always pass a valid level, defensive coding would use the comma-ok idiom.🔎 Proposed fix
if a.Key == slog.LevelKey { - level := a.Value.Any().(slog.Level) - return slog.Attr{Key: "level", Value: slog.StringValue(strings.ToLower(level.String()))} + if level, ok := a.Value.Any().(slog.Level); ok { + return slog.Attr{Key: "level", Value: slog.StringValue(strings.ToLower(level.String()))} + } + return a }
165-180: Consider thread-safe initialization for globalLogger.
InitGlobalLoggerwrites toglobalLoggerandGetLoggerreads from it without synchronization. If called from multiple goroutines during startup, this could cause a data race.🔎 Proposed fix using sync.Once
+import "sync" + +var ( + globalLogger *slog.Logger + initOnce sync.Once +) + // InitGlobalLogger initializes the global logger with the given configuration func InitGlobalLogger(cfg *LogConfig) { - handler := NewHyperFleetHandler(cfg) - globalLogger = slog.New(handler) - slog.SetDefault(globalLogger) + initOnce.Do(func() { + handler := NewHyperFleetHandler(cfg) + globalLogger = slog.New(handler) + slog.SetDefault(globalLogger) + }) }Alternatively, if re-initialization is needed (e.g., for testing), use an atomic pointer or mutex.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
cmd/hyperfleet-api/servecmd/cmd.gopkg/config/config.gopkg/config/logging.gopkg/config/logging_test.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/operationid_middleware.go
💤 Files with no reviewable changes (1)
- pkg/logger/operationid_middleware.go
🧰 Additional context used
📓 Path-based instructions (1)
pkg/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Files:
pkg/config/config.gopkg/config/logging_test.gopkg/config/logging.gopkg/logger/context.gopkg/logger/logger_test.gopkg/logger/logger.go
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Applied to files:
pkg/config/config.gopkg/config/logging_test.gopkg/config/logging.gopkg/logger/context.gopkg/logger/logger_test.gocmd/hyperfleet-api/servecmd/cmd.gopkg/logger/logger.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Applied to files:
pkg/config/logging_test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
Applied to files:
pkg/logger/context.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{dao,services}/**/*.go : Use context.Context as the first parameter in all DAO and service method signatures
Applied to files:
pkg/logger/context.go
🧬 Code graph analysis (3)
pkg/config/config.go (1)
pkg/config/logging.go (2)
LoggingConfig(12-19)NewLoggingConfig(35-50)
pkg/config/logging_test.go (1)
pkg/config/logging.go (2)
NewLoggingConfig(35-50)LoggingConfig(12-19)
cmd/hyperfleet-api/servecmd/cmd.go (1)
pkg/logger/logger.go (4)
LogConfig(27-34)FormatJSON(23-23)InitGlobalLogger(168-172)Info(226-228)
🔇 Additional comments (25)
pkg/config/config.go (1)
21-21: LGTM! Logging configuration integration follows established patterns.The
Loggingfield is consistently wired throughNewApplicationConfig(),AddFlags(), andReadFiles(), matching the existing convention for other configuration subsystems.Also applies to: 31-31, 42-42, 55-55
pkg/config/logging_test.go (5)
1-42: LGTM! Well-structured default value tests.The table-driven approach is clean, and the validation of both exact values and non-empty string constraints for sensitive headers/fields is appropriate.
44-99: LGTM! Flag registration and parsing tests are thorough.Good coverage for flag existence checks and value parsing verification.
101-107: LGTM! ReadFiles stub test is appropriate.Confirms the no-op behavior as expected.
109-221: LGTM! Comprehensive BindEnv tests with proper isolation.Good coverage of basic logging vars, OTel settings, masking settings, and invalid value handling. The save/restore pattern ensures test isolation.
223-307: LGTM! Parsing utility tests cover key edge cases.Whitespace trimming and empty string handling are properly validated.
pkg/logger/logger_test.go (7)
13-51: LGTM! ParseLogLevel tests cover all valid levels and edge cases.Good coverage including case insensitivity, whitespace handling, and the "warning" alias.
53-123: LGTM! ParseLogFormat and ParseLogOutput tests are comprehensive.Proper validation of valid inputs, invalid inputs, and the empty-defaults-to-stdout behavior.
125-193: LGTM! JSON and Text format output tests verify expected fields.Good validation of message, level, component, version, hostname, and custom key-value pairs.
195-304: LGTM! Context field extraction tests are thorough.Both individual and combined context field tests provide good coverage for trace_id, span_id, request_id, cluster_id, resource_type, and resource_id.
306-369: LGTM! Stack trace tests validate error-level behavior correctly.Verifies stack traces appear only for error-level logs and validates the array structure.
371-427: LGTM! Log level filtering and GetLogger uninitialized tests are appropriate.Good coverage of filtering behavior and fallback to slog.Default().
429-572: LGTM! Convenience functions and formatted variants tests are comprehensive.Good coverage of Debug, Warn, and formatted functions (Debugf, Infof, Warnf, Errorf) with proper validation of level, message, error field, and stack trace expectations.
pkg/config/logging.go (3)
11-50: LGTM! Well-structured configuration with sensible defaults.The LoggingConfig, OTelConfig, and MaskingConfig structs are clean. Default sensitive headers and fields cover common security-sensitive values.
52-62: LGTM! AddFlags and ReadFiles follow established patterns.CLI flags are properly registered with descriptive help text.
103-125: LGTM! Parsing utilities correctly handle whitespace and empty input.The implementations are clean and match the test expectations.
pkg/logger/context.go (2)
9-26: LGTM! Type-safe context keys provide good API safety.Using distinct types for each key prevents accidental key collisions and improves code clarity.
28-62: LGTM! Context setters are clean and consistent.All
With*functions follow the same pattern.WithOpIDcorrectly avoids regenerating an existing operation ID.pkg/logger/logger.go (7)
16-34: LGTM! LogFormat and LogConfig provide clean configuration structure.The enum-based format and structured config enable type-safe logger initialization.
83-117: LGTM! Handler correctly extracts context fields and adds error metadata.Context field injection and error-level stack trace capture are well-implemented. The handler properly delegates to the underlying JSON/Text handler.
119-142: LGTM! Handler interface methods correctly preserve HyperFleet metadata.
WithAttrsandWithGroupproperly propagate component, version, and hostname to child handlers.
144-163: LGTM! Stack trace capture filters runtime and testing frames appropriately.The implementation provides useful stack traces for debugging without internal framework noise.
182-220: LGTM! Parsing utilities are robust with clear error messages.Good handling of case insensitivity, whitespace trimming, and informative error messages listing valid options.
222-252: LGTM! Context-aware logging convenience functions follow slog patterns.Both structured (
Debug,Info,Warn,Error) and formatted (Debugf,Infof,Warnf,Errorf) variants are properly implemented.
254-370: LGTM! Legacy OCMLogger preserved with clear deprecation notices.The backward-compatible glog-based logger is properly maintained with deprecation warnings, enabling incremental migration. Based on learnings, the structured logging with
Extra()method for adding context fields is preserved.
Add slog logger with config, context & testing update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @pkg/logger/context.go:
- Around line 19-20: OpIDHeader is incorrectly typed as OperationIDKey even
though it represents an HTTP header name; change its type to string (e.g.,
declare OpIDHeader as a plain string constant with value "X-Operation-ID") while
leaving OpIDKey as OperationIDKey, and update any usages expecting a string
header name (references to OpIDHeader) to use the new string type.
- Line 6: Update the ksuid dependency to v1.0.4: change the import reference in
pkg/logger/context.go remains the same but run `go get
github.com/segmentio/ksuid@v1.0.4` (or edit go.mod to set
github.com/segmentio/ksuid v1.0.4), then run `go mod tidy` and recompile/tests
to ensure no regressions; verify any uses of ksuid (e.g., calls in context.go
that generate IDs) still work against the updated API and adjust call sites if
the v1.0.4 API differs.
In @pkg/logger/logger.go:
- Around line 110-114: The code is adding a redundant "error" attribute by
calling r.AddAttrs(slog.String("error", r.Message)) even though slog already
records r.Message as "message"; remove that r.AddAttrs line so only the stack
trace is added for error-level records (leave captureStackTrace(4) and the
r.AddAttrs(slog.Any("stack_trace", stackTrace)) intact), ensuring no duplicate
"error" field is emitted.
🧹 Nitpick comments (2)
pkg/config/logging.go (1)
103-125: Consider filtering empty strings in list parsing.The
GetSensitiveHeadersListandGetSensitiveFieldsListfunctions trim whitespace but don't filter out empty strings. This means input like"Authorization,,Cookie"would produce["Authorization", "", "Cookie"], which could cause issues when matching headers/fields.🔎 Proposed enhancement
func (l *LoggingConfig) GetSensitiveHeadersList() []string { if l.Masking.SensitiveHeaders == "" { return []string{} } headers := strings.Split(l.Masking.SensitiveHeaders, ",") + result := make([]string, 0, len(headers)) for i := range headers { - headers[i] = strings.TrimSpace(headers[i]) + trimmed := strings.TrimSpace(headers[i]) + if trimmed != "" { + result = append(result, trimmed) + } } - return headers + return result } func (l *LoggingConfig) GetSensitiveFieldsList() []string { if l.Masking.SensitiveFields == "" { return []string{} } fields := strings.Split(l.Masking.SensitiveFields, ",") + result := make([]string, 0, len(fields)) for i := range fields { - fields[i] = strings.TrimSpace(fields[i]) + trimmed := strings.TrimSpace(fields[i]) + if trimmed != "" { + result = append(result, trimmed) + } } - return fields + return result }pkg/logger/logger.go (1)
91-108: Use context helper functions for consistency.The code uses raw type assertions
ctx.Value(TraceIDCtxKey).(string)to extract context values, but dedicated helper functions (GetTraceID,GetSpanID,GetClusterID, etc.) are defined inpkg/logger/context.go. Using the helpers improves consistency, maintainability, and ensures the same extraction logic is used throughout the codebase.🔎 Proposed refactor
- if traceID, ok := ctx.Value(TraceIDCtxKey).(string); ok && traceID != "" { + if traceID, ok := GetTraceID(ctx); ok && traceID != "" { r.AddAttrs(slog.String("trace_id", traceID)) } - if spanID, ok := ctx.Value(SpanIDCtxKey).(string); ok && spanID != "" { + if spanID, ok := GetSpanID(ctx); ok && spanID != "" { r.AddAttrs(slog.String("span_id", spanID)) } - if requestID, ok := ctx.Value(OpIDKey).(string); ok && requestID != "" { + if requestID, ok := GetOperationID(ctx); ok && requestID != "" { r.AddAttrs(slog.String("request_id", requestID)) } - if clusterID, ok := ctx.Value(ClusterIDCtxKey).(string); ok && clusterID != "" { + if clusterID, ok := GetClusterID(ctx); ok && clusterID != "" { r.AddAttrs(slog.String("cluster_id", clusterID)) } - if resourceType, ok := ctx.Value(ResourceTypeCtxKey).(string); ok && resourceType != "" { + if resourceType, ok := GetResourceType(ctx); ok && resourceType != "" { r.AddAttrs(slog.String("resource_type", resourceType)) } - if resourceID, ok := ctx.Value(ResourceIDCtxKey).(string); ok && resourceID != "" { + if resourceID, ok := GetResourceID(ctx); ok && resourceID != "" { r.AddAttrs(slog.String("resource_id", resourceID)) }Note: This refactor assumes
GetOperationIDis updated to return(string, bool)as suggested in the review ofpkg/logger/context.go.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
cmd/hyperfleet-api/servecmd/cmd.gopkg/config/config.gopkg/config/logging.gopkg/config/logging_test.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/operationid_middleware.go
💤 Files with no reviewable changes (1)
- pkg/logger/operationid_middleware.go
🧰 Additional context used
📓 Path-based instructions (1)
pkg/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Files:
pkg/config/logging_test.gopkg/logger/logger_test.gopkg/config/config.gopkg/logger/context.gopkg/config/logging.gopkg/logger/logger.go
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Applied to files:
cmd/hyperfleet-api/servecmd/cmd.gopkg/config/logging_test.gopkg/logger/logger_test.gopkg/config/config.gopkg/logger/context.gopkg/config/logging.gopkg/logger/logger.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Applied to files:
cmd/hyperfleet-api/servecmd/cmd.gopkg/config/logging_test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
Applied to files:
pkg/logger/context.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{dao,services}/**/*.go : Use context.Context as the first parameter in all DAO and service method signatures
Applied to files:
pkg/logger/context.go
🧬 Code graph analysis (5)
cmd/hyperfleet-api/servecmd/cmd.go (1)
pkg/logger/logger.go (4)
LogConfig(27-34)FormatJSON(23-23)InitGlobalLogger(168-172)Info(226-228)
pkg/config/logging_test.go (1)
pkg/config/logging.go (2)
NewLoggingConfig(35-50)LoggingConfig(12-19)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (14)
ParseLogLevel(183-196)Error(234-236)Errorf(250-252)LogFormat(17-17)FormatText(21-21)FormatJSON(23-23)ParseLogFormat(199-208)ParseLogOutput(211-220)LogConfig(27-34)InitGlobalLogger(168-172)Info(226-228)Debug(222-224)GetLogger(175-180)Warn(230-232)pkg/logger/context.go (6)
WithTraceID(29-31)WithSpanID(34-36)OpIDKey(19-19)WithClusterID(39-41)WithResourceType(44-46)WithResourceID(49-51)
pkg/config/config.go (1)
pkg/config/logging.go (2)
LoggingConfig(12-19)NewLoggingConfig(35-50)
pkg/logger/logger.go (1)
pkg/logger/context.go (6)
TraceIDCtxKey(21-21)SpanIDCtxKey(22-22)OpIDKey(19-19)ClusterIDCtxKey(23-23)ResourceTypeCtxKey(24-24)ResourceIDCtxKey(25-25)
🔇 Additional comments (14)
pkg/config/config.go (1)
21-21: LGTM! Logging configuration properly integrated.The
Loggingfield is correctly added toApplicationConfigand properly wired through the constructor, flag registration, and file reading. The integration follows the same pattern as other configuration sections.Also applies to: 31-31, 42-42, 55-55
cmd/hyperfleet-api/servecmd/cmd.go (1)
37-49: Verify integration with LoggingConfig in the next PR.The logger is initialized with hardcoded values instead of using
environments.Environment().ApplicationConfig().Logging, which was added in this PR. While the comment indicates this is "demonstration only" with "full migration in PR 3", please confirm that the next PR will properly integrate the logging configuration, including:
- Reading Level, Format, and Output from config
- Using application version instead of hardcoded "dev"
- Potentially making Component configurable
🔎 Example integration with config
- // Initialize slog logger (demonstration only, full migration in PR 3) ctx := context.Background() + env := environments.Environment() + loggingCfg := env.ApplicationConfig().Logging + + logLevel, err := logger.ParseLogLevel(loggingCfg.Level) + if err != nil { + glog.Fatalf("Invalid log level: %s", err.Error()) + } + + logFormat, err := logger.ParseLogFormat(loggingCfg.Format) + if err != nil { + glog.Fatalf("Invalid log format: %s", err.Error()) + } + + logOutput, err := logger.ParseLogOutput(loggingCfg.Output) + if err != nil { + glog.Fatalf("Invalid log output: %s", err.Error()) + } + hostname, _ := os.Hostname() logConfig := &logger.LogConfig{ - Level: slog.LevelInfo, - Format: logger.FormatJSON, - Output: os.Stdout, + Level: logLevel, + Format: logFormat, + Output: logOutput, Component: "api", - Version: "dev", + Version: env.Name(), Hostname: hostname, } logger.InitGlobalLogger(logConfig) - logger.Info(ctx, "New slog logger initialized (example)", "log_level", "info", "log_format", "json") + logger.Info(ctx, "Logger initialized", "log_level", loggingCfg.Level, "log_format", loggingCfg.Format)pkg/config/logging_test.go (1)
10-348: LGTM! Comprehensive test coverage for logging configuration.The test suite thoroughly covers:
- Default values
- CLI flag registration and parsing
- Environment variable binding and precedence
- Sensitive headers/fields list parsing
- Error handling for invalid values
The test name
TestLoggingConfig_EnvOverridesFlags(line 311) now accurately reflects the behavior being tested, addressing the previous review feedback.pkg/logger/logger_test.go (1)
1-572: LGTM! Excellent test coverage for the logger package.The test suite is comprehensive and well-structured, covering:
- Parsing functions (level, format, output) with error cases
- JSON and text format output validation
- Context field extraction (trace_id, span_id, request_id, cluster_id, resource_type, resource_id)
- Stack trace behavior at different log levels
- Log level filtering
- Uninitialized logger fallback behavior
- All convenience functions and their formatted variants
The tests properly validate structured logging behavior and ensure the new slog-based logger works correctly.
pkg/config/logging.go (2)
11-50: LGTM! Well-structured logging configuration with sensible defaults.The configuration structs are well-organized:
- Core logging settings (Level, Format, Output)
- OpenTelemetry configuration with sampling
- Masking configuration with predefined sensitive fields
Default values are production-ready:
infolevel prevents debug noisejsonformat for structured logging- Masking enabled by default with comprehensive sensitive field lists
52-101: LGTM! Clean separation between CLI flags and environment configuration.The implementation makes a good design choice:
- CLI flags expose only core logging settings (level, format, output) for common use cases
- Advanced settings (OTel, Masking) are environment-only, keeping the CLI interface simple
BindEnvsilently ignores parse errors for booleans/floats, maintaining default values on invalid input (tested behavior inlogging_test.golines 170-190)This design balances usability with configurability.
pkg/logger/logger.go (7)
16-34: Well-structured logging configuration.The
LogFormatenumeration andLogConfigstruct provide a clean, extensible configuration surface for the logger with clear documentation.
45-81: Solid handler implementation with proper customization.The
NewHyperFleetHandlerfunction correctly implements the slog handler pattern with appropriate field renaming (timestamp, level, message) and format selection (JSON vs. Text).
167-180: Clean global logger initialization pattern.The global logger initialization and retrieval functions follow standard Go patterns with a sensible fallback to
slog.Default()when not initialized.
182-220: Robust parsing helpers with clear error messages.The
ParseLogLevel,ParseLogFormat, andParseLogOutputfunctions provide clear error messages listing valid options, which improves developer experience.
222-252: Convenient context-aware logging API.The top-level convenience functions (
Debug,Info,Warn,Errorand their formatted variants) provide an ergonomic API for context-aware logging while maintaining the slog foundation.Based on learnings, this aligns with the guidance to use structured logging via
pkg/logger/logger.go.
254-288: Deprecation notice is clear.The legacy
OCMLoggerinterface andNewOCMLoggerconstructor are clearly marked as deprecated with a specific removal timeline (PR 3), which helps with migration planning.
144-163: Add validation that skip=4 correctly identifies the actual caller.The
captureStackTracefunction is called withskip=4fromHandle(line 111). The existingTestStackTracetest validates that stack traces are captured for error-level logs, but it only checks for the presence and structure of the stack trace array—it does not verify thatskip=4actually captures the caller's frame. To ensure the skip value is correct, add an assertion in the test that verifies the captured frames contain the expected caller (e.g., from the test function itself), not internal logger frames.pkg/logger/context.go (1)
64-70: MakeGetOperationIDconsistent with other getters.
GetOperationIDreturns only astring, while all otherGet*functions return(string, bool). This inconsistency makes it impossible for callers to distinguish between "not present in context" and "present but empty string".🔎 Proposed refactor
// GetOperationID retrieves operation ID from context -func GetOperationID(ctx context.Context) string { +func GetOperationID(ctx context.Context) (string, bool) { if opID, ok := ctx.Value(OpIDKey).(string); ok { - return opID + return opID, ok } - return "" + return "", false }Note: This is a breaking change. Verify and update all call sites across the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @pkg/middleware/otel.go:
- Around line 27-44: The middleware currently extracts span via
trace.SpanFromContext(r.Context()) before calling otelHandler.ServeHTTP, so your
WithTraceID/WithSpanID enrichments are overwritten by otelHandler's span; move
the extraction to after otelHandler has created the request span: call
otelHandler.ServeHTTP first (or wrap it so you get the request context it
establishes), then use trace.SpanFromContext on the resulting request context to
get TraceID/SpanID and call logger.WithTraceID/logger.WithSpanID on that context
before passing to downstream handlers (i.e., ensure enrichment reads span from
the context provided by otelHandler rather than the original r.Context()).
In @pkg/telemetry/otel.go:
- Line 10: Update the OpenTelemetry semantic conventions import from
"go.opentelemetry.io/otel/semconv/v1.4.0" to
"go.opentelemetry.io/otel/semconv/v1.11.0" (keep the semconv alias), and replace
any direct logging calls in this file with the structured logger from
pkg/logger/logger.go by calling the logger instance's Extra() method to attach
context fields; find usages in this file (e.g., any log.*, fmt.Println, or local
loggers) and convert them to logger.Extra(...).Error/Info/etc. with the same
message and context fields.
🧹 Nitpick comments (4)
pkg/middleware/masking_test.go (1)
253-306: Consider usingreflect.DeepEqualfor simpler comparison.The custom
deepEqualanddeepEqualSlicefunctions work correctly, butreflect.DeepEqualfrom the standard library handles nested maps and slices out of the box, reducing code to maintain.Simplified approach
import "reflect" // In tests, replace: if !deepEqual(resultMap, expectedMap) { // with: if !reflect.DeepEqual(resultMap, expectedMap) {pkg/middleware/masking.go (2)
35-44: Consider cloning header values to avoid shared slice references.Line 40 assigns the original
valuesslice reference tomasked[key]. If the originalheadersslice is modified elsewhere,maskedwould reflect those changes. While unlikely in practice, a defensive copy ensures true isolation.Defensive copy
} else { - masked[key] = values + masked[key] = append([]string(nil), values...) }
103-112: Substring matching is intentional but worth documenting in API.The
isSensitiveFielduses substring matching (e.g., "password" matches "user_password"). This is a good security default but could cause over-masking. The tests confirm this is intentional. Consider adding a brief note in the exportedMaskBodydoc comment about substring-based field matching.go.mod (1)
119-126: Align OpenTelemetry exporter version for consistency.Line 122 pins
otlptracehttpto v1.38.0 while other OpenTelemetry packages are at v1.39.0. Since v1.39.0 is available forotlptracehttp, consider upgrading to align dependency versions.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (6)
cmd/hyperfleet-api/server/routes.gogo.modpkg/middleware/masking.gopkg/middleware/masking_test.gopkg/middleware/otel.gopkg/telemetry/otel.go
🧰 Additional context used
📓 Path-based instructions (1)
pkg/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Files:
pkg/telemetry/otel.gopkg/middleware/masking_test.gopkg/middleware/otel.gopkg/middleware/masking.go
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
Applied to files:
cmd/hyperfleet-api/server/routes.gopkg/middleware/otel.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/transaction_middleware.go : Store database sessions in HTTP request context via middleware at request entry point
Applied to files:
cmd/hyperfleet-api/server/routes.gopkg/middleware/otel.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Applied to files:
cmd/hyperfleet-api/server/routes.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/server/**/*.go : Validate JWT tokens from Red Hat SSO in middleware before allowing requests to handlers
Applied to files:
pkg/middleware/masking_test.gopkg/middleware/masking.go
🧬 Code graph analysis (2)
cmd/hyperfleet-api/server/routes.go (1)
pkg/middleware/otel.go (1)
OTelMiddleware(18-45)
pkg/middleware/masking.go (1)
pkg/config/logging.go (1)
LoggingConfig(12-19)
🔇 Additional comments (7)
cmd/hyperfleet-api/server/routes.go (1)
71-76: LGTM!Good middleware ordering: OperationID → OTel → RequestLogging. This ensures trace context is available for request logging when OTel is enabled. The conditional enablement via configuration is clean.
pkg/telemetry/otel.go (2)
16-57: LGTM on tracer provider initialization logic.The sampling rate handling is correct:
>= 1.0→ always sample<= 0.0→ never sample- Otherwise → ratio-based sampling
The stdout exporter with pretty-print is suitable for development/debugging. The comment about future OTLP upgrade is helpful for maintainability.
59-65: LGTM!Graceful nil-check before shutdown prevents panics if the provider was never initialized.
pkg/middleware/masking_test.go (2)
11-90: LGTM!Good coverage of header masking scenarios including case-insensitive matching and disabled state.
92-182: LGTM!Thorough body masking tests covering nested objects, arrays, case-insensitive matching, non-JSON bodies, and empty bodies.
pkg/middleware/masking.go (2)
11-26: LGTM!Clean struct design with configuration-driven initialization. Storing the parsed lists at construction time avoids repeated parsing on each request.
46-91: LGTM!Robust JSON masking with:
- Graceful handling of non-JSON bodies
- Fallback on marshal errors
- Recursive handling of nested objects and arrays
This aligns well with the coding guideline to use structured logging. Based on learnings, sensitive data protection in logs is important for this repository.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/db/db_session/testcontainer.go (1)
41-111: Critical: Replace os.Exit(1) with error returns.The
Initfunction callsos.Exit(1)at five different error paths (lines 58, 67, 76, 100, 107). Usingos.Exitin library/package code is a critical anti-pattern because:
- It terminates the entire process without allowing callers to clean up resources
- It makes the code untestable (you cannot test error paths that call
os.Exit)- It violates Go conventions where library functions should return errors, not kill the process
- It prevents proper error handling and recovery by callers
♻️ Refactor Init to return error
Change the signature of
Initto return an error:-func (f *Testcontainer) Init(config *config.DatabaseConfig) { +func (f *Testcontainer) Init(config *config.DatabaseConfig) error { ctx := context.Background() pkglogger.Info(ctx, "Starting PostgreSQL testcontainer...") // Create PostgreSQL container container, err := postgres.Run(ctx, "postgres:14.2", postgres.WithDatabase(config.Name), postgres.WithUsername(config.Username), postgres.WithPassword(config.Password), testcontainers.WithWaitStrategy( wait.ForListeningPort("5432/tcp"). WithStartupTimeout(60*time.Second)), ) if err != nil { pkglogger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err) - os.Exit(1) + return fmt.Errorf("failed to start PostgreSQL testcontainer: %w", err) }Apply similar changes to all five error paths, and update
NewTestcontainerFactoryto handle or propagate the error:func NewTestcontainerFactory(config *config.DatabaseConfig) *Testcontainer { conn := &Testcontainer{ config: config, } - conn.Init(config) + if err := conn.Init(config); err != nil { + // Log and return nil, or change NewTestcontainerFactory signature to return error + panic(err) // Or handle appropriately + } return conn }Better yet, change
NewTestcontainerFactoryto return(*Testcontainer, error)so callers can handle initialization failures.
🤖 Fix all issues with AI agents
In @docs/logging.md:
- Around line 31-41: Add a language specifier to the two fenced code blocks:
change the middleware chain block surrounding the diagram ("HTTP Request ↓
OperationIDMiddleware ... Handler") to start with ```text and the text output
example block (the time=2026-01-07... log line) to start with ```text so both
fenced blocks include the "text" language for proper syntax highlighting and
readability; ensure only the opening fence is modified for each block and the
closing ``` remains unchanged.
In @pkg/api/error.go:
- Around line 64-66: The code creates a new background context (ctx :=
context.Background()) before logging the error in SendResponse path, which drops
request tracing; replace the Background() usage with the incoming request
context (use r.Context()) so the logger.Error call uses the request's trace/span
context (keep the existing err construction and logger.Error invocation but pass
r.Context() instead of ctx).
- Line 73: The code is creating a root context with ctx := context.Background(),
which loses request-level tracing; replace those instances with ctx :=
r.Context() (use the incoming *http.Request's Context) wherever ctx is
initialized (e.g., the occurrences at lines shown) so panic logs retain trace
and operation IDs; ensure r is the request variable in scope and update both
occurrences accordingly.
- Around line 42-44: The code creates a new background context (ctx :=
context.Background()) before logging the error, which drops tracing information;
change it to use the incoming request context (use r.Context() as ctx or pass
r.Context() directly) so logger.Error(...) receives the request's
trace/operation IDs; update the ctx variable usage around the err assignment and
the logger.Error call (the locations referencing ctx, fmt.Errorf and
logger.Error) to preserve tracing from the request.
In @pkg/db/migrations.go:
- Around line 30-36: Replace the printf-style logger.Errorf call in the
migration error path to use structured logging via the Extra() method: capture
the context and relevant fields (e.g., migrationID and the error returned by
m.MigrateTo) and call logger.Extra(ctx, map[string]interface{}{"migration_id":
migrationID, "error": err}).Error("Could not migrate") instead of
logger.Errorf(ctx, "Could not migrate: %v", err); leave the surrounding flow
(ctx, sessionFactory.New, newGormigrate, os.Exit(1)) unchanged.
In @pkg/logger/logger.go:
- Around line 109-113: The code adds a redundant "error" field using
r.AddAttrs(slog.String("error", r.Message)) even though slog already records
r.Message as "message"; remove that line from the error-level block (the one
invoking r.AddAttrs(slog.String("error", r.Message))) so only the stack trace
(captureStackTrace(4)) is added for error-level records; keep
r.AddAttrs(slog.Any("stack_trace", stackTrace)) and leave r.Message to the
default slog "message" field.
🧹 Nitpick comments (9)
pkg/db/db_session/testcontainer.go (1)
171-171: Consider consistent structured logging throughout the file.Line 171 uses structured logging with key-value pairs (
"table", table, "error", err), which aligns with the coding guidelines for structured logging. However, the rest of the file uses formatted string logging (e.g.,Infof,Errorfwith format specifiers).For consistency and to fully leverage structured logging benefits (better queryability, automatic field extraction), consider using the structured key-value pattern throughout.
Example: Structured logging for other log calls
For instance, line 70 could be changed from:
pkglogger.Infof(ctx, "PostgreSQL testcontainer started at: %s", connStr)to:
pkglogger.Info(ctx, "PostgreSQL testcontainer started", "connection_string", connStr)Similarly, error logs like line 57:
pkglogger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err)could become:
pkglogger.Error(ctx, "Failed to start PostgreSQL testcontainer", "error", err)Based on coding guidelines.
pkg/errors/errors.go (1)
117-118: Consider using structured logging with Extra() for better observability.While the migration from
glog.Errorftologger.Errorfis correct, the error code could be added as a structured field rather than interpolated into the message. This aligns with the structured logging best practices and makes logs more queryable.Based on learnings and coding guidelines.
♻️ Proposed refactor using Extra()
- ctx := context.Background() - logger.Errorf(ctx, "Undefined error code used: %d", code) + ctx := context.Background() + logger.Extra(ctx, "error_code", code).Errorf("Undefined error code used")This approach adds the error code as a structured field, making it easier to query and aggregate in log analysis tools.
pkg/logger/ocm_bridge.go (2)
14-23: Clarify the purpose of the stored context field.The
ctxfield is stored in the struct but isn't used by the logging methods (Debug,Info,Warn,Error,Fatal), which instead use thectxparameter passed by the OCM SDK. The stored context is only referenced by the*Enabled()methods. This inconsistency may confuse future maintainers.Consider either:
- Removing the stored
ctxfield and using the parameterctxin all methods, or- Adding a comment explaining why
*Enabled()methods use the stored context while logging methods use the parameter context.
25-43: Consider preserving structured logging instead of pre-formatting messages.The current implementation uses
fmt.Sprintf(format, args...)to format messages before passing them to the logger. This loses the benefits of structured logging, as the formatted string cannot be parsed or queried effectively.While the OCM SDK uses format strings, you could parse the format string and args to extract structured fields, or at minimum, log the raw format and args as separate fields for better observability.
Example: Preserve format and args as structured fields
func (b *OCMLoggerBridge) Debug(ctx context.Context, format string, args ...interface{}) { - GetLogger().DebugContext(ctx, fmt.Sprintf(format, args...)) + GetLogger().DebugContext(ctx, fmt.Sprintf(format, args...), "ocm_format", format) }This approach logs the formatted message while preserving the original format string for structured queries.
test/helper.go (1)
544-555: Consider using a higher log level for tests by default.The test logger is configured with
slog.LevelInfo, which may produce verbose output during test runs. Consider usingslog.LevelWarnas the default, with the option to override via theLOGLEVELenvironment variable (which is already supported at Line 87).💡 Optional refinement
func initTestLogger() { cfg := &logger.LogConfig{ - Level: slog.LevelInfo, + Level: slog.LevelWarn, Format: logger.FormatText, // Use text format for test readability Output: os.Stdout, Component: "hyperfleet-api-test", Version: "test", Hostname: "test-host", } logger.InitGlobalLogger(cfg) }cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
15-27: Consider caching the masking middleware instance.The masking middleware is recreated on every request (Line 26). Since the configuration doesn't change per-request, consider creating it once during middleware initialization to avoid repeated allocations.
♻️ Optional optimization
+var masker *middleware.MaskingMiddleware +var maskerOnce sync.Once + func RequestLoggingMiddleware(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Skip health check endpoint to reduce log spam if strings.TrimSuffix(r.URL.Path, "/") == "/api/hyperfleet" { handler.ServeHTTP(w, r) return } - // Initialize masking middleware from environment config - masker := middleware.NewMaskingMiddleware(environments.Environment().Config.Logging) + // Initialize masking middleware once from environment config + maskerOnce.Do(func() { + masker = middleware.NewMaskingMiddleware(environments.Environment().Config.Logging) + }) maskedHeaders := masker.MaskHeaders(r.Header)Don't forget to add the
syncimport.cmd/hyperfleet-api/servecmd/cmd.go (2)
57-61: Use parent context for graceful shutdown.The shutdown defer uses
context.Background(), which ignores any cancellation from the parent context. If the application needs to perform graceful shutdown when the command context is canceled, consider usingctxinstead.♻️ Proposed fix
defer func() { - if err := telemetry.Shutdown(context.Background(), tp); err != nil { + if err := telemetry.Shutdown(ctx, tp); err != nil { logger.Error(ctx, "Failed to shutdown OpenTelemetry", "error", err) } }()
108-112: Consider defaulting to text format for invalid values.When an invalid log format is provided, the code defaults to
FormatJSON. Users might expect a simpler text format as the default, especially in development environments.♻️ Proposed change
format, err := logger.ParseLogFormat(cfg.Format) if err != nil { logger.Warn(ctx, "Invalid log format, using default", "format", cfg.Format, "error", err) - format = logger.FormatJSON // Default to JSON + format = logger.FormatText // Default to text }pkg/logger/logger.go (1)
54-56: Add type assertion safety check.The type assertion
a.Value.Any().(slog.Level)could panic if the value is not aslog.Level. While slog internals are stable, defensive programming suggests checking the assertion.🛡️ Proposed fix
if a.Key == slog.LevelKey { - level := a.Value.Any().(slog.Level) - return slog.Attr{Key: "level", Value: slog.StringValue(strings.ToLower(level.String()))} + if level, ok := a.Value.Any().(slog.Level); ok { + return slog.Attr{Key: "level", Value: slog.StringValue(strings.ToLower(level.String()))} + } + return a }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (30)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/errors/errors.gopkg/handlers/openapi.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/otel.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/logging.go
🚧 Files skipped from review as they are similar to previous changes (1)
- pkg/logger/logger_test.go
🧰 Additional context used
📓 Path-based instructions (7)
pkg/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Files:
pkg/db/db_session/test.gopkg/middleware/otel.gopkg/auth/authz_middleware_mock.gopkg/db/migrations.gopkg/db/db_session/testcontainer.gopkg/errors/errors.gopkg/api/error.gopkg/logger/ocm_bridge.gopkg/handlers/openapi.gopkg/telemetry/otel.gopkg/logger/logger.go
test/integration/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use Testcontainers to spin up isolated PostgreSQL instances for integration tests
Files:
test/integration/integration_test.go
pkg/{handlers,services}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Retrieve database sessions from context via db.NewContext() rather than creating new GORM connections
Files:
pkg/handlers/openapi.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: Automatically convert errors to OpenAPI error responses using errors.SendError() in HTTP handlers
Parse HTTP request bodies using json.NewDecoder(r.Body) in handler functions
Write HTTP responses using json.NewEncoder(w) for consistency with request parsing
Ensure all HTTP handlers follow the pattern: parse request, call service/DAO, handle errors, send response
Implement handlers as methods on handler structs that accept (w http.ResponseWriter, r *http.Request) parameters
Set HTTP status codes correctly: 201 Created for POST, 200 OK for GET, 204 No Content for DELETE operations
Files:
pkg/handlers/openapi.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Support pagination in list operations via ListArgs parameter with configurable limit and offset
Files:
pkg/handlers/openapi.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Return ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields in error handling
Files:
pkg/handlers/openapi.go
pkg/{db/transaction_middleware.go,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Store request operation IDs in context for tracing and debugging purposes in error logs
Files:
pkg/handlers/openapi.go
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{handlers,services}/**/*.go : Retrieve database sessions from context via db.NewContext() rather than creating new GORM connections
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/server.gopkg/db/migrations.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/openapi.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/server.gopkg/auth/authz_middleware_mock.godocs/logging.mdpkg/db/migrations.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/main.gopkg/errors/errors.gocmd/hyperfleet-api/server/api_server.gopkg/api/error.gocmd/hyperfleet-api/server/healthcheck_server.gotest/helper.gocmd/hyperfleet-api/environments/framework.gopkg/logger/ocm_bridge.gopkg/handlers/openapi.gocmd/hyperfleet-api/servecmd/cmd.gopkg/telemetry/otel.gopkg/logger/logger.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{dao,services}/**/*.go : Use context.Context as the first parameter in all DAO and service method signatures
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/server.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/main.gopkg/errors/errors.gocmd/hyperfleet-api/server/api_server.gopkg/api/error.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/openapi.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
Applied to files:
pkg/db/db_session/test.gopkg/middleware/otel.gotest/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/server.godocs/logging.mdpkg/db/migrations.gopkg/db/db_session/testcontainer.gopkg/errors/errors.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/api/error.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/transaction_middleware.go : Store database sessions in HTTP request context via middleware at request entry point
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/logging/request_logging_middleware.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/migrations/**/*.go : Use GORM AutoMigrate for schema management instead of manual SQL scripts
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to test/integration/**/*.go : Use Testcontainers to spin up isolated PostgreSQL instances for integration tests
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to test/factories/**/*.go : Provide test data factories in test/factories/ for consistent test fixture creation
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gotest/helper.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Applied to files:
test/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/main.gotest/helper.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/api/openapi_embed.go : Embed OpenAPI specification at compile time using //go:embed directive
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gocmd/hyperfleet-api/server/api_server.gotest/helper.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/migrations/**/*.go : Store cluster and node pool specifications as JSONB columns to allow flexible cloud provider configurations
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : Use polymorphic status tables with owner_type and owner_id columns to support multiple resource types
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/db_session/testcontainer.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/server/**/*.go : Extract user account ID and username from JWT claims for audit logging and authorization checks
Applied to files:
cmd/hyperfleet-api/server/server.gopkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/main.gopkg/errors/errors.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gotest/helper.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/server/**/*.go : Validate JWT tokens from Red Hat SSO in middleware before allowing requests to handlers
Applied to files:
pkg/auth/authz_middleware_mock.gopkg/errors/errors.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Automatically convert errors to OpenAPI error responses using errors.SendError() in HTTP handlers
Applied to files:
pkg/errors/errors.gopkg/api/error.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Return ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields in error handling
Applied to files:
pkg/errors/errors.gopkg/api/error.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/api/openapi/model_*.go : Support JSON request/response serialization with proper struct tags on generated OpenAPI models
Applied to files:
pkg/errors/errors.gotest/helper.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Implement handlers as methods on handler structs that accept (w http.ResponseWriter, r *http.Request) parameters
Applied to files:
cmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/api/error.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Write HTTP responses using json.NewEncoder(w) for consistency with request parsing
Applied to files:
cmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/api/error.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Set HTTP status codes correctly: 201 Created for POST, 200 OK for GET, 204 No Content for DELETE operations
Applied to files:
pkg/api/error.gopkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Use FIPS-compliant crypto with CGO_ENABLED=1 and GOEXPERIMENT=boringcrypto build flags
Applied to files:
test/helper.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Ensure all HTTP handlers follow the pattern: parse request, call service/DAO, handle errors, send response
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/services/**/*.go : Implement service layer between handlers and DAOs for business logic like status aggregation and generation tracking
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/servecmd/cmd.go
🧬 Code graph analysis (14)
pkg/middleware/otel.go (1)
pkg/logger/context.go (2)
WithTraceID(29-31)WithSpanID(34-36)
test/integration/integration_test.go (1)
pkg/logger/logger.go (2)
Infof(241-243)Warn(229-231)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (1)
Error(233-235)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
cmd/hyperfleet-api/server/server.go (1)
pkg/logger/logger.go (1)
Error(233-235)
pkg/auth/authz_middleware_mock.go (1)
pkg/logger/logger.go (1)
Info(225-227)
pkg/db/db_session/testcontainer.go (2)
pkg/logger/logger.go (4)
Info(225-227)Errorf(249-251)Infof(241-243)Error(233-235)pkg/db/migrations.go (1)
Migrate(17-24)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(249-251)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (3)
pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/logger/logger.go (1)
Info(225-227)
cmd/hyperfleet-api/server/api_server.go (4)
pkg/logger/ocm_bridge.go (1)
NewOCMLoggerBridge(19-23)pkg/logger/logger.go (2)
Info(225-227)Error(233-235)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)cmd/hyperfleet-api/environments/types.go (1)
Database(36-38)
pkg/api/error.go (1)
pkg/logger/logger.go (2)
Errorf(249-251)Error(233-235)
cmd/hyperfleet-api/server/healthcheck_server.go (2)
pkg/logger/logger.go (2)
Infof(241-243)Info(225-227)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(221-223)GetLogger(174-179)Info(225-227)Warn(229-231)Error(233-235)
cmd/hyperfleet-api/servecmd/cmd.go (3)
pkg/logger/logger.go (9)
Error(233-235)Warn(229-231)Info(225-227)ParseLogLevel(182-195)ParseLogFormat(198-207)FormatJSON(22-22)ParseLogOutput(210-219)LogConfig(26-33)InitGlobalLogger(167-171)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/telemetry/otel.go (2)
InitTraceProvider(16-57)Shutdown(60-65)
pkg/logger/logger.go (1)
pkg/logger/context.go (6)
TraceIDCtxKey(21-21)SpanIDCtxKey(22-22)OpIDKey(19-19)ClusterIDCtxKey(23-23)ResourceTypeCtxKey(24-24)ResourceIDCtxKey(25-25)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
🪛 LanguageTool
docs/logging.md
[grammar] ~297-~297: Ensure spelling is correct
Context: ...)` | ### Context-Aware Migration Old (glog): ```go func MyHandler(w http.ResponseW...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~315-~315: Ensure spelling is correct
Context: ...span_id } ### Error Handling Old (glog):go if err != nil { glog.Errorf...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
docs/logging.md
31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
195-195: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (38)
pkg/db/db_session/testcontainer.go (3)
7-7: Imports support problematic os.Exit pattern.The
osimport is only used foros.Exit(1)calls within theInitfunction. Usingos.Exitin library/package code is a critical anti-pattern that prevents proper error handling and makes the code untestable. Consider refactoringInitto return an error instead.Related to lines 58, 67, 76, 100, 107 where
os.Exit(1)is called.Also applies to: 19-19
133-153: LGTM!The
Closefunction correctly migrates to context-aware logging with pkglogger. Error handling is appropriate for cleanup code, where logging and continuing is acceptable.
177-186: LGTM!The
NewListenerfunction correctly migrates to context-aware logging with pkglogger. Error handling is appropriate.pkg/errors/errors.go (1)
9-9: No action required; the openapi import is valid.The import at line 9 is correct and necessary—the
AsOpenapiError()method at line 154 and related functions useopenapi.Error,openapi.ErrorDetailsInner, andopenapi.PtrString. The package is code-generated by themake generatebuild target, so it does not exist until generation is run. The static analysis warning is expected and will resolve during the normal build process.pkg/auth/authz_middleware_mock.go (1)
6-6: LGTM! Clean migration to context-aware structured logging.The migration from glog to the new logger package is correct and follows best practices. The logging call properly uses the request context and structured key-value pairs for better queryability.
Based on learnings, this follows the coding guideline to use structured logging via pkg/logger/logger.go.
Also applies to: 19-19
docs/logging.md (1)
1-498: Excellent comprehensive logging documentation.The documentation thoroughly covers the new slog-based logging system, including:
- Clear architecture and component descriptions
- Configuration examples with environment variables
- Usage patterns and best practices
- OpenTelemetry integration details
- Data masking capabilities
- Migration guide from glog
This will be valuable for developers adopting the new logging system.
README.md (1)
158-158: LGTM! Documentation entry added correctly.The new Logging documentation entry is properly formatted and provides a clear, concise description of the logging features.
cmd/hyperfleet-api/environments/framework.go (4)
68-119: LGTM! Proper migration to context-aware logging in initialization flow.The migration correctly uses context.Background() for initialization logging, which is appropriate since this code runs during application startup before request contexts are available. The error handling pattern (log then exit) is consistent throughout.
Based on learnings, this follows the coding guideline to use structured logging via pkg/logger/logger.go.
135-160: LGTM! Clean logging migration in LoadClients.The client loading logic properly uses context-aware logging with structured messages. The use of logger.Info and logger.Errorf with context is correct.
163-174: LGTM! Proper cleanup logging in Teardown.The teardown function correctly uses context-aware error logging for resource cleanup failures.
176-185: Excellent use of structured logging with key-value pairs.Line 180 correctly uses the structured logging pattern with explicit key-value pairs ("flag", name, "error", err) instead of string formatting, which improves log queryability.
go.mod (2)
32-36: LGTM! OpenTelemetry dependencies added correctly.The OpenTelemetry dependencies are properly versioned (v1.39.0) and include the necessary components for HTTP instrumentation, tracing, and exporters.
72-72: glog is still a direct dependency, not an indirect one.The
go mod graphoutput showsgithub.com/openshift-hyperfleet/hyperfleet-api github.com/golang/glog@v1.2.5, indicating glog v1.2.5 is a direct dependency of the project, not merely an indirect transitive dependency. While the go.mod file marks it as// indirect, the module graph confirms it's pulled in directly by the project itself. Since no direct code imports of glog were found, it should be removed entirely if it's no longer needed.Likely an incorrect or invalid review comment.
pkg/logger/ocm_bridge.go (1)
45-49: LGTM: Fatal implementation follows expected behavior.The
Fatalmethod correctly logs at error level with a "FATAL: " prefix and exits immediately. This is standard behavior for fatal errors in logging bridges.pkg/db/db_session/test.go (1)
52-61: LGTM: Clean migration to structured logging.The migration from
glogto the internal logger package is correctly implemented. The context is appropriately created and passed to all logging calls, following the new structured logging pattern.pkg/handlers/openapi.go (2)
25-53: LGTM: Proper context usage and logging migration.The initialization correctly creates a context and uses it for structured logging during OpenAPI spec loading. The migration from
glogto the internal logger follows the established patterns.
61-83: LGTM: Excellent use of structured logging with context.The handler methods correctly use
logger.NewOCMLoggerwith theExtra()method to add structured fields (endpoint, method, status_code, error), following the coding guidelines for structured logging. The error handling after response commitment is also appropriate.Based on coding guidelines: Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields.
cmd/hyperfleet-api/server/server.go (1)
27-34: LGTM: Proper structured logging migration.The
check()function correctly migrates to structured logging usinglogger.Errorwith key-value pairs. The context is appropriately created and the error is logged as a structured field.cmd/hyperfleet-api/server/healthcheck_server.go (1)
43-63: LGTM: Clean logging migration with proper context usage.The
Start()method correctly migrates fromglogto the internal logger with appropriate context creation and usage across all logging statements. The migration maintains the informational logging while adding context awareness.pkg/api/error.go (1)
92-92: LGTM: Appropriate use of Background() in init.Using
context.Background()is correct here sinceinit()runs at package initialization time before any HTTP requests exist.Also applies to: 113-113
cmd/hyperfleet-api/migrate/cmd.go (1)
33-44: LGTM: Proper context and logging for CLI command.The use of
context.Background()is appropriate for this CLI migration command, and the structured logging follows the project's logging guidelines.test/helper.go (1)
74-74: LGTM: Appropriate use of Background() in test infrastructure.Using
context.Background()is correct throughout this test helper since these are test lifecycle functions without HTTP request contexts.Also applies to: 142-142, 166-166, 176-176, 184-184, 194-194, 203-203, 210-210, 221-221, 228-228
test/integration/integration_test.go (1)
15-52: LGTM: Proper structured logging in test setup.The TestMain function correctly uses
context.Background()and structured logging. The schema path detection logic is well-structured with appropriate error handling.cmd/hyperfleet-api/server/logging/request_logging_middleware.go (2)
30-54: LGTM: Well-structured request/response logging.The middleware correctly:
- Uses request context for trace propagation (Line 17)
- Masks sensitive headers (Line 27)
- Captures status codes via response wrapper (Lines 39-43)
- Logs both request start and completion with appropriate fields
This implementation aligns with the structured logging guidelines.
59-68: LGTM: Correct response writer wrapper implementation.The
responseWritercorrectly captures the HTTP status code while delegating to the wrapped writer. The default status ofhttp.StatusOK(Line 39) properly handles cases where handlers don't explicitly callWriteHeader.cmd/hyperfleet-api/main.go (3)
26-34: LGTM! Early logger initialization and consistent error handling.The implementation correctly:
- Initializes the logger before any operations that might log
- Uses consistent error handling pattern (
logger.Error+os.Exit(1))- Creates a context for structured logging
54-66: LGTM! Bootstrap logger with sensible defaults.The default logger initialization is appropriate for early startup before configuration is loaded. The
"unknown"version (line 62) will be replaced when the full configuration is initialized in the serve command.
68-74: LGTM! Graceful fallback for hostname retrieval.The silent fallback to
"unknown"is appropriate during bootstrap initialization, as hostname is not critical for logger functionality.cmd/hyperfleet-api/server/api_server.go (3)
39-40: LGTM! Correct OCM logger bridge initialization.The authentication handler correctly uses
logger.NewOCMLoggerBridgewith a background context, which is appropriate for a long-lived component.
106-127: LGTM! Proper structured logging with context.The logging implementation correctly:
- Creates and uses context for all logging calls
- Uses structured fields for contextual information (
"bind_address")- Provides clear lifecycle messages for TLS/non-TLS serving and termination
138-151: LGTM! Consistent error handling and structured logging.The error handling correctly:
- Uses context for all logging calls
- Applies structured fields for error details
- Follows the consistent pattern of
logger.Error+os.Exit(1)for fatal startup errors- Logs database connection close errors appropriately
cmd/hyperfleet-api/servecmd/cmd.go (2)
17-32: LGTM!The migration from glog to structured logging is correctly implemented. The error handling pattern using
logger.Errorwith explicitos.Exit(1)provides better control over the shutdown process.
68-74: Good diagnostic logging.Logging the configuration details at startup provides valuable context for troubleshooting and auditing.
pkg/logger/logger.go (5)
15-33: LGTM!The type definitions are clean and well-documented. The
LogConfigstruct provides all necessary configuration options for the logger.
164-179: LGTM!The global logger initialization and retrieval pattern is clean. The fallback to
slog.Default()ensures the logger is always available, even if initialization hasn't occurred yet.
181-219: LGTM!The parser functions provide clear validation with helpful error messages. The support for aliases (e.g., "warn" and "warning") improves usability.
221-251: LGTM!The helper functions provide a clean, consistent API for structured logging. All functions are context-aware, which aligns with the coding guidelines.
Based on learnings, this correctly implements structured logging via the Extra() method pattern (available through the OCMLogger interface).
253-355: LGTM!The OCM Logger compatibility layer is well-implemented:
- Immutable logger pattern in
Extra()prevents unintended side effects- Context fields (account_id, tx_id) are extracted and preserved
- The
V()method correctly maps verbosity levels to debug/infoFatal()appropriately exits the process
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/migrate/cmd.go:
- Line 37: The migrate command currently calls os.Exit() which bypasses deferred
cleanup and leaves the DB pool from db_session.NewProdFactory() open; after
creating the production DB factory (the call to db_session.NewProdFactory() that
returns connection), add a defer connection.Close() immediately so the
connection pool is released on any exit path, and ensure any early os.Exit()
paths call connection.Close() (or return instead) so resources are not leaked.
In @cmd/hyperfleet-api/server/logging/request_logging_middleware.go:
- Around line 26-27: The request logger currently creates a new masker on every
request by calling middleware.NewMaskingMiddleware inside
RequestLoggingMiddleware; instead, initialize the masker once and reuse it:
change RequestLoggingMiddleware to accept a prepared masker (or reference a
package-level masker) and remove middleware.NewMaskingMiddleware from the
per-request path, then call masker.MaskHeaders(r.Header) inside the handler as
before; update router setup to construct the masker once via
middleware.NewMaskingMiddleware(env.Config.Logging) and pass it into
RequestLoggingMiddleware when registering the middleware.
🧹 Nitpick comments (8)
cmd/hyperfleet-api/migrate/cmd.go (2)
36-37: Make error messages more specific.The generic message "Fatal error" doesn't convey what operation failed. Consider using a more descriptive message like "Failed to read database configuration files".
📝 Suggested improvement
- logger.Error(ctx, "Fatal error", "error", err) + logger.Error(ctx, "Failed to read database configuration files", "error", err)
41-44: Make error messages more specific.Similar to the previous error handler, use a more descriptive message like "Failed to run database migrations" instead of the generic "Fatal error".
📝 Suggested improvement
- logger.Error(ctx, "Fatal error", "error", err) + logger.Error(ctx, "Failed to run database migrations", "error", err)cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
30-36: Consider reducing header logging verbosity.Logging all headers on every request may produce very verbose logs and could impact performance, even with masking. Consider:
- Only logging headers in debug mode
- Logging a subset of important headers (e.g., Content-Type, Authorization status)
- Moving detailed header logging to trace level if available
pkg/logger/ocm_bridge.go (1)
14-23: Consider removing the stored context field.If the context field is only used by the
Enabledmethods and those are updated to accept context parameters, thectxfield in the struct becomes unnecessary. Consider simplifying the bridge to be stateless.♻️ Simplified implementation
// OCMLoggerBridge bridges slog to OCM SDK's Logger interface // Note: Uses "Bridge" instead of "Adapter" to avoid confusion with HyperFleet adapters (GCP/Azure adapters) -type OCMLoggerBridge struct { - ctx context.Context -} +type OCMLoggerBridge struct{} // NewOCMLoggerBridge creates an OCM SDK logger bridge -func NewOCMLoggerBridge(ctx context.Context) sdk.Logger { - return &OCMLoggerBridge{ - ctx: ctx, - } +func NewOCMLoggerBridge(ctx context.Context) sdk.Logger { + return &OCMLoggerBridge{} }pkg/errors/errors.go (1)
117-118: Consider accepting context as a parameter for better tracing.The use of
context.Background()is acceptable, but for improved observability, consider updating theNew()function signature to accept a context parameter. This would allow operation IDs and trace IDs to be included in error logs.♻️ Optional refactor
-func New(code ServiceErrorCode, reason string, values ...interface{}) *ServiceError { +func New(ctx context.Context, code ServiceErrorCode, reason string, values ...interface{}) *ServiceError { // If the code isn't defined, use the general error code var err *ServiceError exists, err := Find(code) if !exists { - ctx := context.Background() logger.Errorf(ctx, "Undefined error code used: %d", code)Note: This would require updating all call sites of
New()and the wrapper functions (NotFound, GeneralError, etc.) throughout the codebase.Based on learnings, request operation IDs should be stored in context for tracing and debugging purposes in error logs.
cmd/hyperfleet-api/environments/framework.go (1)
68-119: Consider consolidating context creation.The function creates
ctx := context.Background()at the start and uses it throughout, which is correct. However, multiple functions in this file create their own background contexts (lines 68, 135, 163, 177). Consider propagating a context from the caller to enable better trace propagation and testing.💡 Refactoring suggestion
Update the method signatures to accept context:
-func (e *Env) Initialize() error { - ctx := context.Background() +func (e *Env) Initialize(ctx context.Context) error { logger.Infof(ctx, "Initializing %s environment", e.Name)Apply similar changes to
LoadClients,Teardown, andsetConfigDefaults.pkg/logger/context.go (1)
11-11: Reconsider the type forOpIDHeader.
OpIDHeaderrepresents an HTTP header name ("X-Operation-ID"), which should be a plainstringconstant rather than a custom type. WhileOperationIDHeaderKeyprovides type safety, HTTP header names are conventionally strings in Go's standard library (e.g.,http.Headerusesstringkeys). This custom type may cause friction when used with standard HTTP APIs.🔄 Proposed refactor
// Context key types for type safety type OperationIDKey string -type OperationIDHeaderKey string type TraceIDKey string type SpanIDKey string type ClusterIDKey string type ResourceTypeKey string type ResourceIDKey string // Context keys for storing correlation fields const ( OpIDKey OperationIDKey = "opID" - OpIDHeader OperationIDHeaderKey = "X-Operation-ID" + OpIDHeader = "X-Operation-ID" TraceIDCtxKey TraceIDKey = "trace_id"Also applies to: 21-21
pkg/logger/logger.go (1)
282-284: Consider using a typed context key fortxid.Line 282 uses the string
"txid"directly as a context key, which is inconsistent with the typed key pattern established inpkg/logger/context.go. For consistency and type safety, consider defining a typed key for transaction IDs similar toOperationIDKey,TraceIDKey, etc.🔄 Suggested enhancement
In
pkg/logger/context.go, add:type TransactionIDKey string const ( // ... existing constants TxIDCtxKey TransactionIDKey = "txid" )Then update the usage in
logger.go:- if txid, ok := ctx.Value("txid").(int64); ok { + if txid, ok := ctx.Value(TxIDCtxKey).(int64); ok { attrs = append(attrs, slog.Int64("tx_id", txid)) }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (31)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/errors/errors.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/otel.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/responseinfo.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/logging.go
🚧 Files skipped from review as they are similar to previous changes (11)
- cmd/hyperfleet-api/server/server.go
- pkg/db/db_session/testcontainer.go
- pkg/handlers/openapi.go
- pkg/logger/logger_test.go
- cmd/hyperfleet-api/main.go
- pkg/telemetry/otel.go
- cmd/hyperfleet-api/server/healthcheck_server.go
- pkg/auth/authz_middleware_mock.go
- cmd/hyperfleet-api/servecmd/cmd.go
- cmd/hyperfleet-api/server/api_server.go
- pkg/middleware/otel.go
🧰 Additional context used
📓 Path-based instructions (2)
test/integration/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use Testcontainers to spin up isolated PostgreSQL instances for integration tests
Files:
test/integration/integration_test.go
pkg/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Files:
pkg/api/error.gopkg/db/migrations.gopkg/logger/ocm_bridge.gopkg/logger/context.gopkg/logger/logger.gopkg/db/db_session/test.gopkg/errors/errors.go
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/**/*.go : Use structured logging via pkg/logger/logger.go with Extra() method for adding context fields
Applied to files:
cmd/hyperfleet-api/environments/framework.gotest/helper.gotest/integration/integration_test.gopkg/api/error.godocs/logging.mdpkg/db/migrations.gopkg/logger/ocm_bridge.gocmd/hyperfleet-api/migrate/cmd.gopkg/logger/context.gopkg/logger/logger.gopkg/db/db_session/test.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Use environment-based configuration via OCM_ENV to select development, unit_testing, integration_testing, or production settings
Applied to files:
cmd/hyperfleet-api/environments/framework.gotest/helper.gotest/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{dao,services}/**/*.go : Use context.Context as the first parameter in all DAO and service method signatures
Applied to files:
cmd/hyperfleet-api/environments/framework.gotest/integration/integration_test.gopkg/api/error.gopkg/db/migrations.gocmd/hyperfleet-api/migrate/cmd.gopkg/logger/context.gopkg/db/db_session/test.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{handlers,services}/**/*.go : Retrieve database sessions from context via db.NewContext() rather than creating new GORM connections
Applied to files:
cmd/hyperfleet-api/environments/framework.gotest/integration/integration_test.gopkg/api/error.gopkg/db/migrations.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/test.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/server/**/*.go : Extract user account ID and username from JWT claims for audit logging and authorization checks
Applied to files:
test/helper.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to test/factories/**/*.go : Provide test data factories in test/factories/ for consistent test fixture creation
Applied to files:
test/helper.gotest/integration/integration_test.gopkg/db/db_session/test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Use FIPS-compliant crypto with CGO_ENABLED=1 and GOEXPERIMENT=boringcrypto build flags
Applied to files:
test/helper.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/api/openapi_embed.go : Embed OpenAPI specification at compile time using //go:embed directive
Applied to files:
test/helper.gotest/integration/integration_test.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/api/openapi/model_*.go : Support JSON request/response serialization with proper struct tags on generated OpenAPI models
Applied to files:
test/helper.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to test/integration/**/*.go : Use Testcontainers to spin up isolated PostgreSQL instances for integration tests
Applied to files:
test/integration/integration_test.gopkg/db/db_session/test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Automatically convert errors to OpenAPI error responses using errors.SendError() in HTTP handlers
Applied to files:
pkg/api/error.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Return ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields in error handling
Applied to files:
pkg/api/error.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/transaction_middleware.go,handlers}/**/*.go : Store request operation IDs in context for tracing and debugging purposes in error logs
Applied to files:
pkg/api/error.godocs/logging.mdcmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/db/migrations.gocmd/hyperfleet-api/migrate/cmd.gopkg/logger/context.gopkg/db/db_session/test.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Set HTTP status codes correctly: 201 Created for POST, 200 OK for GET, 204 No Content for DELETE operations
Applied to files:
pkg/api/error.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Write HTTP responses using json.NewEncoder(w) for consistency with request parsing
Applied to files:
pkg/api/error.gocmd/hyperfleet-api/server/logging/request_logging_middleware.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/handlers/**/*.go : Implement handlers as methods on handler structs that accept (w http.ResponseWriter, r *http.Request) parameters
Applied to files:
pkg/api/error.gocmd/hyperfleet-api/server/logging/request_logging_middleware.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to cmd/hyperfleet/server/**/*.go : Validate JWT tokens from Red Hat SSO in middleware before allowing requests to handlers
Applied to files:
cmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/errors/errors.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/transaction_middleware.go : Store database sessions in HTTP request context via middleware at request entry point
Applied to files:
cmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/migrations/**/*.go : Use GORM AutoMigrate for schema management instead of manual SQL scripts
Applied to files:
pkg/db/migrations.gocmd/hyperfleet-api/migrate/cmd.gogo.modpkg/db/db_session/test.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : Use polymorphic status tables with owner_type and owner_id columns to support multiple resource types
Applied to files:
pkg/db/migrations.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/db/migrations/**/*.go : Store cluster and node pool specifications as JSONB columns to allow flexible cloud provider configurations
Applied to files:
pkg/db/migrations.gocmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2025-12-12T11:04:29.971Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T11:04:29.971Z
Learning: Applies to pkg/{db/migrations,dao}/adapter_status.go : Store adapter statuses with observed_generation field to track which resource generation each adapter has processed
Applied to files:
pkg/db/migrations.go
🧬 Code graph analysis (7)
test/helper.go (1)
pkg/logger/logger.go (5)
Error(232-234)Info(224-226)Debug(220-222)LogConfig(26-33)InitGlobalLogger(166-170)
test/integration/integration_test.go (1)
pkg/logger/logger.go (2)
Infof(240-242)Warn(228-230)
pkg/api/error.go (1)
pkg/logger/logger.go (1)
Error(232-234)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (3)
pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/logger/logger.go (1)
Info(224-226)
pkg/logger/logger.go (2)
pkg/logger/context.go (6)
TraceIDCtxKey(22-22)SpanIDCtxKey(23-23)OpIDKey(20-20)ClusterIDCtxKey(24-24)ResourceTypeCtxKey(25-25)ResourceIDCtxKey(26-26)pkg/errors/errors.go (1)
New(112-132)
pkg/db/db_session/test.go (1)
pkg/logger/logger.go (1)
Errorf(248-250)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(248-250)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
🪛 markdownlint-cli2 (0.18.1)
docs/logging.md
29-29: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
181-181: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (21)
cmd/hyperfleet-api/migrate/cmd.go (2)
6-6: LGTM: Import changes support the glog-to-slog migration.The new imports (
os,db_session,logger) correctly support the refactored error handling and database initialization pattern.Also applies to: 12-13
33-38: The logger is properly initialized. Themain()function callsinitDefaultLogger()before creating or executing any commands, which invokeslogger.InitGlobalLogger(). By the timerunMigrate()executes, the logger is guaranteed to be initialized with a global logger instance.cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
58-68: LGTM! Clean responseWriter wrapper.The responseWriter wrapper correctly captures the status code with proper delegation to the underlying ResponseWriter.
pkg/logger/ocm_bridge.go (2)
26-49: LGTM! Clean delegation to slog logger.The logging methods correctly delegate to
GetLogger()with proper context propagation and formatted messages. The Fatal method appropriately prefixes with "FATAL: " and exits.
52-69: The proposed fix violates the OCM SDK's Logger interface contract.The
Enabledmethods in the OCM SDK's Logger interface are defined without context parameters:DebugEnabled() bool,InfoEnabled() bool, etc. The current implementation correctly adheres to this interface. Adding context parameters as suggested would break the interface implementation.The underlying concern about using stale stored context is valid—
b.ctxcaptured at construction time may lack current request-specific values. However, this is an unavoidable constraint of the OCM SDK's Logger interface design. The stored context approach is the only way to implement these methods given the interface signature.Consider documenting this limitation in a comment to clarify the design tradeoff: that while other logging methods receive fresh context, the
Enabledpredicates must use the construction-time context due to interface constraints.Likely an incorrect or invalid review comment.
README.md (1)
158-158: LGTM! Documentation link added correctly.The logging documentation link is properly formatted and placed in the Core Documentation section with an accurate description.
go.mod (2)
32-36: Verify OpenTelemetry versions are pre-release or unreleased.The PR specifies OpenTelemetry dependencies at v1.39.0, but the latest stable version reported is v1.38.0. Confirm whether v1.39.0 is a pre-release, unreleased, or if there is a newer stable release available. Using versions ahead of the latest stable may introduce instability.
Likely an incorrect or invalid review comment.
26-26: Verify ksuid version bump and check for breaking changes.Review the changelog for the ksuid upgrade. No formal upstream release notes were found for the v1.0.2 → v1.0.4 transition; check the commit history directly: segmentio/ksuid@v1.0.2...v1.0.4
pkg/db/db_session/test.go (2)
16-16: LGTM! Context usage is appropriate for initialization.The structured logger import and context creation align with the logging migration. Using
context.Background()in thesync.Onceinitialization block is correct since no parent context exists at this stage.Based on learnings, using structured logging via pkg/logger/logger.go with context.
Also applies to: 52-54
54-54: LGTM! Error logging correctly migrated to structured logger.The migration from glog to pkglogger.Errorf maintains error visibility while adding structured logging benefits. Context is properly passed to logging calls.
Based on learnings, using structured logging via pkg/logger/logger.go.
Also applies to: 59-59
pkg/api/error.go (1)
89-110: LGTM! Appropriate use of Background context in init.Using
context.Background()in theinit()function is correct since no request context exists during package initialization.test/helper.go (2)
544-555: LGTM! Test logger initialization is well-structured.The
initTestLoggerfunction properly configures the global logger for tests with appropriate defaults (text format, info level). This provides consistent logging behavior across the test suite.
72-74: LGTM! Context usage is appropriate for test infrastructure.Using
context.Background()throughout test setup, teardown, and server lifecycle functions is correct. Test infrastructure code doesn't have parent request contexts, so Background() is the appropriate choice.Based on learnings, using structured logging via pkg/logger/logger.go.
Also applies to: 84-86, 96-97, 142-149, 166-172, 176-179, 184-189, 194-199, 203-206, 210-211, 221-222
docs/logging.md (1)
1-509: Excellent documentation! Comprehensive logging guide.This documentation provides thorough coverage of the new structured logging system including:
- Clear architecture overview with middleware chain
- Practical examples with actual output
- Configuration options and environment variables
- Best practices and troubleshooting guidance
- OpenTelemetry integration details
- Data masking configuration
test/integration/integration_test.go (1)
4-43: LGTM! Clean migration to structured logging.The integration test has been successfully migrated from glog to the new context-aware logger. The use of structured logging with key-value pairs (line 40) aligns with the coding guidelines for
pkg/**/*.gofiles.cmd/hyperfleet-api/environments/framework.go (1)
73-80: Fatal error handling pattern is consistent.The use of
logger.Errorffollowed byos.Exit(1)for fatal errors is consistent across the file and appropriate for initialization failures that should terminate the process.pkg/logger/context.go (1)
57-63: LGTM! Idempotent operation ID generation.The
WithOpIDfunction correctly checks if an operation ID already exists before generating a new KSUID, preventing unnecessary allocations and maintaining ID stability across context propagation.pkg/logger/logger.go (4)
109-112: Skip outdated review comment.The past review comment suggesting removal of a duplicate error field on line 112 is no longer applicable. The current code correctly adds only the stack trace for error-level logs without duplicating the message field.
45-80: LGTM! Well-structured slog handler implementation.The
HyperFleetHandlercorrectly implements theslog.Handlerinterface with appropriate field renaming (timestamp, level, message) and support for both JSON and text formats. The attribute replacement logic properly handles slog's built-in keys.
142-161: LGTM! Stack trace filtering is appropriate.The stack trace capture correctly filters out
runtime.*andtesting.*frames to focus on application code, making error logs more actionable. The 15-frame limit prevents excessive log size while capturing sufficient context.
166-170: Verify the impact of callingslog.SetDefault.Line 169 sets the global default logger, which affects all slog usage across the application and any third-party libraries using
slog.Default(). This is intentional for this migration but ensure all existing code paths have been tested with this change.Based on learnings, structured logging via
pkg/logger/logger.gois the established pattern for this codebase.
cmd/hyperfleet-api/server/logging/request_logging_middleware.go
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cmd/hyperfleet-api/servecmd/cmd.go (1)
76-92: Implement signal handling for graceful shutdown of the three servers.The servers are started in separate goroutines and the main goroutine blocks indefinitely with
select{}, but there is no signal handling (SIGTERM/SIGINT). While each server has aStop()method that gracefully shuts down the HTTP server, these methods are never invoked. This causes the application to be forcefully terminated without proper cleanup:
- In-flight requests are abruptly terminated
- Database connections and telemetry resources may not be properly released
- Kubernetes termination grace period will timeout, forcing a hard kill
Implement signal handling (e.g., using
signal.Notifyforsyscall.SIGTERMandsyscall.SIGINT) to callStop()on all three servers and await their completion before exiting.
🤖 Fix all issues with AI agents
In @pkg/logger/logger.go:
- Around line 163-170: InitGlobalLogger currently writes the package-level
globalLogger without synchronization causing a race if called concurrently;
protect initialization by adding a package-level sync.Once (e.g., var initOnce
sync.Once) and wrap the existing setup (NewHyperFleetHandler(cfg), globalLogger
= slog.New(handler), slog.SetDefault(globalLogger)) inside initOnce.Do so the
logger is created exactly once; update InitGlobalLogger to call initOnce.Do with
a closure performing the existing logic (or alternatively document that
InitGlobalLogger must only be invoked during single-threaded startup).
🧹 Nitpick comments (8)
pkg/db/db_session/testcontainer.go (1)
57-58: Prefer structured logging over printf-style formatting.Multiple error logging statements use printf-style formatting (
Errorf,Infof) rather than structured logging. Line 171 demonstrates the preferred structured approach with key-value pairs. For consistency and better log analysis, consider using structured logging throughout.♻️ Example refactors for structured logging
if err != nil { - pkglogger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err) + pkglogger.Error(ctx, "Failed to start PostgreSQL testcontainer", "error", err) os.Exit(1) }if err != nil { - pkglogger.Errorf(ctx, "Failed to get connection string from testcontainer: %s", err) + pkglogger.Error(ctx, "Failed to get connection string from testcontainer", "error", err) os.Exit(1) }-pkglogger.Infof(ctx, "PostgreSQL testcontainer started at: %s", connStr) +pkglogger.Info(ctx, "PostgreSQL testcontainer started", "connection_string", connStr)Similar patterns can be applied to lines 75-76, 99-100, 106-107, and 181.
Based on coding guidelines emphasizing structured logging.
Also applies to: 66-67, 75-76, 99-100, 106-107, 181-181
pkg/errors/errors.go (1)
117-118: Prefer structured logging with error code as a field.The current implementation uses printf-style formatting. For better log analysis and consistency with the structured logging approach, consider capturing the error code as a structured field.
♻️ Proposed refactor
if !exists { ctx := context.Background() - logger.Errorf(ctx, "Undefined error code used: %d", code) + logger.Error(ctx, "Undefined error code used", "code", code) err = &ServiceError{ Code: ErrorGeneral, Reason: "Unspecified error", HttpCode: 500, } }Based on coding guidelines emphasizing structured logging.
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
58-68: Consider implementing additionalhttp.ResponseWriteroptional interfaces.The
responseWriterwrapper only implementshttp.ResponseWriter. If downstream handlers usehttp.Hijacker(WebSockets),http.Flusher(SSE), orhttp.Pusher(HTTP/2 push), they will fail type assertions.♻️ Optional: Interface delegation pattern
// Unwrap returns the underlying ResponseWriter for interface upgrades func (rw *responseWriter) Unwrap() http.ResponseWriter { return rw.ResponseWriter }Go 1.20+
http.ResponseControllerusesUnwrap()to access underlying interfaces.cmd/hyperfleet-api/main.go (1)
54-66: Consider injecting version at build time.The hardcoded
Version: "unknown"works, but consider using linker flags (-ldflags) to inject the actual version at build time for better observability.// Inject at build time with: go build -ldflags "-X main.version=1.2.3" var version = "unknown" func initDefaultLogger() { cfg := &logger.LogConfig{ // ... Version: version, // ... } }cmd/hyperfleet-api/environments/framework.go (1)
176-184: Minor: Inconsistent logging style with other methods in this file.This method uses structured logging (
logger.Errorwith key-value pairs) while other methods use formatted logging (logger.Errorf). Consider aligning for consistency.♻️ Option 1: Use Errorf for consistency
func setConfigDefaults(flags *pflag.FlagSet, defaults map[string]string) error { ctx := context.Background() for name, value := range defaults { if err := flags.Set(name, value); err != nil { - logger.Error(ctx, "Error setting flag", "flag", name, "error", err) + logger.Errorf(ctx, "Error setting flag %s: %s", name, err) return err } } return nil }Alternatively, migrate all methods to structured logging style for better log aggregation.
cmd/hyperfleet-api/servecmd/cmd.go (2)
57-61: Consider adding a timeout to the OpenTelemetry shutdown context.The deferred shutdown uses
context.Background(), which could block indefinitely. Consider using a timeout context to ensure graceful shutdown completes within a reasonable timeframe.♻️ Proposed enhancement
} else { defer func() { - if err := telemetry.Shutdown(context.Background(), tp); err != nil { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := telemetry.Shutdown(shutdownCtx, tp); err != nil { logger.Error(ctx, "Failed to shutdown OpenTelemetry", "error", err) } }()
121-122: Log hostname retrieval errors for better observability.The error from
os.Hostname()is silently ignored. While falling back to an empty hostname is acceptable, logging the error would aid debugging in environments where hostname resolution fails.♻️ Proposed enhancement
// Get hostname - hostname, _ := os.Hostname() + hostname, err := os.Hostname() + if err != nil { + logger.Warn(ctx, "Failed to get hostname", "error", err) + hostname = "" + }pkg/logger/logger.go (1)
282-284: Use a typed constant for the "txid" context key.The hardcoded string
"txid"should be defined as a typed constant (similar toTraceIDCtxKey,SpanIDCtxKey) for type safety and consistency with the rest of the codebase.♻️ Proposed refactor
In
pkg/logger/context.go, add:type ResourceTypeKey string type ResourceIDKey string +type TransactionIDKey string const ( OpIDKey OperationIDKey = "opID" OpIDHeader OperationIDHeaderKey = "X-Operation-ID" TraceIDCtxKey TraceIDKey = "trace_id" SpanIDCtxKey SpanIDKey = "span_id" ClusterIDCtxKey ClusterIDKey = "cluster_id" ResourceTypeCtxKey ResourceTypeKey = "resource_type" ResourceIDCtxKey ResourceIDKey = "resource_id" + TxIDCtxKey TransactionIDKey = "txid" )Then update the usage in
logger.go:- if txid, ok := ctx.Value("txid").(int64); ok { + if txid, ok := ctx.Value(TxIDCtxKey).(int64); ok { attrs = append(attrs, slog.Int64("tx_id", txid)) }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (32)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/errors/errors.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/otel.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/logging.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
🚧 Files skipped from review as they are similar to previous changes (6)
- pkg/auth/authz_middleware_mock.go
- README.md
- pkg/api/error.go
- pkg/db/db_session/test.go
- cmd/hyperfleet-api/migrate/cmd.go
- docs/logging.md
🧰 Additional context used
📓 Path-based instructions (8)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
test/helper.gopkg/errors/errors.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/handlers/openapi.gopkg/telemetry/otel.gopkg/logger/logger_test.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/middleware/otel.gopkg/logger/ocm_bridge.gopkg/db/migrations.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gopkg/logger/context.gopkg/logger/logger.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/openapi.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/openapi.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/handlers/openapi.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/handlers/openapi.gopkg/db/migrations.gopkg/db/db_session/testcontainer.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/migrations.gopkg/db/db_session/testcontainer.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/migrations.gopkg/db/db_session/testcontainer.go
test/integration/**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Files:
test/integration/integration_test.go
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
test/helper.gopkg/errors/errors.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/handlers/openapi.gopkg/telemetry/otel.gopkg/logger/logger_test.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/main.gopkg/logger/ocm_bridge.gopkg/db/migrations.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gopkg/logger/context.gopkg/logger/logger.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
test/helper.gopkg/errors/errors.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gotest/integration/integration_test.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
test/helper.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
test/helper.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/main.gopkg/db/migrations.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
test/helper.gopkg/errors/errors.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/main.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
test/helper.gopkg/db/migrations.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
test/helper.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
test/helper.gopkg/errors/errors.gopkg/handlers/openapi.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
test/helper.gocmd/hyperfleet-api/environments/framework.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
pkg/errors/errors.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gopkg/middleware/otel.gopkg/db/migrations.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gopkg/logger/context.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
pkg/errors/errors.gocmd/hyperfleet-api/server/server.gopkg/logger/context.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
pkg/errors/errors.gocmd/hyperfleet-api/server/server.gopkg/db/migrations.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
pkg/errors/errors.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/servecmd/cmd.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/handlers/openapi.gopkg/db/migrations.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
pkg/telemetry/otel.gopkg/db/migrations.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Applied to files:
cmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
pkg/db/migrations.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
pkg/db/migrations.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Applied to files:
test/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
test/integration/integration_test.gopkg/db/db_session/testcontainer.go
🧬 Code graph analysis (17)
test/helper.go (1)
pkg/logger/logger.go (6)
Error(232-234)Info(224-226)Debug(220-222)Warn(228-230)LogConfig(26-33)InitGlobalLogger(166-170)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(248-250)
cmd/hyperfleet-api/server/healthcheck_server.go (1)
pkg/logger/logger.go (2)
Infof(240-242)Info(224-226)
pkg/handlers/openapi.go (1)
pkg/logger/logger.go (1)
Info(224-226)
cmd/hyperfleet-api/server/api_server.go (5)
pkg/logger/ocm_bridge.go (1)
NewOCMLoggerBridge(19-23)pkg/logger/logger.go (2)
Info(224-226)Error(232-234)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)cmd/hyperfleet-api/environments/types.go (1)
Database(36-38)pkg/db/session.go (1)
SessionFactory(12-20)
cmd/hyperfleet-api/server/server.go (1)
pkg/logger/logger.go (1)
Error(232-234)
cmd/hyperfleet-api/servecmd/cmd.go (3)
pkg/logger/logger.go (6)
ParseLogLevel(181-194)ParseLogFormat(197-206)FormatJSON(22-22)ParseLogOutput(209-218)LogConfig(26-33)InitGlobalLogger(166-170)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/telemetry/otel.go (2)
InitTraceProvider(16-57)Shutdown(60-65)
cmd/hyperfleet-api/server/routes.go (3)
pkg/middleware/otel.go (1)
OTelMiddleware(18-50)pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
RequestLoggingMiddleware(14-56)
cmd/hyperfleet-api/main.go (1)
pkg/logger/logger.go (4)
Error(232-234)LogConfig(26-33)FormatJSON(22-22)InitGlobalLogger(166-170)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (2)
pkg/middleware/masking.go (1)
MaskingMiddleware(13-17)pkg/logger/logger.go (1)
Info(224-226)
pkg/middleware/otel.go (1)
pkg/logger/context.go (2)
WithTraceID(30-32)WithSpanID(35-37)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(220-222)GetLogger(173-178)Info(224-226)Warn(228-230)Error(232-234)
pkg/db/migrations.go (2)
pkg/errors/errors.go (1)
New(112-132)pkg/logger/logger.go (2)
NewOCMLogger(274-297)Error(232-234)
test/integration/integration_test.go (1)
pkg/logger/logger.go (2)
Infof(240-242)Warn(228-230)
pkg/db/db_session/testcontainer.go (2)
pkg/logger/logger.go (4)
Info(224-226)Errorf(248-250)Infof(240-242)Error(232-234)pkg/db/migrations.go (1)
Migrate(17-24)
pkg/logger/context.go (1)
pkg/errors/errors.go (1)
New(112-132)
pkg/logger/logger.go (1)
pkg/logger/context.go (6)
TraceIDCtxKey(22-22)SpanIDCtxKey(23-23)OpIDKey(20-20)ClusterIDCtxKey(24-24)ResourceTypeCtxKey(25-25)ResourceIDCtxKey(26-26)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
🔇 Additional comments (30)
pkg/db/migrations.go (1)
30-38: LGTM! Structured logging implementation is correct.The migration error handling now correctly uses
logger.NewOCMLogger(ctx)with theExtra()method for structured logging, properly capturing the migration ID and error context. This aligns with the coding guidelines and addresses the previous review feedback.pkg/handlers/openapi.go (1)
25-25: LGTM! Context-aware logging for initialization.The logging statements appropriately use context-aware logging for initialization messages. The simple
logger.Info()calls are suitable for these straightforward informational messages without additional structured fields.Also applies to: 43-43, 53-53
cmd/hyperfleet-api/server/server.go (1)
28-33: LGTM! Proper structured logging implementation.The error handling correctly uses context-aware structured logging with key-value pairs (
"error", err), which aligns with the coding guidelines and enables better log analysis.cmd/hyperfleet-api/server/healthcheck_server.go (1)
44-62: LGTM! Logger migration completed correctly.The migration from glog to the structured logger is correct. Using
context.Background()with the top-levellogger.Infof/Infofunctions is appropriate for server startup logging, where request-scoped context is not available.test/helper.go (2)
544-555: LGTM! Test logger initialization is well-structured.The test logger configuration is appropriate for testing:
- Text format for readability
- Reasonable defaults (component, version, hostname)
- Uses the global logger initialization mechanism
72-74: LGTM! Consistent error handling pattern.The replacement of
log.Fataland glog fatal calls withlogger.Error(ctx, ...)followed byos.Exit(1)is correct and provides better control over error logging and exit behavior.Also applies to: 84-86, 96-98
cmd/hyperfleet-api/server/routes.go (1)
71-81: LGTM! Middleware initialization follows best practices.The changes correctly implement:
- Conditional OpenTelemetry middleware based on configuration
- Single masking middleware instance reused across requests (avoiding unnecessary allocations)
- Proper middleware ordering: OperationID → OTel → RequestLogging ensures context is enriched before logging
test/integration/integration_test.go (1)
17-43: LGTM! Excellent use of structured logging.The migration to context-aware logging is correct, and line 40 demonstrates the proper use of structured logging with key-value pairs:
logger.Warn(ctx, "Schema file not found, skipping OPENAPI_SCHEMA_PATH setup", "schema_path", schemaPath, "error", err)This pattern provides better log aggregation and filtering capabilities.
pkg/middleware/otel.go (1)
18-50: LGTM! The middleware correctly addresses the span ordering issue.The implementation properly wraps
enrichedHandlerwithotelhttp.NewHandler, ensuring the span is created before trace/span IDs are extracted. The validity check at line 25 correctly handles cases where no parent trace context exists.cmd/hyperfleet-api/server/api_server.go (2)
39-56: LGTM! Authentication logger bridge correctly wired.The
NewOCMLoggerBridgeis properly instantiated with a background context for the authentication handler initialization. This aligns with the project's structured logging approach per the coding guidelines.
137-152: LGTM! Server startup error handling correctly migrated.The replacement of
glog.Fatalwithlogger.Errorfollowed byos.Exit(1)provides equivalent behavior while integrating with the new structured logging system. The database close error is also properly logged.cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
14-56: Good refactor! Masker is now properly reused across requests.The signature change to accept a pre-constructed
*middleware.MaskingMiddlewareaddresses the previous concern about per-request instantiation overhead.cmd/hyperfleet-api/main.go (1)
26-34: LGTM! Logger initialization before first log is correct.Initializing the logger before any logging ensures consistent structured output from the start. The empty flag parsing for cobra compatibility is a known pattern when mixing
flagwithcobra.cmd/hyperfleet-api/environments/framework.go (1)
67-120: LGTM! Environment initialization correctly migrated to structured logging.The migration from
glog.Fataltologger.Errorffollowed byos.Exit(1)preserves the fail-fast behavior while integrating with the new logging system.pkg/logger/logger_test.go (3)
125-195: Consider test isolation for global logger state.Each test calls
InitGlobalLogger(cfg)which modifies a package-level global. If tests run in parallel (t.Parallel()), they could interfere with each other. Currently tests don't uset.Parallel(), so this is safe, but worth noting for future maintenance.
400-417: Good defensive test for uninitialized logger fallback.The test correctly saves and restores the global logger state, and verifies that
GetLogger()falls back toslog.Default()when uninitialized.
308-360: Good coverage of stack trace behavior.The test verifies that stack traces are captured for error level but not for info level, which aligns with the expected behavior for production debugging.
pkg/logger/ocm_bridge.go (3)
26-43: Context parameter is used correctly in logging methods.Looking more closely, the logging methods correctly pass the
ctxparameter received from the SDK toGetLogger().*Context()methods (e.g.,GetLogger().DebugContext(ctx, ...)). This ensures request-scoped context values are properly propagated.
51-68: The*Enabled()methods use stored context, not call-site context.The
DebugEnabled(),InfoEnabled(), etc. methods useb.ctx(the context from construction time) rather than a call-site context. This is acceptable since these methods don't take a context parameter per thesdk.Loggerinterface, but be aware that log-level decisions are based on the construction-time context.
45-49:os.Exit(1)is correct — no changes needed.The OCM SDK Logger interface expects
Fatalto log the error and immediately exit the process (not panic). The current implementation correctly callsos.Exit(1)after logging. The use ofErrorContextwith a"FATAL: "prefix is a pragmatic workaround, since the standard libraryslogdoes not provide a dedicated FATAL log level.pkg/logger/context.go (2)
9-27: Excellent use of type-safe context keys.The use of distinct types for context keys (OperationIDKey, TraceIDKey, SpanIDKey, etc.) is a Go best practice that prevents context key collisions. This ensures type safety and makes the codebase more maintainable.
54-63: KSUID-based operation ID generation looks correct.The
WithOpIDfunction properly checks for existing operation IDs before generating a new one, preventing unnecessary allocations. The KSUID provides a sortable, globally unique identifier suitable for distributed tracing.pkg/logger/logger.go (6)
15-33: Well-structured logging configuration.The
LogFormatenum andLogConfigstruct provide a clean abstraction for logger configuration with appropriate fields for component, version, and hostname. This aligns well with structured logging best practices.
44-80: Handler implementation follows slog patterns correctly.The
NewHyperFleetHandlerproperly wraps slog's built-in handlers (JSON/Text) with custom attribute replacement. The ReplaceAttr function correctly standardizes field names (timestamp, level, message) across output formats.
90-107: Context field extraction is comprehensive and correct.The handler properly extracts correlation fields from context (trace_id, span_id, request_id, cluster_id, resource_type, resource_id) and adds them to log records. The type assertions with the
okpattern safely handle missing values.Based on learnings, structured logging with context-aware fields including operation ID, account ID, and transaction ID is required, which this implementation provides.
142-161: Stack trace filtering is appropriate.The
captureStackTracefunction correctly filters out runtime and testing frames while limiting depth to 15 frames, providing useful debugging information without noise.
273-297: OCMLogger backward compatibility maintained correctly.The
NewOCMLoggerfunction properly extracts account_id and tx_id from context and creates a logger with those attributes. This maintains backward compatibility while leveraging the new slog infrastructure.Based on learnings, structured logging via
logger.NewOCMLogger(ctx)with context-aware log fields is required, which this implementation provides.
350-354: Fatal method behavior is appropriate.The
Fatalmethod logs an error and callsos.Exit(1), which is the expected behavior for fatal errors. The "FATAL: " prefix clearly distinguishes fatal errors in logs.go.mod (2)
72-72: Intentional transition of glog from direct to indirect dependency is confirmed.No direct imports of
github.com/golang/glogremain in the codebase. The migration tolog/sloghas been successfully completed across all relevant files (logger.go, logger_test.go, ocm_bridge.go, main.go, servecmd/cmd.go, and test helper). The glog package remains as an indirect dependency, which is expected if it's pulled in by other transitive dependencies.
32-36: The OpenTelemetry dependencies at versions v1.39.0 and v0.49.0 are compatible with the project's Go version 1.24.9 and have no known security vulnerabilities. No action is required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
pkg/db/db_session/testcontainer.go (3)
41-111: Replace os.Exit calls with error returns in test infrastructure.The Init method calls
os.Exit(1)on multiple error paths (lines 58, 67, 76, 100, 107), which terminates the entire test process. This prevents:
- Other tests from running
- Test frameworks from reporting failures properly
- Cleanup code from executing
- Proper debugging and error inspection
Refactor Init to return an error, and update NewTestcontainerFactory to handle it appropriately.
🔧 Proposed refactor to return errors instead of calling os.Exit
-func (f *Testcontainer) Init(config *config.DatabaseConfig) { +func (f *Testcontainer) Init(config *config.DatabaseConfig) error { ctx := context.Background() pkglogger.Info(ctx, "Starting PostgreSQL testcontainer...") // Create PostgreSQL container container, err := postgres.Run(ctx, "postgres:14.2", postgres.WithDatabase(config.Name), postgres.WithUsername(config.Username), postgres.WithPassword(config.Password), testcontainers.WithWaitStrategy( wait.ForListeningPort("5432/tcp"). WithStartupTimeout(60*time.Second)), ) if err != nil { pkglogger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err) - os.Exit(1) + return fmt.Errorf("failed to start PostgreSQL testcontainer: %w", err) } f.container = container // Get connection string from container connStr, err := container.ConnectionString(ctx, "sslmode=disable") if err != nil { pkglogger.Errorf(ctx, "Failed to get connection string from testcontainer: %s", err) - os.Exit(1) + return fmt.Errorf("failed to get connection string: %w", err) } pkglogger.Infof(ctx, "PostgreSQL testcontainer started at: %s", connStr) // Open SQL connection f.sqlDB, err = sql.Open("postgres", connStr) if err != nil { pkglogger.Errorf(ctx, "Failed to connect to testcontainer database: %s", err) - os.Exit(1) + return fmt.Errorf("failed to connect to database: %w", err) } // ... rest of method f.g2, err = gorm.Open(gormpostgres.New(gormpostgres.Config{ Conn: f.sqlDB, PreferSimpleProtocol: true, }), conf) if err != nil { pkglogger.Errorf(ctx, "Failed to connect GORM to testcontainer database: %s", err) - os.Exit(1) + return fmt.Errorf("failed to connect GORM: %w", err) } // Run migrations pkglogger.Info(ctx, "Running database migrations on testcontainer...") if err := db.Migrate(f.g2); err != nil { pkglogger.Errorf(ctx, "Failed to run migrations on testcontainer: %s", err) - os.Exit(1) + return fmt.Errorf("failed to run migrations: %w", err) } pkglogger.Info(ctx, "Testcontainer database initialized successfully") + return nil }Then update the constructor:
func NewTestcontainerFactory(config *config.DatabaseConfig) *Testcontainer { conn := &Testcontainer{ config: config, } - conn.Init(config) + if err := conn.Init(config); err != nil { + // Let the caller handle the error appropriately + panic(fmt.Sprintf("failed to initialize testcontainer: %v", err)) + } return conn }Note: Using panic in a constructor is still not ideal, but it's significantly better than os.Exit. Consider refactoring NewTestcontainerFactory to also return an error for proper error handling.
44-110: Use structured logging consistently with logger.NewOCMLogger(ctx).The code mixes printf-style logging (e.g.,
pkglogger.Infof,pkglogger.Errorf) with structured logging (line 171 uses key-value pairs). According to coding guidelines, structured logging should be used vialogger.NewOCMLogger(ctx)with context-aware log fields.While test infrastructure may not need operation/account IDs, using structured logging consistently improves log parsing and observability.
♻️ Proposed refactor to use structured logging consistently
func (f *Testcontainer) Init(config *config.DatabaseConfig) { ctx := context.Background() + log := pkglogger.NewOCMLogger(ctx) - pkglogger.Info(ctx, "Starting PostgreSQL testcontainer...") + log.Info("Starting PostgreSQL testcontainer") // Create PostgreSQL container container, err := postgres.Run(ctx, // ... config ... ) if err != nil { - pkglogger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err) + log.Error("Failed to start PostgreSQL testcontainer", "error", err) os.Exit(1) } // ... rest of method similarly updated - pkglogger.Infof(ctx, "PostgreSQL testcontainer started at: %s", connStr) + log.Info("PostgreSQL testcontainer started", "connection_string", connStr)Apply similar changes throughout the file for consistency.
Based on coding guidelines.
155-175: Consider returning errors from ResetDB.The ResetDB method logs truncation errors (line 171) but doesn't return them, which could leave the database in an inconsistent state. Callers have no way to detect if the reset succeeded, potentially leading to flaky tests running with stale data.
♻️ Proposed refactor to return errors
-func (f *Testcontainer) ResetDB() { +func (f *Testcontainer) ResetDB() error { // For testcontainers, we can just truncate all tables ctx := context.Background() g2 := f.New(ctx) // Truncate all business tables in the correct order (respecting FK constraints) // Using CASCADE to handle foreign key constraints automatically tables := []string{ "adapter_statuses", // Polymorphic table, no FK constraints "node_pools", // Has FK to clusters "clusters", // Referenced by node_pools "events", // Independent table } for _, table := range tables { if g2.Migrator().HasTable(table) { if err := g2.Exec(fmt.Sprintf("TRUNCATE TABLE %s CASCADE", table)).Error; err != nil { pkglogger.Error(ctx, "Error truncating table", "table", table, "error", err) + return fmt.Errorf("failed to truncate table %s: %w", table, err) } } } + return nil }cmd/hyperfleet-api/environments/framework.go (1)
67-120: Inconsistent error handling: some paths return error, others callos.Exit(1).The
Initializemethod has mixed error handling patterns:
- Lines 94-97: Returns error from
LoadClients- Lines 109-112: Returns error from
Seed- Other failures: Call
logger.Errorffollowed byos.Exit(1)This inconsistency makes error handling unpredictable for callers. Consider either consistently returning errors (preferred for testability) or documenting why certain failures are unrecoverable.
♻️ Suggested refactor for consistent error handling
func (e *Env) Initialize() error { ctx := context.Background() logger.Infof(ctx, "Initializing %s environment", e.Name) envImpl, found := environments[e.Name] if !found { - logger.Errorf(ctx, "Unknown runtime environment: %s", e.Name) - os.Exit(1) + return fmt.Errorf("unknown runtime environment: %s", e.Name) } if err := envImpl.OverrideConfig(e.Config); err != nil { - logger.Errorf(ctx, "Failed to configure ApplicationConfig: %s", err) - os.Exit(1) + return fmt.Errorf("failed to configure ApplicationConfig: %w", err) } // ... apply similar pattern to other error paths }Then let the caller (e.g.,
runServe) decide whether to log and exit.cmd/hyperfleet-api/servecmd/cmd.go (1)
77-92: No graceful shutdown or error propagation from server goroutines.The three servers are started in goroutines with no mechanism to:
- Detect if a server fails to start
- Gracefully shut down on signals (SIGTERM/SIGINT)
- Coordinate shutdown of all servers
The
select {}blocks forever, making it impossible to cleanly terminate the process.♻️ Suggested pattern for graceful shutdown
// Handle shutdown signals sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) errChan := make(chan error, 3) go func() { apiserver := server.NewAPIServer() if err := apiserver.Start(); err != nil { errChan <- fmt.Errorf("API server: %w", err) } }() // ... similar for other servers select { case sig := <-sigChan: logger.Info(ctx, "Received signal, shutting down", "signal", sig) // Trigger graceful shutdown of servers case err := <-errChan: logger.Error(ctx, "Server failed", "error", err) os.Exit(1) }
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/servecmd/cmd.go:
- Around line 95-136: initLogger() never updates the active logger because
InitGlobalLogger uses sync.Once and initDefaultLogger() ran earlier; add a
reconfiguration path by implementing a ReconfigureGlobalLogger(cfg
*logger.LogConfig) in the logger package that creates a new handler
(NewHyperFleetHandler or equivalent), constructs a new slog.Logger, sets
slog.SetDefault(newLogger) and replaces the package global, then call
logger.ReconfigureGlobalLogger(logConfig) from initLogger() instead of
InitGlobalLogger so environment config takes effect without removing the
existing InitGlobalLogger usage.
In @pkg/logger/logger.go:
- Around line 55-57: The code handling the attribute with key slog.LevelKey uses
an unchecked type assertion a.Value.Any().(slog.Level) which can panic; update
the block that checks slog.LevelKey (around the attr handling in
pkg/logger/logger.go) to perform a safe type assertion (e.g., use the "val, ok
:= a.Value.Any().(slog.Level)" pattern or a type switch) and handle the non-ok
case by falling back to a safe string representation (e.g.,
fmt.Sprint(a.Value.Any()) or a default level string) so the function returns a
slog.Attr with a non-panicking, lowercased level string in all cases.
In @pkg/telemetry/otel.go:
- Line 10: Update the semconv import to the newer module version: replace the
current import alias semconv referencing
"go.opentelemetry.io/otel/semconv/v1.11.0" with the compatible
"go.opentelemetry.io/otel/semconv/v1.37.0" so the package used by the code
(semconv) matches OTEL SDK v1.39.0; locate the import statement that defines
semconv and update its version string accordingly and then run go mod tidy to
refresh dependencies.
🧹 Nitpick comments (5)
pkg/db/db_session/testcontainer.go (1)
177-186: Consider returning an error or cleanup function from NewListener.The method silently fails if it cannot obtain a connection string (line 181-182). While logging and returning early is acceptable for test infrastructure, returning an error would allow callers to handle failures explicitly.
Alternatively, consider returning a cleanup function (like
io.Closer) to allow callers to manage listener lifecycle.♻️ Proposed refactor options
Option 1: Return error
-func (f *Testcontainer) NewListener(ctx context.Context, channel string, callback func(id string)) { +func (f *Testcontainer) NewListener(ctx context.Context, channel string, callback func(id string)) error { // Get the connection string for the listener connStr, err := f.container.ConnectionString(ctx, "sslmode=disable") if err != nil { pkglogger.Errorf(ctx, "Failed to get connection string for listener: %s", err) - return + return fmt.Errorf("failed to get connection string for listener: %w", err) } newListener(ctx, connStr, channel, callback) + return nil }Option 2: Return cleanup function
-func (f *Testcontainer) NewListener(ctx context.Context, channel string, callback func(id string)) { +func (f *Testcontainer) NewListener(ctx context.Context, channel string, callback func(id string)) (func() error, error) { connStr, err := f.container.ConnectionString(ctx, "sslmode=disable") if err != nil { pkglogger.Errorf(ctx, "Failed to get connection string for listener: %s", err) - return + return nil, fmt.Errorf("failed to get connection string for listener: %w", err) } - newListener(ctx, connStr, channel, callback) + cleanup := newListener(ctx, connStr, channel, callback) + return cleanup, nil }Note: Option 2 assumes
newListenercan be refactored to return a cleanup function.pkg/logger/context.go (1)
60-96: Consider consistent return signatures for getter functions.
GetOperationIDreturns a string (empty on miss), whileGetTraceID,GetSpanID, etc., return(string, bool). This inconsistency may cause confusion for callers who need to distinguish between "empty value" and "value not found."♻️ Refactor to consistent return signature
-// GetOperationID retrieves operation ID from context -func GetOperationID(ctx context.Context) string { - if opID, ok := ctx.Value(OpIDKey).(string); ok { - return opID - } - return "" -} +// GetOperationID retrieves operation ID from context +func GetOperationID(ctx context.Context) (string, bool) { + opID, ok := ctx.Value(OpIDKey).(string) + return opID, ok +}Note: This would require updating all call sites that use
GetOperationID.cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
59-69: Consider implementing additionalhttp.ResponseWriterinterfaces.The
responseWriterwrapper correctly captures the status code, but it may break middleware that requireshttp.Flusher,http.Hijacker, orhttp.Pusherinterfaces (e.g., for SSE, WebSockets, or HTTP/2). If your API uses any of these features, consider implementing interface assertions.♻️ Optional enhancement for interface compatibility
// responseWriter wraps http.ResponseWriter to capture status code type responseWriter struct { http.ResponseWriter statusCode int } // WriteHeader captures the status code before writing func (rw *responseWriter) WriteHeader(code int) { rw.statusCode = code rw.ResponseWriter.WriteHeader(code) } + +// Flush implements http.Flusher if the underlying writer supports it +func (rw *responseWriter) Flush() { + if f, ok := rw.ResponseWriter.(http.Flusher); ok { + f.Flush() + } +}cmd/hyperfleet-api/main.go (1)
30-34: Redundant flag parsing before Cobra.Parsing
flag.CommandLinewith an empty slice before Cobra'sExecute()appears unnecessary. Cobra handles flag parsing internally. Unless there's a specific compatibility requirement with packages that register flags viaflagpackage, this can likely be removed.♻️ Consider removing if not needed
func main() { // Initialize logger first (before any logging occurs) initDefaultLogger() ctx := context.Background() - // Parse flags (needed for cobra compatibility) - if err := flag.CommandLine.Parse([]string{}); err != nil { - logger.Error(ctx, "Failed to parse flags", "error", err) - os.Exit(1) - } - rootCmd := &cobra.Command{If this is required for compatibility with glog or another library that registers flags, please add a comment explaining why.
pkg/logger/logger.go (1)
179-184:resetForTestingis unsafe for concurrent tests.Resetting
initOnce = sync.Once{}while other goroutines might be accessingglobalLoggerintroduces a data race. Consider using async.RWMutexto protect both the logger and the Once, or document that tests using this function must run serially.♻️ Safer approach with mutex
var ( globalLogger *slog.Logger initOnce sync.Once + loggerMu sync.RWMutex ) func InitGlobalLogger(cfg *LogConfig) { initOnce.Do(func() { + loggerMu.Lock() + defer loggerMu.Unlock() handler := NewHyperFleetHandler(cfg) globalLogger = slog.New(handler) slog.SetDefault(globalLogger) }) } func resetForTesting() { + loggerMu.Lock() + defer loggerMu.Unlock() globalLogger = nil initOnce = sync.Once{} } func GetLogger() *slog.Logger { + loggerMu.RLock() + defer loggerMu.RUnlock() if globalLogger == nil { return slog.Default() } return globalLogger }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (33)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/errors/errors.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/http.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/otel.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/logging.go
🚧 Files skipped from review as they are similar to previous changes (11)
- cmd/hyperfleet-api/server/server.go
- pkg/auth/authz_middleware_mock.go
- README.md
- cmd/hyperfleet-api/server/healthcheck_server.go
- pkg/logger/logger_test.go
- pkg/logger/ocm_bridge.go
- test/integration/integration_test.go
- docs/logging.md
- pkg/db/migrations.go
- pkg/api/error.go
- cmd/hyperfleet-api/server/api_server.go
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
test/helper.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/environments/framework.gopkg/logger/http.gopkg/middleware/otel.gopkg/db/db_session/testcontainer.gopkg/telemetry/otel.gopkg/errors/errors.gopkg/logger/context.gocmd/hyperfleet-api/servecmd/cmd.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/routes.gopkg/logger/logger.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/db_session/test.gopkg/db/db_session/testcontainer.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/db_session/test.gopkg/db/db_session/testcontainer.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/handlers/openapi.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/openapi.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/openapi.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/handlers/openapi.go
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
test/helper.gopkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/environments/framework.gopkg/logger/http.gopkg/db/db_session/testcontainer.gopkg/telemetry/otel.gopkg/errors/errors.gopkg/logger/context.gocmd/hyperfleet-api/servecmd/cmd.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/routes.gopkg/logger/logger.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
test/helper.gopkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.gopkg/middleware/otel.gopkg/db/db_session/testcontainer.gopkg/errors/errors.gopkg/logger/context.gocmd/hyperfleet-api/servecmd/cmd.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
test/helper.gopkg/errors/errors.gopkg/handlers/openapi.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
test/helper.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
test/helper.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/servecmd/cmd.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
test/helper.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/environments/framework.gopkg/errors/errors.gocmd/hyperfleet-api/servecmd/cmd.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
test/helper.gopkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
test/helper.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
test/helper.gopkg/errors/errors.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
test/helper.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
pkg/db/db_session/test.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/db/db_session/test.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity
Applied to files:
cmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
pkg/db/db_session/testcontainer.gopkg/errors/errors.gopkg/logger/context.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
pkg/db/db_session/testcontainer.gopkg/telemetry/otel.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
pkg/errors/errors.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Applied to files:
pkg/handlers/openapi.go
🧬 Code graph analysis (8)
test/helper.go (2)
pkg/logger/logger.go (7)
Error(246-248)Info(238-240)Debug(234-236)Warn(242-244)LogConfig(27-34)FormatText(21-21)InitGlobalLogger(171-177)cmd/hyperfleet-api/server/api_server.go (1)
NewAPIServer(30-101)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (2)
Error(246-248)Info(238-240)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
cmd/hyperfleet-api/environments/framework.go (3)
pkg/logger/logger.go (4)
Infof(254-256)Errorf(262-264)Info(238-240)Error(246-248)pkg/client/ocm/client.go (3)
Config(17-24)NewClientMock(47-53)NewClient(26-45)cmd/hyperfleet-api/environments/types.go (2)
Database(36-38)Clients(67-69)
pkg/middleware/otel.go (1)
pkg/logger/context.go (2)
WithTraceID(25-27)WithSpanID(30-32)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(262-264)
pkg/logger/context.go (1)
pkg/errors/errors.go (1)
New(112-132)
pkg/handlers/openapi.go (1)
pkg/logger/logger.go (1)
Info(238-240)
cmd/hyperfleet-api/server/routes.go (3)
pkg/middleware/otel.go (1)
OTelMiddleware(18-50)pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
RequestLoggingMiddleware(15-57)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
🔇 Additional comments (21)
go.mod (1)
26-26: LGTM! Dependency updates are well-structured.The OpenTelemetry dependencies are consistently versioned at v1.39.0, and the ksuid package has been updated to v1.0.4 as previously recommended. The migration of glog from direct to indirect dependency aligns with the structured logging refactor.
Also applies to: 32-36
pkg/logger/context.go (1)
14-22: Context key definitions are well-structured.The use of an unexported
contextKeytype for context keys is a Go best practice that prevents collisions. The keys are appropriately typed and named for their purposes.pkg/handlers/openapi.go (1)
24-59: LGTM! Proper context usage and structured logging migration.The initialization function correctly uses
context.Background()for startup logging, which is appropriate for non-request initialization code. The migration from glog to structured logging follows the project's coding guidelines.Based on coding guidelines and learnings.
pkg/errors/errors.go (1)
117-118: LGTM! Appropriate use of background context for error logging.Using
context.Background()in the undefined error code path is correct, as no request context is available at this point. The migration to structured logging withlogger.Errorffollows the project's coding guidelines.The static analysis hint about the missing import is a false positive—the import is correctly present at line 9.
Based on coding guidelines and learnings.
pkg/db/db_session/test.go (1)
16-16: LGTM! Logging migration looks good.The switch from glog to the structured logger (pkg/logger) with context-aware logging is correct. The use of
pkglogger.Errorf(ctx, ...)is appropriate for test database initialization error paths.Also applies to: 52-61
cmd/hyperfleet-api/server/routes.go (3)
71-75: LGTM! Conditional OTel middleware registration is well-placed.The conditional registration based on configuration and placement after the Operation ID middleware are appropriate. The middleware will extract trace context when enabled without adding overhead when disabled.
77-78: LGTM! Masking middleware initialization is efficient.Initializing the masking middleware once at startup and reusing it across all requests is the correct approach for a stateless middleware component.
81-81: LGTM! Request logging middleware integration is correct.Passing the masking middleware to
RequestLoggingMiddlewareenables sensitive data redaction in HTTP logs, as designed.pkg/middleware/otel.go (1)
18-50: LGTM! OTel middleware implementation is correct.The middleware correctly wraps the enrichment logic (
enrichedHandler) inside the OTel handler (otelHandler). The execution flow ensures:
otelHandlercreates the span and establishes the trace contextenrichedHandlerextracts the span from that context- Trace ID and span ID are added to the logger context
- The business handler receives the enriched context
This addresses the previous review concern about context timing.
test/helper.go (3)
72-97: LGTM! Test logger initialization and error handling are correct.The early initialization of the test logger (line 73) and consistent use of context-based logging throughout the setup phase align with the structured logging guidelines. Using
os.Exit(1)for fatal setup errors is appropriate for test infrastructure.
142-207: LGTM! Server lifecycle logging is consistent and context-aware.The consistent pattern of creating a local background context and using structured logging (
logger.Debug,logger.Error,logger.Warn) across all server lifecycle methods (API, metrics, health check) is correct and aligns with the logging guidelines.
544-555: LGTM! Test logger configuration is appropriate.The
initTestLoggerfunction correctly initializes the global logger with sensible defaults for the test environment:
- Text format for readability
- Info level for standard test output
- Appropriate component/version metadata
cmd/hyperfleet-api/migrate/cmd.go (2)
33-45: LGTM! Database connection cleanup properly handles the resource leak.The addition of the
deferblock (lines 41-45) immediately after creating the connection ensures the database connection is closed on all exit paths, addressing the previous review concern about resource leaks whenos.Exit()is called.
47-56: LGTM! Migration execution with proper error handling and logging.The migration flow correctly:
- Uses
connection.New(ctx)for context-aware database operations- Logs errors with structured logging
- Explicitly closes the connection before
os.Exit(1)to ensure cleanup- Logs successful completion
The explicit close on the error path (lines 50-52) ensures cleanup even though
os.Exit(1)bypasses the defer.cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
15-57: LGTM! Middleware structure is well-designed.The refactored middleware correctly:
- Accepts the masker as a parameter (avoiding per-request allocation)
- Skips health check endpoints to reduce log noise
- Captures both request and response metrics with proper timing
- Uses structured logging with HTTP attribute helpers
cmd/hyperfleet-api/environments/framework.go (1)
134-160: LGTM! Context-aware logging inLoadClients.The OCM client creation path correctly uses structured logging with context. The mock vs real client branching is clear.
cmd/hyperfleet-api/main.go (1)
54-66: LGTM! Default logger initialization.The early logger initialization ensures logging works before configuration is loaded. Using
"unknown"for version is appropriate since the real version is set later inservecmd.initLogger().cmd/hyperfleet-api/servecmd/cmd.go (1)
50-66: LGTM! OpenTelemetry initialization with proper shutdown.The OTel integration correctly:
- Checks the enabled flag before initializing
- Uses deferred shutdown with error handling
- Logs the configuration state for observability
pkg/logger/http.go (1)
1-49: LGTM! Clean HTTP attribute helpers.These helpers provide consistent, typed attribute construction for HTTP request/response logging. The separation of individual helpers (e.g.,
HTTPMethod) and aggregate helpers (e.g.,HTTPRequestAttrs) offers flexibility for different logging contexts.pkg/logger/logger.go (2)
266-311: LGTM! OCMLogger backward compatibility layer.The
ocmLoggerimplementation provides a clean bridge from the legacy OCMLogger interface to the new slog-based system:
- Correctly extracts
account_idandtx_idfrom context- Properly handles verbosity levels (V > 1 maps to debug)
- Implements immutable
Extra()with proper slice copyingBased on learnings, this aligns with the guideline to "Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields."
83-116: LGTM! Context-aware log record enrichment.The
Handlemethod correctly extracts correlation IDs from context (trace_id, span_id, operation_id, cluster_id, resource_type, resource_id) and adds stack traces for error-level logs. This aligns with the coding guidelines for context-aware logging.
|
@coderabbitai help |
ChatThere are 3 ways to chat with CodeRabbit:
CodeRabbit commands
Other keywords and placeholders
CodeRabbit configuration file (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cmd/hyperfleet-api/servecmd/cmd.go (1)
76-92: Missing graceful shutdown and server error handling.The servers are started in fire-and-forget goroutines with no error propagation or supervision. The
select {}blocks forever with no signal handling (SIGTERM, SIGINT), meaning:
- The deferred OTel shutdown at line 57-61 will never execute on normal termination
- If a server crashes, others continue without notification
- No graceful shutdown capability for container orchestration
🛠️ Suggested improvement
// Handle shutdown signals sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) // Start servers with error channels errChan := make(chan error, 3) go func() { apiserver := server.NewAPIServer() if err := apiserver.Start(); err != nil { errChan <- fmt.Errorf("API server: %w", err) } }() // ... similar for other servers // Wait for shutdown signal or error select { case sig := <-sigChan: logger.Info(ctx, "Received shutdown signal", "signal", sig) case err := <-errChan: logger.Error(ctx, "Server error", "error", err) } // Graceful shutdown logic here
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/server/metrics_server.go:
- Around line 59-60: The TLS metrics startup log uses the wrong config field;
update the logger.Info call that logs "Serving Metrics with TLS" to use
env().Config.Metrics.BindAddress instead of env().Config.Server.BindAddress so
it matches the non-TLS log and the actual server bind used during
initialization.
🧹 Nitpick comments (10)
cmd/hyperfleet-api/migrate/cmd.go (1)
33-33: Consider enriching the context with a migration-specific operation ID.While
context.Background()is appropriate for a CLI command, adding a unique operation ID (e.g.,logger.ContextWithOperationID(ctx, "migrate")) would align with the structured logging guidelines and improve log correlation.Based on coding guidelines requiring context-aware log fields including operation ID.
pkg/db/context.go (1)
33-33: Minor inconsistency in error logging.Lines 33 and 40 call
err.Error()to convert the error to a string, while line 54 passes theerrobject directly. While slog handles both approaches, consistent usage within the same file is preferable.♻️ Suggested consistency fix
- logger.Info(ctx, "Marked transaction for rollback", "error", err) + logger.Info(ctx, "Marked transaction for rollback", "error", err.Error())Or alternatively, update lines 33 and 40 to pass the error object directly (which is idiomatic for slog).
Also applies to: 40-40, 54-54
pkg/handlers/framework.go (1)
31-40: Consider adding structured fields for consistency.While the logging correctly uses the centralized logger with context, it only logs
err.Error()as a plain message. For consistency with other error logging in the codebase (e.g.,pkg/handlers/metadata.golines 48-51,pkg/middleware/schema_validation.golines 26-30), consider adding structured fields:logger.Info(r.Context(), err.Error(), "endpoint", r.URL.Path, "method", r.Method, "status_code", err.HttpCode)and similarly for the Error call at line 37.
This would provide better traceability and align with the structured logging pattern established elsewhere.
pkg/middleware/schema_validation.go (1)
20-20: Add structured fields for consistency.Line 20 logs the validation error without structured fields, while lines 26-30 in the same function include structured fields (endpoint, method, status_code, error). For consistency:
♻️ Suggested improvement
- logger.Info(r.Context(), err.Error()) + logger.Info(r.Context(), err.Error(), + "endpoint", r.URL.Path, + "method", r.Method, + "status_code", err.HttpCode)This provides better traceability and aligns with the structured logging pattern used elsewhere in this function.
pkg/db/db_session/default.go (1)
100-120: Accept context parameter to preserve trace information.The
waitForNotificationfunction creates a newBackground()context, but it's called fromnewListener(Line 136) which receives a context parameter. This breaks context propagation and loses trace IDs, operation IDs, and other correlation data that may be present in the parent context.♻️ Refactor to accept and use parent context
-func waitForNotification(l *pq.Listener, callback func(id string)) { - ctx := context.Background() +func waitForNotification(ctx context.Context, l *pq.Listener, callback func(id string)) { for { select { case n := <-l.Notify: logger.Info(ctx, "Received data from channel", "channel", n.Channel, "data", n.Extra) callback(n.Extra) return case <-time.After(10 * time.Second): logger.Debug(ctx, "Received no events on channel during interval. Pinging source") go func() { if err := l.Ping(); err != nil { logger.Debug(ctx, "Ping failed", "error", err) } }() return } } }Then update the call site in
newListener:func newListener(ctx context.Context, connstr, channel string, callback func(id string)) { // ... existing code ... logger.Info(ctx, "Starting channeling monitor", "channel", channel) for { - waitForNotification(listener, callback) + waitForNotification(ctx, listener, callback) } }Based on learnings, context values should be used for passing request-scoped data including operation ID and transaction ID.
pkg/telemetry/otel.go (2)
16-57: Consider adding structured logging for trace provider initialization.Per coding guidelines, all
**/*.gofiles should use structured logging. Consider adding log statements for successful initialization and any errors encountered during setup to aid debugging and monitoring.Example logging integration
func InitTraceProvider(serviceName, serviceVersion string, samplingRate float64) (*trace.TracerProvider, error) { + ctx := context.Background() + logger.Info(ctx, "Initializing OpenTelemetry trace provider", + "service_name", serviceName, + "service_version", serviceVersion, + "sampling_rate", samplingRate) + // Create stdout exporter exporter, err := stdouttrace.New( stdouttrace.WithPrettyPrint(), // Formatted output ) if err != nil { + logger.Error(ctx, "Failed to create stdout exporter", "error", err) return nil, err } // ... rest of function ... // Set global trace provider otel.SetTracerProvider(tp) + logger.Info(ctx, "OpenTelemetry trace provider initialized successfully") return tp, nil }
60-65: Consider adding logging for trace provider shutdown.Adding a log statement when shutting down the trace provider would help with debugging and observability, especially if the shutdown encounters errors.
Example shutdown logging
func Shutdown(ctx context.Context, tp *trace.TracerProvider) error { if tp == nil { return nil } + logger.Info(ctx, "Shutting down OpenTelemetry trace provider") - return tp.Shutdown(ctx) + err := tp.Shutdown(ctx) + if err != nil { + logger.Error(ctx, "Error shutting down trace provider", "error", err) + } else { + logger.Info(ctx, "OpenTelemetry trace provider shut down successfully") + } + return err }cmd/hyperfleet-api/main.go (1)
54-74: Consider setting version from build information.The logger version is currently hardcoded to "unknown". Consider using build-time variables to inject the actual application version for better observability.
Example using build-time version
+var ( + Version = "unknown" // Set via -ldflags at build time +) + func initDefaultLogger() { cfg := &logger.LogConfig{ Level: slog.LevelInfo, Format: logger.FormatJSON, Output: os.Stdout, Component: "hyperfleet-api", - Version: "unknown", + Version: Version, Hostname: getHostname(), } logger.InitGlobalLogger(cfg) }Then build with:
go build -ldflags "-X main.Version=v1.0.0"pkg/logger/ocm_bridge.go (1)
13-22: Stored context may become stale for long-lived bridges.The
ctxfield is captured at construction time but*Enabled()methods use it later. If the bridge is long-lived (e.g., stored in a connection object), this context may become stale or cancelled. Consider usingcontext.Background()for level checks, or accepting context in*Enabled()if the SDK interface allows.♻️ Suggested approach
// DebugEnabled implements sdk.Logger func (b *OCMLoggerBridge) DebugEnabled() bool { - return GetLogger().Enabled(b.ctx, slog.LevelDebug) + return GetLogger().Enabled(context.Background(), slog.LevelDebug) }Apply similarly to
InfoEnabled,WarnEnabled, andErrorEnabled.pkg/logger/logger.go (1)
274-288: The formatted variants lose structured logging benefits.The
*ffunctions (Debugf, Infof, Warnf, Errorf) format the message withfmt.Sprintf, embedding arguments into the message string. This loses the structured logging benefit of searchable key-value pairs. Consider documenting that the non-formatted variants are preferred for observability, or deprecating the*fvariants.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (48)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/metrics_server.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/auth/helpers.gopkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.gopkg/errors/errors.gopkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/http.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/otel.gopkg/middleware/schema_validation.gopkg/services/cluster.gopkg/services/generic.gopkg/services/node_pool.gopkg/services/status_aggregation.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/logging.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
🚧 Files skipped from review as they are similar to previous changes (8)
- cmd/hyperfleet-api/server/routes.go
- docs/logging.md
- test/helper.go
- cmd/hyperfleet-api/server/server.go
- pkg/middleware/otel.go
- pkg/logger/context.go
- pkg/db/db_session/test.go
- cmd/hyperfleet-api/server/healthcheck_server.go
🧰 Additional context used
📓 Path-based instructions (12)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
pkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/db/context.gopkg/services/node_pool.gopkg/handlers/metadata.gopkg/api/error.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/db/db_session/testcontainer.gopkg/middleware/schema_validation.gopkg/logger/logger_test.gotest/integration/integration_test.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/api_server.gopkg/services/status_aggregation.gopkg/telemetry/otel.gopkg/logger/ocm_bridge.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/handlers/nodepool_status.gopkg/logger/http.gocmd/hyperfleet-api/main.gopkg/services/generic.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/framework.gopkg/db/migrations.gocmd/hyperfleet-api/server/metrics_server.gopkg/logger/logger.gopkg/errors/errors.go
pkg/**/*{auth,middleware}*.go
📄 CodeRabbit inference engine (AGENTS.md)
JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Files:
pkg/auth/authz_middleware_mock.gopkg/db/transaction_middleware.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/handlers/helpers.gopkg/handlers/openapi.gopkg/handlers/nodepool_status.gopkg/handlers/framework.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/handlers/helpers.gopkg/handlers/openapi.gopkg/handlers/nodepool_status.gopkg/handlers/framework.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/handlers/metadata.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/handlers/openapi.gopkg/services/status_aggregation.gopkg/handlers/nodepool_status.gopkg/services/generic.gopkg/handlers/framework.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/handlers/cluster_status.gopkg/db/context.gopkg/services/node_pool.gopkg/handlers/metadata.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/db/db_session/testcontainer.gopkg/handlers/openapi.gopkg/services/status_aggregation.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/handlers/nodepool_status.gopkg/services/generic.gopkg/handlers/framework.gopkg/db/migrations.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/context.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/db/migrations.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/context.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/db/migrations.go
pkg/services/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/services/**/*.go: Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Files:
pkg/services/node_pool.gopkg/services/cluster.gopkg/services/status_aggregation.gopkg/services/generic.go
pkg/{dao,services}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Files:
pkg/services/node_pool.gopkg/services/cluster.gopkg/services/status_aggregation.gopkg/services/generic.go
pkg/api/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Files:
pkg/api/error.go
test/integration/**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Files:
test/integration/integration_test.go
🧠 Learnings (30)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Applied to files:
pkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
pkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/db/context.gopkg/services/node_pool.gopkg/handlers/metadata.gopkg/api/error.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/db/db_session/testcontainer.gopkg/middleware/schema_validation.gopkg/logger/logger_test.gotest/integration/integration_test.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gopkg/services/status_aggregation.gopkg/telemetry/otel.gopkg/logger/ocm_bridge.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/handlers/nodepool_status.gocmd/hyperfleet-api/main.gopkg/services/generic.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/framework.gopkg/db/migrations.gocmd/hyperfleet-api/server/metrics_server.gopkg/logger/logger.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Applied to files:
pkg/handlers/cluster_status.gopkg/services/status_aggregation.gopkg/handlers/nodepool_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Applied to files:
pkg/handlers/cluster_status.gopkg/services/status_aggregation.gopkg/handlers/nodepool_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Applied to files:
pkg/handlers/cluster_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
pkg/db/context.gopkg/api/error.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/db/db_session/testcontainer.gopkg/middleware/schema_validation.gotest/integration/integration_test.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/openapi.gopkg/services/status_aggregation.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/services/generic.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/framework.gopkg/db/migrations.gocmd/hyperfleet-api/server/metrics_server.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
pkg/db/context.gopkg/api/error.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
pkg/db/context.gopkg/api/error.gopkg/db/transaction_middleware.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
pkg/db/context.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity
Applied to files:
pkg/services/node_pool.gocmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
pkg/handlers/metadata.gopkg/api/error.gopkg/handlers/helpers.gopkg/middleware/schema_validation.gotest/integration/integration_test.gopkg/auth/helpers.gopkg/handlers/openapi.gopkg/services/status_aggregation.gopkg/handlers/framework.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/helpers.gopkg/auth/helpers.gopkg/handlers/openapi.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
pkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/default.gopkg/db/migrations.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
pkg/db/db_session/testcontainer.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/openapi.gopkg/db/db_session/default.gopkg/db/transaction_middleware.gopkg/handlers/framework.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
pkg/db/db_session/testcontainer.gotest/integration/integration_test.gopkg/services/status_aggregation.gopkg/telemetry/otel.gopkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
test/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/default.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/environments/framework.gopkg/db/migrations.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
test/integration/integration_test.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gogo.modpkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
test/integration/integration_test.gopkg/handlers/openapi.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Applied to files:
test/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
test/integration/integration_test.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/metrics_server.gopkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/handlers/openapi.gopkg/db/db_session/default.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Applied to files:
pkg/handlers/openapi.gopkg/services/generic.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Applied to files:
pkg/services/generic.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
go.mod
🧬 Code graph analysis (20)
pkg/auth/authz_middleware_mock.go (1)
pkg/logger/logger.go (1)
Info(262-264)
pkg/db/context.go (2)
pkg/logger/logger.go (2)
Error(270-272)Info(262-264)pkg/db/db_context/db_context.go (1)
Transaction(23-26)
pkg/services/node_pool.go (1)
pkg/logger/logger.go (1)
Info(262-264)
pkg/api/error.go (1)
pkg/logger/logger.go (1)
Error(270-272)
pkg/db/db_session/testcontainer.go (4)
pkg/logger/logger.go (4)
Info(262-264)Errorf(286-288)Infof(278-280)Error(270-272)pkg/db/db_session/default.go (1)
Default(20-29)pkg/errors/errors.go (1)
New(112-132)pkg/db/migrations.go (1)
Migrate(17-24)
pkg/middleware/schema_validation.go (1)
pkg/logger/logger.go (3)
Info(262-264)Error(270-272)Warn(266-268)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (14)
ParseLogLevel(219-232)Error(270-272)Errorf(286-288)LogFormat(15-15)FormatText(19-19)FormatJSON(21-21)ParseLogFormat(235-244)ParseLogOutput(247-256)LogConfig(25-32)InitGlobalLogger(174-182)Info(262-264)Debug(258-260)GetLogger(208-216)Warn(266-268)pkg/logger/context.go (6)
WithTraceID(25-27)WithSpanID(30-32)OpIDKey(15-15)WithClusterID(35-37)WithResourceType(40-42)WithResourceID(45-47)
pkg/auth/helpers.go (1)
pkg/logger/logger.go (2)
Info(262-264)Error(270-272)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (2)
Error(270-272)Info(262-264)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
pkg/handlers/openapi.go (1)
pkg/logger/logger.go (2)
Info(262-264)Error(270-272)
cmd/hyperfleet-api/server/api_server.go (6)
pkg/logger/ocm_bridge.go (1)
NewOCMLoggerBridge(18-22)pkg/logger/logger.go (2)
Info(262-264)Error(270-272)pkg/client/ocm/client.go (1)
Config(17-24)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)cmd/hyperfleet-api/environments/types.go (1)
Database(36-38)pkg/db/session.go (1)
SessionFactory(12-20)
pkg/services/status_aggregation.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(258-260)GetLogger(208-216)Info(262-264)Warn(266-268)Error(270-272)
pkg/db/db_session/default.go (1)
pkg/logger/logger.go (3)
Info(262-264)Debug(258-260)Error(270-272)
cmd/hyperfleet-api/main.go (1)
pkg/logger/logger.go (4)
Error(270-272)LogConfig(25-32)FormatJSON(21-21)InitGlobalLogger(174-182)
pkg/services/generic.go (1)
pkg/logger/logger.go (2)
Warn(266-268)Info(262-264)
cmd/hyperfleet-api/servecmd/cmd.go (3)
pkg/logger/logger.go (9)
Error(270-272)Warn(266-268)Info(262-264)ParseLogLevel(219-232)ParseLogFormat(235-244)FormatJSON(21-21)ParseLogOutput(247-256)LogConfig(25-32)ReconfigureGlobalLogger(187-195)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/telemetry/otel.go (2)
InitTraceProvider(16-57)Shutdown(60-65)
pkg/db/migrations.go (1)
pkg/logger/logger.go (1)
Error(270-272)
cmd/hyperfleet-api/server/metrics_server.go (1)
pkg/logger/logger.go (1)
Info(262-264)
pkg/logger/logger.go (2)
pkg/logger/context.go (4)
GetOperationID(61-66)GetClusterID(81-84)GetResourceType(87-90)GetResourceID(93-96)pkg/errors/errors.go (1)
New(112-132)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/server/metrics_server.go:
- Around line 59-60: The TLS startup log uses the wrong config field: change the
logger.Info call that currently logs env().Config.Server.BindAddress to log
env().Config.Metrics.BindAddress instead so the TLS message matches the non-TLS
case and the actual server initialization (update the logger.Info invocation
that prints "Serving Metrics with TLS" to reference
env().Config.Metrics.BindAddress).
In @pkg/db/transaction_middleware.go:
- Line 18: The error logging after NewContext can use an invalid ctx when
NewContext fails; update the error branch so logger.Error is called with the
original request context r.Context() instead of the potentially nil/invalid ctx.
Locate the NewContext call and its error-handling block in
transaction_middleware.go and change the logger.Error invocation (the one
currently passing ctx and err.Error()) to use r.Context() and include the same
message and error detail; ensure other uses in that error path do not
dereference ctx.
In @pkg/logger/ocm_bridge.go:
- Around line 13-68: The stored context field in OCMLoggerBridge causes
inconsistent context usage between the level checks and logging calls; remove
the ctx field from OCMLoggerBridge and stop storing a context in
NewOCMLoggerBridge, and update DebugEnabled/InfoEnabled/WarnEnabled/ErrorEnabled
to call GetLogger().Enabled with a global context (e.g., context.Background() or
context.TODO()) instead of b.ctx so the enabled checks are context-independent
and consistent with the logging methods that accept a request context (symbols:
type OCMLoggerBridge, NewOCMLoggerBridge, DebugEnabled, InfoEnabled,
WarnEnabled, ErrorEnabled).
🧹 Nitpick comments (18)
pkg/db/context.go (1)
47-55: Consider using err.Error() for consistency.Line 54 passes the error directly, while Lines 33 and 40 use
err.Error(). Although slog handles both, usingerr.Error()consistently improves readability and ensures uniform string formatting across all log statements in this file.♻️ Proposed fix for consistency
- logger.Info(ctx, "Marked transaction for rollback", "error", err) + logger.Info(ctx, "Marked transaction for rollback", "error", err.Error())pkg/db/migrations.go (1)
35-38: LGTM! Structured logging properly implemented.The error logging correctly uses structured fields with the context. The migration failure appropriately terminates the application with
os.Exit(1).Optional: Pass error directly instead of converting to string
The logger can handle error values directly:
logger.Error(ctx, "Could not migrate", "migration_id", migrationID, - "error", err.Error()) + "error", err)This is a minor style preference—both approaches work correctly.
Based on learnings, structured logging with context-aware fields is properly implemented.
pkg/db/db_session/default.go (1)
122-138: Consider using structured error field in listener error callback.At line 125, the error is passed as the message string via
err.Error(). For consistency with the structured logging approach used elsewhere, consider using a structured error field:- logger.Error(ctx, err.Error()) + logger.Error(ctx, "listener error", "error", err)This allows log aggregation tools to parse the error as a structured field.
cmd/hyperfleet-api/server/routes.go (1)
104-135: LGTM! Schema validation logging migrated to centralized logger.The schema validation initialization now uses context-aware structured logging with appropriate fields (schema_path, error). The guidance messages on lines 127-129 provide clear instructions for enabling schema validation in different environments.
Optional: Consolidate guidance messages
The three separate logger.Info calls on lines 127-129 could be consolidated into a single multi-line message for slightly cleaner logs, but the current approach is perfectly acceptable.
pkg/middleware/masking_test.go (1)
253-306: LGTM! Deep comparison helpers correctly handle JSON structure comparison.The recursive comparison functions properly handle maps, slices, and nested structures, ensuring JSON comparisons are order-independent. The implementation is correct and well-suited for validating masked JSON output.
Optional: Extract to test utilities
If these deep comparison helpers are useful for other test files, consider extracting them to a shared test utility package (e.g.,
test/testutil). For now, keeping them local is perfectly fine.cmd/hyperfleet-api/migrate/cmd.go (1)
40-57: LGTM! Connection cleanup correctly handles both success and error paths.The cleanup pattern properly addresses the previous review concern:
- Success path: The defer on lines 41-45 closes the connection after successful migration
- Error path: Explicit close on line 50 ensures cleanup before
os.Exit(1)(which bypasses defers)This is the correct approach for handling resource cleanup with
os.Exit()calls.Optional: Add clarity comment
Consider adding a comment above line 50 explaining why explicit close is needed:
// Close connection explicitly before os.Exit (defers don't run with os.Exit) if closeErr := connection.Close(); closeErr != nil {This would help future maintainers understand the nuanced cleanup pattern.
pkg/db/db_session/testcontainer.go (3)
57-58: Prefer structured logging over printf-style format strings.The error logging uses
logger.Errorfwith printf-style formatting, which is less structured than the recommended approach. Consider usinglogger.Errorwith key-value pairs for consistency with the coding guidelines.♻️ Proposed refactor
- logger.Errorf(ctx, "Failed to start PostgreSQL testcontainer: %s", err) + logger.Error(ctx, "Failed to start PostgreSQL testcontainer", "error", err)Apply similar changes to lines 66, 75, 99, and 106 for consistency.
Based on coding guidelines requiring structured logging with context-aware log fields.
Also applies to: 66-67, 75-76, 99-100, 106-107
70-70: Prefer structured logging for connection string.Line 70 uses
logger.Infofwith printf-style formatting. For consistency with structured logging patterns used elsewhere in this file (e.g., line 171), consider using key-value pairs.♻️ Proposed refactor
- logger.Infof(ctx, "PostgreSQL testcontainer started at: %s", connStr) + logger.Info(ctx, "PostgreSQL testcontainer started", "connection_string", connStr)
139-139: Prefer structured logging in error paths.Lines 139 and 181 use
logger.Errorfwith printf-style formatting. For consistency with the structured logging approach recommended in the coding guidelines, uselogger.Errorwith key-value pairs.♻️ Proposed refactor
- logger.Errorf(ctx, "Error closing SQL connection: %s", err) + logger.Error(ctx, "Error closing SQL connection", "error", err)Apply the same pattern to line 181.
Also applies to: 181-181
pkg/middleware/masking.go (1)
104-112: Ensure sensitive field keywords are specific to avoid false positives.Line 107 uses
strings.Containsfor substring matching, which means overly generic keywords (e.g., "id") could match unrelated fields ("video", "identifier"). Ensure the sensitive fields list inLoggingConfiguses specific keywords to avoid over-redaction.cmd/hyperfleet-api/servecmd/cmd.go (2)
51-66: LGTM: OpenTelemetry initialization is robust.The OTel initialization properly handles failures without blocking server startup (lines 54-56), implements graceful shutdown with error logging (lines 57-61), and provides clear visibility into the configuration state (lines 62, 65).
📝 Optional: Add timeout for shutdown
Consider creating a timeout context for the shutdown operation to prevent hanging:
defer func() { - if err := telemetry.Shutdown(context.Background(), tp); err != nil { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := telemetry.Shutdown(shutdownCtx, tp); err != nil { logger.Error(ctx, "Failed to shutdown OpenTelemetry", "error", err) } }()
95-138: LGTM: Logger initialization with proper reconfiguration.The
initLoggerfunction correctly usesReconfigureGlobalLogger(line 137) to apply environment configuration, addressing the previously identified sync.Once issue. The fallback defaults (lines 104, 111, 118) ensure safe operation even with invalid configuration.📝 Optional: Log hostname retrieval failure
Line 122 silently ignores hostname errors. Consider logging a warning for visibility:
// Get hostname - hostname, _ := os.Hostname() + hostname, err := os.Hostname() + if err != nil { + logger.Warn(ctx, "Failed to get hostname, using empty string", "error", err) + hostname = "" + }pkg/telemetry/otel.go (2)
16-34: LGTM: Exporter and resource creation follow OTel best practices.The stdout exporter with pretty-printing (lines 18-20) is appropriate for initial implementation, and the resource attributes (lines 27-29) correctly use semantic conventions. The comment about future OTLP HTTP upgrade (lines 14-15) shows good forward planning.
📝 Optional: Accept context parameter
Consider accepting a context parameter instead of using
context.Background()on line 26 for better context propagation:-func InitTraceProvider(serviceName, serviceVersion string, samplingRate float64) (*trace.TracerProvider, error) { +func InitTraceProvider(ctx context.Context, serviceName, serviceVersion string, samplingRate float64) (*trace.TracerProvider, error) { // Create stdout exporter exporter, err := stdouttrace.New( stdouttrace.WithPrettyPrint(), // Formatted output ) if err != nil { return nil, err } // Create resource (service information) - res, err := resource.New(context.Background(), + res, err := resource.New(ctx,This would require updating the caller in
servecmd/cmd.goline 53.
36-44: LGTM: Sampler logic correctly handles standard cases.The sampling rate logic (lines 38-43) properly handles the three standard scenarios: always sample (≥1.0), never sample (≤0.0), and ratio-based sampling (0.0-1.0).
📝 Optional: Add input validation
Consider validating the sampling rate for edge cases (NaN, Inf):
func InitTraceProvider(serviceName, serviceVersion string, samplingRate float64) (*trace.TracerProvider, error) { + // Validate sampling rate + if math.IsNaN(samplingRate) || math.IsInf(samplingRate, 0) { + return nil, fmt.Errorf("invalid sampling rate: %v", samplingRate) + } + // Create stdout exporterpkg/config/logging.go (1)
65-101: Consider logging environment variable parsing errors.The
BindEnvmethod silently ignores parsing errors for boolean and float values (lines 77-87, 90-94). While this fail-safe behavior is acceptable, consider logging a warning when parsing fails so operators can detect configuration issues.🔍 Optional enhancement
if val := os.Getenv("OTEL_ENABLED"); val != "" { enabled, err := strconv.ParseBool(val) - if err == nil { + if err != nil { + // Could log warning here if logger is initialized + // For now, silently keep default + } else { l.OTel.Enabled = enabled } }Note: This is a nitpick and the current silent behavior is reasonable for a configuration loader.
pkg/logger/context.go (1)
61-96: Consider consistent getter signatures across all context helpers.
GetOperationIDreturns a string (empty if not found), while other getters (GetTraceID,GetSpanID, etc.) return(string, bool)tuples. This inconsistency makes error handling less uniform for callers.♻️ Proposed fix for consistency
-// GetOperationID retrieves operation ID from context -func GetOperationID(ctx context.Context) string { - if opID, ok := ctx.Value(OpIDKey).(string); ok { - return opID - } - return "" -} +// GetOperationID retrieves operation ID from context +func GetOperationID(ctx context.Context) (string, bool) { + opID, ok := ctx.Value(OpIDKey).(string) + return opID, ok +}This would require updating call sites that expect a single string return value.
pkg/logger/logger.go (2)
174-182: Consider removing redundant lock insidesync.Once.The
sync.Once.Doalready provides synchronization guarantees - the function passed toDowill execute exactly once and all other callers will block until completion. TheloggerMutex.Lock()inside is redundant for initialization safety.However, keeping it maintains consistency with
ReconfigureGlobalLoggerandGetLoggerwhich use the same mutex, so this is a minor point.♻️ Optional simplification
func InitGlobalLogger(cfg *LogConfig) { initOnce.Do(func() { handler := NewHyperFleetHandler(cfg) - loggerMutex.Lock() globalLogger = slog.New(handler) slog.SetDefault(globalLogger) - loggerMutex.Unlock() }) }
274-288: Consider deprecating or documenting the*fvariants.The
Debugf,Infof,Warnf,Errorffunctions usefmt.Sprintfwhich embeds arguments directly into the message string, bypassing slog's structured logging. This loses the queryability benefits of structured logging (e.g., filtering by field values in log aggregation systems).These functions may exist for compatibility with legacy code, but new code should prefer the structured variants:
// Instead of: logger.Infof(ctx, "Processing cluster %s", clusterID) // Prefer: logger.Info(ctx, "Processing cluster", "cluster_id", clusterID)If these are intended for migration compatibility, consider adding a deprecation comment.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (54)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/metrics_server.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/auth/helpers.gopkg/config/config.gopkg/config/logging.gopkg/config/logging_test.gopkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.gopkg/errors/errors.gopkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/http.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/logger/operationid_middleware.gopkg/middleware/masking.gopkg/middleware/masking_test.gopkg/middleware/otel.gopkg/middleware/schema_validation.gopkg/services/cluster.gopkg/services/generic.gopkg/services/node_pool.gopkg/services/status_aggregation.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (6)
- cmd/hyperfleet-api/server/logging/logging.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- pkg/logger/operationid_middleware.go
🧰 Additional context used
📓 Path-based instructions (12)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
test/integration/integration_test.gopkg/errors/errors.gopkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/db/transaction_middleware.gopkg/services/node_pool.gopkg/middleware/masking_test.gotest/helper.gopkg/handlers/openapi.gopkg/logger/logger_test.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/helpers.gopkg/logger/http.gopkg/middleware/otel.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/server/metrics_server.gopkg/middleware/schema_validation.gopkg/logger/ocm_bridge.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/db/context.gopkg/config/logging_test.gopkg/telemetry/otel.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/middleware/masking.gopkg/config/logging.gopkg/services/cluster.gocmd/hyperfleet-api/server/api_server.gopkg/db/db_session/testcontainer.gopkg/logger/context.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/services/generic.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/api/error.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/handlers/framework.gocmd/hyperfleet-api/servecmd/cmd.gopkg/config/config.gopkg/logger/logger.gopkg/services/status_aggregation.gocmd/hyperfleet-api/server/routes.go
test/integration/**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Files:
test/integration/integration_test.go
pkg/**/*{auth,middleware}*.go
📄 CodeRabbit inference engine (AGENTS.md)
JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Files:
pkg/auth/authz_middleware_mock.gopkg/db/transaction_middleware.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/cluster_status.gopkg/handlers/openapi.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/framework.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/cluster_status.gopkg/handlers/openapi.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/framework.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/handlers/openapi.gopkg/handlers/helpers.gopkg/services/cluster.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/services/generic.gopkg/handlers/framework.gopkg/services/status_aggregation.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/handlers/cluster_status.gopkg/db/transaction_middleware.gopkg/services/node_pool.gopkg/handlers/openapi.gopkg/handlers/helpers.gopkg/db/db_session/test.gopkg/db/context.gopkg/services/cluster.gopkg/db/db_session/testcontainer.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/services/generic.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/handlers/framework.gopkg/services/status_aggregation.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/transaction_middleware.gopkg/db/db_session/test.gopkg/db/context.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/migrations.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/transaction_middleware.gopkg/db/db_session/test.gopkg/db/context.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/migrations.go
pkg/services/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/services/**/*.go: Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Files:
pkg/services/node_pool.gopkg/services/cluster.gopkg/services/generic.gopkg/services/status_aggregation.go
pkg/{dao,services}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Files:
pkg/services/node_pool.gopkg/services/cluster.gopkg/services/generic.gopkg/services/status_aggregation.go
pkg/api/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Files:
pkg/api/error.go
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gopkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/db/transaction_middleware.gopkg/services/node_pool.gotest/helper.gopkg/handlers/openapi.gopkg/logger/logger_test.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/helpers.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/server/metrics_server.godocs/logging.mdpkg/middleware/schema_validation.gopkg/logger/ocm_bridge.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/server.gopkg/db/context.gopkg/telemetry/otel.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/config/logging.gopkg/services/cluster.gocmd/hyperfleet-api/server/api_server.gopkg/db/db_session/testcontainer.gopkg/logger/context.gopkg/handlers/metadata.gopkg/services/generic.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/api/error.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/handlers/framework.gocmd/hyperfleet-api/servecmd/cmd.gopkg/logger/logger.gopkg/services/status_aggregation.gocmd/hyperfleet-api/server/routes.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gopkg/db/transaction_middleware.gotest/helper.gopkg/handlers/openapi.gocmd/hyperfleet-api/environments/framework.gopkg/handlers/helpers.gopkg/middleware/otel.gocmd/hyperfleet-api/server/metrics_server.gopkg/middleware/schema_validation.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/server.gopkg/db/context.gopkg/auth/helpers.gocmd/hyperfleet-api/migrate/cmd.gopkg/services/cluster.gocmd/hyperfleet-api/server/api_server.gopkg/db/db_session/testcontainer.gopkg/logger/context.gopkg/handlers/metadata.gopkg/services/generic.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/api/error.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/handlers/framework.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
test/integration/integration_test.gotest/helper.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/migrate/cmd.gogo.modcmd/hyperfleet-api/server/healthcheck_server.gopkg/db/db_session/default.gopkg/db/migrations.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gotest/helper.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/api_server.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gotest/helper.gopkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Applied to files:
test/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
test/integration/integration_test.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
test/integration/integration_test.gopkg/errors/errors.gopkg/handlers/openapi.gopkg/handlers/helpers.gopkg/middleware/schema_validation.gocmd/hyperfleet-api/server/server.gopkg/auth/helpers.gopkg/handlers/metadata.gopkg/api/error.gopkg/handlers/framework.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
test/integration/integration_test.gopkg/db/db_session/test.gopkg/telemetry/otel.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
test/integration/integration_test.gotest/helper.gocmd/hyperfleet-api/environments/framework.gopkg/config/logging_test.gocmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
pkg/errors/errors.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/server/server.gopkg/db/context.gopkg/logger/context.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
pkg/errors/errors.gotest/helper.gopkg/handlers/openapi.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/server/metrics_server.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Applied to files:
pkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Applied to files:
pkg/handlers/cluster_status.gopkg/handlers/nodepool_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Applied to files:
pkg/handlers/cluster_status.gopkg/handlers/nodepool_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Applied to files:
pkg/handlers/cluster_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/db/transaction_middleware.gopkg/handlers/openapi.gopkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/migrations.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity
Applied to files:
pkg/services/node_pool.gocmd/hyperfleet-api/migrate/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
test/helper.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
test/helper.gopkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gogo.modpkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
test/helper.gopkg/handlers/openapi.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/server/healthcheck_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Applied to files:
pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/handlers/openapi.gopkg/db/db_session/default.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/openapi.gopkg/handlers/helpers.gopkg/auth/helpers.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/server/metrics_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Applied to files:
pkg/handlers/openapi.gopkg/services/generic.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
pkg/db/db_session/test.gopkg/db/context.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gopkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/server/server.gopkg/db/context.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/db_session/testcontainer.gopkg/api/error.gopkg/db/db_session/default.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
pkg/db/db_session/test.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Applied to files:
pkg/services/generic.go
🧬 Code graph analysis (32)
test/integration/integration_test.go (1)
pkg/logger/logger.go (2)
Infof(278-280)Warn(266-268)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(286-288)
pkg/auth/authz_middleware_mock.go (1)
pkg/logger/logger.go (1)
Info(262-264)
pkg/handlers/cluster_status.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
pkg/db/transaction_middleware.go (1)
pkg/logger/logger.go (1)
Error(270-272)
pkg/services/node_pool.go (1)
pkg/logger/logger.go (1)
Info(262-264)
test/helper.go (1)
pkg/logger/logger.go (7)
Error(270-272)Info(262-264)Debug(258-260)Warn(266-268)LogConfig(25-32)FormatText(19-19)InitGlobalLogger(174-182)
pkg/handlers/openapi.go (1)
pkg/logger/logger.go (2)
Info(262-264)Error(270-272)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (17)
ParseLogLevel(219-232)Error(270-272)Errorf(286-288)LogFormat(15-15)FormatText(19-19)FormatJSON(21-21)ParseLogFormat(235-244)ParseLogOutput(247-256)LogConfig(25-32)InitGlobalLogger(174-182)Info(262-264)Debug(258-260)GetLogger(208-216)Warn(266-268)Debugf(274-276)Infof(278-280)Warnf(282-284)pkg/logger/context.go (6)
WithTraceID(25-27)WithSpanID(30-32)OpIDKey(15-15)WithClusterID(35-37)WithResourceType(40-42)WithResourceID(45-47)
cmd/hyperfleet-api/environments/framework.go (1)
pkg/logger/logger.go (4)
Infof(278-280)Errorf(286-288)Info(262-264)Error(270-272)
pkg/handlers/helpers.go (1)
pkg/logger/logger.go (1)
Error(270-272)
cmd/hyperfleet-api/main.go (1)
pkg/logger/logger.go (4)
Error(270-272)LogConfig(25-32)FormatJSON(21-21)InitGlobalLogger(174-182)
pkg/middleware/schema_validation.go (1)
pkg/logger/logger.go (3)
Info(262-264)Error(270-272)Warn(266-268)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(258-260)GetLogger(208-216)Info(262-264)Warn(266-268)Error(270-272)
pkg/db/db_session/test.go (3)
pkg/db/migrations.go (1)
Migrate(17-24)pkg/logger/logger.go (1)
Errorf(286-288)pkg/db/db_session/default.go (1)
Default(20-29)
cmd/hyperfleet-api/server/server.go (1)
pkg/logger/logger.go (1)
Error(270-272)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (3)
pkg/middleware/masking.go (1)
MaskingMiddleware(13-17)pkg/logger/logger.go (1)
Info(262-264)pkg/logger/http.go (5)
HTTPMethod(10-12)HTTPPath(15-17)HTTPUserAgent(30-32)HTTPStatusCode(20-22)HTTPDuration(25-27)
pkg/config/logging_test.go (1)
pkg/config/logging.go (2)
NewLoggingConfig(35-50)LoggingConfig(12-19)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (2)
Error(270-272)Info(262-264)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
pkg/middleware/masking.go (1)
pkg/config/logging.go (1)
LoggingConfig(12-19)
pkg/services/cluster.go (1)
pkg/logger/logger.go (1)
Info(262-264)
pkg/handlers/metadata.go (2)
pkg/logger/logger.go (1)
Error(270-272)pkg/api/error.go (1)
SendPanic(70-81)
pkg/handlers/nodepool_status.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
pkg/services/generic.go (1)
pkg/logger/logger.go (2)
Warn(266-268)Info(262-264)
cmd/hyperfleet-api/server/healthcheck_server.go (1)
pkg/logger/logger.go (2)
Infof(278-280)Info(262-264)
pkg/db/db_session/default.go (1)
pkg/logger/logger.go (3)
Info(262-264)Debug(258-260)Error(270-272)
pkg/db/migrations.go (2)
pkg/errors/errors.go (1)
New(112-132)pkg/logger/logger.go (1)
Error(270-272)
pkg/handlers/framework.go (1)
pkg/logger/logger.go (2)
Info(262-264)Error(270-272)
pkg/config/config.go (1)
pkg/config/logging.go (2)
LoggingConfig(12-19)NewLoggingConfig(35-50)
pkg/logger/logger.go (2)
pkg/logger/context.go (6)
GetTraceID(69-72)GetSpanID(75-78)GetOperationID(61-66)GetClusterID(81-84)GetResourceType(87-90)GetResourceID(93-96)pkg/errors/errors.go (1)
New(112-132)
pkg/services/status_aggregation.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
cmd/hyperfleet-api/server/routes.go (4)
pkg/middleware/otel.go (1)
OTelMiddleware(18-50)pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
RequestLoggingMiddleware(15-57)pkg/logger/logger.go (3)
Warn(266-268)Error(270-272)Info(262-264)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/db/db_session/default.go (1)
100-120: Context propagation issue in waitForNotification.
waitForNotificationcreates its owncontext.Background()instead of accepting the context fromnewListener. This breaks context propagation, meaning any context-specific log fields (operation ID, trace ID) from the caller won't be included in these logs.🔧 Proposed fix
-func waitForNotification(l *pq.Listener, callback func(id string)) { - ctx := context.Background() +func waitForNotification(ctx context.Context, l *pq.Listener, callback func(id string)) { for { select { case n := <-l.Notify:And update the call site in
newListener:for { - waitForNotification(listener, callback) + waitForNotification(ctx, listener, callback) }
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/server/logging/request_logging_middleware.go:
- Around line 59-69: The responseWriter wrapper needs a Write method so implicit
calls that trigger a 200 status still update rw.statusCode; add a method on
responseWriter: func (rw *responseWriter) Write(b []byte) (int, error) { if
rw.statusCode == 0 { rw.statusCode = http.StatusOK } return
rw.ResponseWriter.Write(b) } to ensure statusCode is set when WriteHeader wasn't
called explicitly (referencing the responseWriter type and its WriteHeader
method).
In @pkg/services/node_pool.go:
- Line 107: Replace the vague, grammatically incorrect logger.Info call with a
context-aware logger from logger.NewOCMLogger(ctx) and a clearer message: create
a logger via l := logger.NewOCMLogger(ctx) and call l.Info("Perform idempotent
operations on node pool", "nodepool_id", nodePool.ID) so the log includes the
corrected message and automatic context fields (operation ID, account ID,
transaction ID).
🧹 Nitpick comments (14)
pkg/services/node_pool.go (1)
113-113: Use logger.NewOCMLogger per coding guidelines.Per coding guidelines, use
logger.NewOCMLogger(ctx)instead oflogger.Info(ctx, ...)to ensure context-aware fields like operation ID, account ID, and transaction ID are automatically included from the context.Based on coding guidelines and learnings.
📝 Suggested fix
- logger.Info(ctx, "This nodePool has been deleted", "nodepool_id", id) + log := logger.NewOCMLogger(ctx) + log.Info("NodePool deleted", "nodepool_id", id)pkg/errors/errors.go (1)
117-118: LGTM - Context-aware logging for undefined error codes.The migration to the centralized logger is correct. Using
context.Background()is acceptable here sinceNew()doesn't have a caller-provided context.As a future enhancement, consider accepting
context.Contextas an optional parameter to propagate request-scoped data (operation ID, account ID) for better traceability. Based on learnings, the codebase emphasizes context-aware logging with operation ID, account ID, and transaction ID.pkg/handlers/framework.go (1)
31-40: LGTM - Proper context-aware error logging.The migration correctly uses
r.Context()for logging, enabling request-scoped data to be included. The distinction between 4xx (Info level) and other errors (Error level) is appropriate.Based on coding guidelines, consider including the
operationIDin the log message for enhanced traceability:♻️ Optional enhancement
func handleError(r *http.Request, w http.ResponseWriter, err *errors.ServiceError) { operationID := logger.GetOperationID(r.Context()) // If this is a 400 error, its the user's issue, log as info rather than error if err.HttpCode >= 400 && err.HttpCode <= 499 { - logger.Info(r.Context(), err.Error()) + logger.Info(r.Context(), err.Error(), "operation_id", operationID) } else { - logger.Error(r.Context(), err.Error()) + logger.Error(r.Context(), err.Error(), "operation_id", operationID) } writeJSONResponse(w, r, err.HttpCode, err.AsOpenapiError(operationID)) }cmd/hyperfleet-api/environments/framework.go (1)
176-184: Minor inconsistency in logging style.Line 180 uses
logger.Errorwith structured key-value pairs ("flag", name, "error", err), while other error paths in this file uselogger.Errorfwith format strings. Consider aligning the style for consistency:♻️ Suggested fix for consistency
func setConfigDefaults(flags *pflag.FlagSet, defaults map[string]string) error { ctx := context.Background() for name, value := range defaults { if err := flags.Set(name, value); err != nil { - logger.Error(ctx, "Error setting flag", "flag", name, "error", err) + logger.Errorf(ctx, "Error setting flag %s: %s", name, err) return err } } return nil }Alternatively, migrate all
Errorfcalls to the structuredErrorstyle with key-value pairs for better consistency with modern slog patterns.pkg/logger/http.go (1)
34-41: Consider nil safety for HTTPRequestAttrs.
HTTPRequestAttrswill panic if called with a nil*http.Request. While callers should validate inputs, a defensive nil check could prevent unexpected panics in edge cases.♻️ Optional defensive check
// HTTPRequestAttrs returns a slice of slog attributes for HTTP request func HTTPRequestAttrs(r *http.Request) []slog.Attr { + if r == nil { + return nil + } return []slog.Attr{ HTTPMethod(r.Method), HTTPPath(r.URL.Path), HTTPUserAgent(r.UserAgent()), } }pkg/logger/logger.go (1)
246-256: Consider supporting file output in ParseLogOutput.Currently, only
stdoutandstderrare supported. For production environments, file-based logging is often required for log aggregation systems.♻️ Optional enhancement for file output support
// ParseLogOutput converts string to io.Writer func ParseLogOutput(output string) (io.Writer, error) { switch strings.ToLower(strings.TrimSpace(output)) { case "stdout", "": return os.Stdout, nil case "stderr": return os.Stderr, nil default: - return nil, fmt.Errorf("unknown log output: %s (valid: stdout, stderr)", output) + // Attempt to open as file path + file, err := os.OpenFile(output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, fmt.Errorf("failed to open log file %s: %w", output, err) + } + return file, nil } }Note: If file output is added, ensure proper file handle cleanup is managed elsewhere.
pkg/db/context.go (1)
46-55: Inconsistent error value formatting.Line 54 passes
errdirectly as the value, while other locations (lines 33, 40) useerr.Error(). For consistent structured logging output, consider using.Error()uniformly or relying on slog's automatic error formatting.♻️ Proposed fix for consistency
func MarkForRollback(ctx context.Context, err error) { transaction, ok := dbContext.Transaction(ctx) if !ok { logger.Error(ctx, "failed to mark transaction for rollback: could not retrieve transaction from context") return } transaction.SetRollbackFlag(true) - logger.Info(ctx, "Marked transaction for rollback", "error", err) + logger.Info(ctx, "Marked transaction for rollback", "error", err.Error()) }pkg/db/transaction_middleware.go (1)
36-45: Consider logging marshaling and write errors.Silent failures in
writeJSONResponsemay make debugging difficult. While headers are already sent, logging these errors could help with troubleshooting.♻️ Optional: Add error logging for visibility
+import "context" + func writeJSONResponse(w http.ResponseWriter, code int, payload interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) if payload != nil { response, err := json.Marshal(payload) if err != nil { - // Log error but don't expose to client since headers already sent + logger.Error(context.Background(), "Failed to marshal JSON response", "error", err.Error()) return } if _, err := w.Write(response); err != nil { - // Response writing failed, nothing we can do at this point + logger.Error(context.Background(), "Failed to write response", "error", err.Error()) return } } }Note: This function lacks request context, so
context.Background()would be used. Consider passing context as a parameter if request tracing is needed.cmd/hyperfleet-api/server/server.go (1)
28-34: Consider accepting context as a parameter for better composability.The
checkfunction currently creates a new context viacontext.Background(). While this is acceptable for a top-level error handler that exits the process, accepting a context parameter would improve composability and allow propagation of existing context values (e.g., trace IDs, operation IDs) into error logs.♻️ Proposed refactor
-func check(err error, msg string) { - ctx := context.Background() +func check(ctx context.Context, err error, msg string) { if err != nil && err != http.ErrServerClosed { logger.Error(ctx, msg, "error", err) os.Exit(1) } }Then update call sites to pass context (e.g., from Start/Stop methods).
test/helper.go (1)
84-86: Consider usingt.Fatalinstead ofos.Exit(1)for test setup failures.
os.Exit(1)bypasses Go's test framework reporting and cleanup. While this preserves the previousglog.Fatalbehavior, switching tot.Fatal(or propagating errors) would provide better test diagnostics.♻️ Example refactor
if err != nil { - logger.Error(ctx, "Unable to add environment flags", "error", err) - os.Exit(1) + t.Fatalf("Unable to add environment flags: %v", err) }Note: This would require passing
tinto the once.Do block or restructuring the initialization.cmd/hyperfleet-api/migrate/cmd.go (1)
41-54: Double-close pattern may cause issues ifClose()is not idempotent.The explicit
Close()call beforeos.Exit(1)(lines 50-52) is necessary sincedeferdoesn't run onos.Exit. However, if the code is later refactored to usereturninstead ofos.Exit,Close()would be called twice.Consider restructuring to avoid the explicit close:
♻️ Alternative approach using a helper
func runMigrate(_ *cobra.Command, _ []string) { ctx := context.Background() + if err := doMigrate(ctx); err != nil { + logger.Error(ctx, "Migration failed", "error", err) + os.Exit(1) + } + logger.Info(ctx, "Migration completed successfully") +} + +func doMigrate(ctx context.Context) error { err := dbConfig.ReadFiles() if err != nil { - logger.Error(ctx, "Fatal error", "error", err) - os.Exit(1) + return fmt.Errorf("reading config files: %w", err) } connection := db_session.NewProdFactory(dbConfig) defer func() { if closeErr := connection.Close(); closeErr != nil { logger.Error(ctx, "Failed to close database connection", "error", closeErr) } }() - if err := db.Migrate(connection.New(ctx)); err != nil { - logger.Error(ctx, "Migration failed", "error", err) - // Close connection before exit to avoid resource leak - if closeErr := connection.Close(); closeErr != nil { - logger.Error(ctx, "Failed to close database connection", "error", closeErr) - } - os.Exit(1) - } - - logger.Info(ctx, "Migration completed successfully") + return db.Migrate(connection.New(ctx)) }cmd/hyperfleet-api/servecmd/cmd.go (1)
76-93: Consider adding explicit signal handling for graceful shutdown.The
select {}on line 92 blocks indefinitely, causing the deferredtelemetry.Shutdown(lines 57-61) to rely on process termination signals for execution. While Go does run deferred functions before process exit, explicit signal handling (usingos/signalpackage) would improve clarity and allow for coordinated graceful shutdown of the API, metrics, and health check servers before telemetry is flushed.pkg/middleware/masking.go (2)
19-26: Consider adding defensive nil check for cfg parameter.If
cfgisnil, this constructor will panic when accessingcfg.Masking.Enabled. While the caller likely always provides a valid config, adding a nil check or panic with a clear message would make the code more defensive and easier to debug.🛡️ Proposed defensive nil check
func NewMaskingMiddleware(cfg *config.LoggingConfig) *MaskingMiddleware { + if cfg == nil { + panic("NewMaskingMiddleware: cfg cannot be nil") + } return &MaskingMiddleware{ enabled: cfg.Masking.Enabled, sensitiveHeaders: cfg.GetSensitiveHeadersList(), sensitiveFields: cfg.GetSensitiveFieldsList(), } }
114-123: Be aware: substring matching may produce false positives.The substring matching approach (line 118) will catch field name variants like
password,user_password,passwordHash, but may also mask unintended fields. For example, if"pass"is configured as a sensitive field, it would matchcompassorpassenger.This is a reasonable trade-off for broader coverage, but consider documenting this behavior or evaluating if exact matches should be required for certain field names.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (50)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/metrics_server.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/auth/helpers.gopkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.gopkg/errors/errors.gopkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/http.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/middleware/masking.gopkg/middleware/masking_test.gopkg/middleware/otel.gopkg/middleware/schema_validation.gopkg/services/cluster.gopkg/services/generic.gopkg/services/node_pool.gopkg/services/status_aggregation.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (5)
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/logging.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
🚧 Files skipped from review as they are similar to previous changes (16)
- pkg/services/cluster.go
- pkg/handlers/openapi.go
- pkg/telemetry/otel.go
- cmd/hyperfleet-api/server/routes.go
- pkg/handlers/helpers.go
- pkg/logger/logger_test.go
- pkg/handlers/metadata.go
- cmd/hyperfleet-api/server/healthcheck_server.go
- pkg/middleware/otel.go
- pkg/logger/context.go
- test/integration/integration_test.go
- pkg/db/db_session/test.go
- pkg/services/generic.go
- pkg/middleware/masking_test.go
- cmd/hyperfleet-api/server/metrics_server.go
- pkg/auth/helpers.go
🧰 Additional context used
📓 Path-based instructions (11)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
pkg/errors/errors.gopkg/db/context.gopkg/services/status_aggregation.gopkg/middleware/schema_validation.gopkg/logger/http.gopkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/handlers/framework.gocmd/hyperfleet-api/main.gotest/helper.gopkg/middleware/masking.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/nodepool_status.gocmd/hyperfleet-api/server/api_server.gopkg/db/migrations.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/environments/framework.gopkg/logger/ocm_bridge.gopkg/logger/logger.gocmd/hyperfleet-api/server/server.gopkg/api/error.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/db/context.gopkg/services/status_aggregation.gopkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/handlers/framework.gopkg/handlers/nodepool_status.gopkg/db/migrations.gopkg/db/transaction_middleware.go
pkg/services/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/services/**/*.go: Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Files:
pkg/services/status_aggregation.gopkg/services/node_pool.go
pkg/{dao,services}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Files:
pkg/services/status_aggregation.gopkg/services/node_pool.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/services/status_aggregation.gopkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/handlers/framework.gopkg/handlers/nodepool_status.go
pkg/**/*{auth,middleware}*.go
📄 CodeRabbit inference engine (AGENTS.md)
JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Files:
pkg/auth/authz_middleware_mock.gopkg/db/transaction_middleware.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/nodepool_status.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/nodepool_status.go
pkg/api/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Files:
pkg/api/error.go
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
pkg/errors/errors.gopkg/db/context.gopkg/services/status_aggregation.gopkg/auth/authz_middleware_mock.gopkg/handlers/cluster_status.gopkg/services/node_pool.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/handlers/framework.gocmd/hyperfleet-api/main.gotest/helper.godocs/logging.mdcmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/api_server.gopkg/db/migrations.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/environments/framework.gopkg/logger/ocm_bridge.gopkg/logger/logger.gocmd/hyperfleet-api/server/server.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
pkg/errors/errors.gopkg/db/context.gopkg/services/status_aggregation.gopkg/middleware/schema_validation.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/handlers/framework.gotest/helper.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/api_server.gopkg/db/migrations.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/environments/framework.gopkg/logger/ocm_bridge.gocmd/hyperfleet-api/server/server.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
pkg/errors/errors.gopkg/services/status_aggregation.gopkg/middleware/schema_validation.gopkg/handlers/framework.gocmd/hyperfleet-api/server/server.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
pkg/errors/errors.gopkg/db/context.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/environments/framework.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
pkg/errors/errors.gopkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/transaction_middleware.gocmd/hyperfleet-api/environments/framework.gopkg/api/error.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
pkg/errors/errors.gocmd/hyperfleet-api/main.gotest/helper.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
pkg/errors/errors.gotest/helper.gogo.modcmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
pkg/errors/errors.gotest/helper.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
pkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/transaction_middleware.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
pkg/db/context.gopkg/services/status_aggregation.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Applied to files:
pkg/services/status_aggregation.gopkg/handlers/cluster_status.gopkg/handlers/nodepool_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Applied to files:
pkg/services/status_aggregation.gopkg/handlers/cluster_status.gopkg/handlers/nodepool_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Applied to files:
pkg/services/status_aggregation.gopkg/handlers/cluster_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Applied to files:
pkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity
Applied to files:
pkg/services/node_pool.gocmd/hyperfleet-api/migrate/cmd.gopkg/handlers/nodepool_status.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
pkg/db/db_session/default.gopkg/db/db_session/testcontainer.gotest/helper.gocmd/hyperfleet-api/migrate/cmd.gogo.modpkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/db/db_session/default.gopkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/transaction_middleware.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
pkg/db/db_session/default.gocmd/hyperfleet-api/main.gotest/helper.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/migrate/cmd.gogo.modpkg/db/migrations.gocmd/hyperfleet-api/environments/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/db/db_session/default.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
pkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
pkg/db/db_session/testcontainer.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
test/helper.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
test/helper.gocmd/hyperfleet-api/server/server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
test/helper.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,db}/**/*.go : Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Applied to files:
pkg/db/migrations.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO interface methods must include Create, Get, List, Update, Delete operations with consistent signatures taking context.Context
Applied to files:
pkg/db/transaction_middleware.go
🧬 Code graph analysis (18)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(286-288)
pkg/services/status_aggregation.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
pkg/handlers/cluster_status.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
pkg/db/db_session/default.go (1)
pkg/logger/logger.go (3)
Info(262-264)Debug(258-260)Error(270-272)
pkg/db/db_session/testcontainer.go (3)
pkg/logger/logger.go (5)
Info(262-264)Errorf(286-288)Infof(278-280)Debug(258-260)Error(270-272)pkg/db/db_session/default.go (1)
Default(20-29)pkg/db/migrations.go (1)
Migrate(17-24)
pkg/handlers/framework.go (1)
pkg/logger/logger.go (2)
Info(262-264)Error(270-272)
cmd/hyperfleet-api/main.go (1)
pkg/logger/logger.go (4)
Error(270-272)LogConfig(25-32)FormatJSON(21-21)InitGlobalLogger(174-182)
test/helper.go (1)
pkg/logger/logger.go (7)
Error(270-272)Info(262-264)Debug(258-260)Warn(266-268)LogConfig(25-32)FormatText(19-19)InitGlobalLogger(174-182)
pkg/middleware/masking.go (1)
pkg/config/logging.go (1)
LoggingConfig(12-19)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (3)
pkg/middleware/masking.go (1)
MaskingMiddleware(13-17)pkg/logger/logger.go (1)
Info(262-264)pkg/logger/http.go (5)
HTTPMethod(10-12)HTTPPath(15-17)HTTPUserAgent(30-32)HTTPStatusCode(20-22)HTTPDuration(25-27)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (2)
Error(270-272)Info(262-264)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
pkg/handlers/nodepool_status.go (1)
pkg/logger/logger.go (1)
Warn(266-268)
cmd/hyperfleet-api/server/api_server.go (5)
pkg/logger/ocm_bridge.go (1)
NewOCMLoggerBridge(16-18)pkg/logger/logger.go (2)
Info(262-264)Error(270-272)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)cmd/hyperfleet-api/environments/types.go (1)
Database(36-38)pkg/db/session.go (1)
SessionFactory(12-20)
pkg/db/migrations.go (2)
pkg/errors/errors.go (1)
New(112-132)pkg/logger/logger.go (1)
Error(270-272)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(258-260)GetLogger(208-216)Info(262-264)Warn(266-268)Error(270-272)
pkg/logger/logger.go (2)
pkg/logger/context.go (6)
GetTraceID(69-72)GetSpanID(75-78)GetOperationID(61-66)GetClusterID(81-84)GetResourceType(87-90)GetResourceID(93-96)pkg/errors/errors.go (1)
New(112-132)
cmd/hyperfleet-api/server/server.go (1)
pkg/logger/logger.go (1)
Error(270-272)
pkg/api/error.go (1)
pkg/logger/logger.go (1)
Error(270-272)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
🔇 Additional comments (34)
pkg/handlers/nodepool_status.go (1)
101-104: LGTM - Properly structured warning log.The migration correctly uses the context-aware
logger.Warnwith structured fields (nodepool_id,error). The warning level is appropriate since the aggregation failure is non-fatal and the request should still succeed.pkg/handlers/cluster_status.go (1)
101-104: LGTM - Consistent with nodepool_status handler pattern.The logging migration mirrors the pattern in
nodepool_status.go, maintaining consistency across status handlers. Context-aware logging with structured fields is correctly implemented.cmd/hyperfleet-api/environments/framework.go (1)
68-117: Logging migration in Initialize() looks correct.The use of
context.Background()is appropriate for startup/initialization code that runs outside request context. Thelogger.Errorffollowed byos.Exit(1)pattern correctly replaces the previous fatal logging behavior.pkg/db/db_session/default.go (2)
11-17: Good import aliasing to avoid collision.Using
gormloggeras an alias forgorm.io/gorm/loggeravoids collision with the hyperfleetloggerpackage. This is a clean approach.
144-153: LGTM - GORM logger configuration updated correctly.The
gormlogger.Silentreference correctly uses the aliased import for the GORM logger level.pkg/logger/http.go (1)
1-49: Well-structured HTTP logging helpers.The attribute helpers follow slog conventions and provide a clean API for structured HTTP request/response logging. The separation of request and response attributes is a good design choice.
Consider adding
HTTPRemoteAddrorHTTPClientIPattributes for request tracing in future iterations, as client identification can be valuable for debugging and security auditing.pkg/db/db_session/testcontainer.go (2)
41-111: LGTM - Proper migration to structured logging.The initialization flow correctly uses the new context-aware logger with appropriate error handling. The
os.Exit(1)pattern afterlogger.Errorfis acceptable for startup failures that should prevent the application from running.
155-175: Good use of structured logging with key-value pairs.The
ResetDBfunction correctly uses the structured logging API with inline fields ("table","error"), which aligns with the coding guidelines for context-aware log fields.pkg/logger/logger.go (2)
43-83: Well-designed custom slog handler with context enrichment.The
HyperFleetHandlercorrectly implements theslog.Handlerinterface with proper delegation to the underlying handler. The safe type assertion forslog.Level(lines 55-59) addresses the previous review feedback. The context field extraction (trace_id, span_id, operation_id, etc.) aligns well with the coding guidelines for structured logging.
166-182: Thread-safe global logger initialization.The use of
sync.Onceensures the logger is initialized exactly once, addressing the previous review feedback about race conditions. TheloggerMutexinsideinitOnce.Dois technically redundant sincesync.Oncealready provides synchronization, but it doesn't cause issues and maintains consistency withReconfigureGlobalLogger.pkg/auth/authz_middleware_mock.go (1)
17-22: LGTM - Proper structured logging migration.The mock middleware correctly uses
r.Context()for context-aware logging with structured fields. This aligns with the coding guidelines for using context values for request-scoped data.pkg/api/error.go (2)
40-46: LGTM - Request context properly used for tracing.The previous review feedback has been addressed. Using
r.Context()preserves trace IDs, span IDs, and operation IDs from the request context, maintaining observability. Based on learnings, this aligns with using context values for request-scoped data.
88-112: Appropriate use of Background context in init().Using
context.Background()in theinit()function is correct since there's no request context available during package initialization. The error logging beforeos.Exit(1)provides visibility into initialization failures.pkg/db/transaction_middleware.go (1)
14-29: LGTM - Correct transaction management with proper error handling.The middleware correctly:
- Uses
r.Context()for logging whenNewContextfails (addressing past review feedback)- Assigns the transaction context to the request via
r.WithContext(ctx)- Defers
Resolveto handle commit/rollback on request completionThis aligns with the coding guidelines that database transactions are automatically managed by TransactionMiddleware.
pkg/services/status_aggregation.go (1)
142-142: LGTM! Structured logging correctly implemented.The migration to structured logging with
logger.Warnproperly uses context and key-value pairs for both the missing adapter warning and stale generation scenarios. The structured fields (adapter,observed_generation,expected_generation) enable better queryability and align with the project's logging specification.Based on learnings, this follows the requirement to use structured logging via logger with context-aware log fields.
Also applies to: 149-152
README.md (1)
158-158: LGTM! Documentation link appropriately added.The new logging documentation reference complements the broader logging infrastructure introduced in this PR.
pkg/middleware/schema_validation.go (1)
20-20: LGTM! Context-aware structured logging correctly implemented.The migration replaces per-request logger initialization with centralized logger calls, properly using
r.Context()for request-scoped data. Log levels are appropriately chosen (Info for validation errors, Error for encoding failures, Warn for close errors), and structured fields enable better queryability.Based on learnings, this correctly uses context values for passing request-scoped data.
Also applies to: 26-30, 53-54
docs/logging.md (1)
1-509: Excellent comprehensive logging documentation.This documentation provides thorough coverage of the logging system, including architecture, configuration, usage patterns, and best practices. The examples are practical and well-explained, particularly:
- Clear middleware chain visualization
- Concrete log output examples for different scenarios
- Security guidance on data masking
- Troubleshooting section for common issues
The documentation will serve as a valuable reference for developers working with the HyperFleet API logging system.
pkg/db/migrations.go (1)
30-39: LGTM! Structured logging with context properly implemented.The migration error handling now uses the new slog-based logger with structured fields (
migration_id,error), and the context is correctly passed tosessionFactory.New(ctx).cmd/hyperfleet-api/main.go (2)
54-66: Good early logger initialization pattern.Initializing the logger before any logging ensures consistent log output. The configuration with JSON format and INFO level provides sensible defaults before environment-specific configuration is loaded by subcommands.
68-74: LGTM!Graceful fallback to "unknown" when hostname retrieval fails is appropriate for non-critical logging metadata.
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (1)
15-57: LGTM! Clean middleware implementation with proper masking integration.The middleware correctly accepts the masker as a parameter (addressing the previous per-request allocation concern), skips noisy health check logging, and captures request/response metrics with structured logging.
test/helper.go (2)
72-74: Good test logger initialization with text format for readability.Initializing the logger early and using text format for tests improves debugging experience. The static hostname ensures deterministic test output.
544-555: LGTM!Test logger configuration with text format, static hostname, and "test" version provides consistent and readable output for debugging.
cmd/hyperfleet-api/server/api_server.go (3)
39-56: LGTM! Authentication handler properly wired with OCM logger bridge.The
NewOCMLoggerBridge()provides compatibility with the OCM SDK's logging interface while routing logs through the centralized slog-based logger.
105-128: LGTM!Serve method properly logs TLS configuration status with bind address for operational visibility.
137-152: LGTM!Start method properly handles startup errors and database connection cleanup with structured logging.
cmd/hyperfleet-api/servecmd/cmd.go (2)
95-138: LGTM! Logger reconfiguration properly handles thesync.Oncelimitation.Using
ReconfigureGlobalLoggerinstead ofInitGlobalLoggercorrectly addresses the previous issue where the default logger frommain.gocouldn't be updated. The fallback pattern for parsing errors ensures the server starts even with invalid configuration.
50-66: OpenTelemetry initialization with proper shutdown handling.Implementation correctly uses conditional initialization, properly handles deferred shutdown with nil checks (telemetry.Shutdown returns nil if TracerProvider is nil), and logs both success and disabled states. Structured logging is automatically applied via the HyperFleetHandler which enriches all logs with context-aware fields including operation_id, trace_id, span_id, and component metadata. The code is well-implemented.
pkg/middleware/masking.go (2)
28-44: LGTM! Header masking implementation is correct.The method correctly:
- Guards with the enabled flag
- Creates a new header map to avoid modifying the original
- Uses case-insensitive matching for sensitive headers
- Replaces sensitive values while preserving others
69-102: Excellent recursive masking implementation.The recursive masking correctly handles:
- Top-level maps and arrays via type switch
- Nested objects and arrays
- Array elements that are maps
- Sensitive field detection at any nesting level
The implementation comprehensively masks sensitive data in complex JSON structures.
pkg/logger/ocm_bridge.go (3)
20-38: Correct context-aware logging bridge implementation.The logging methods correctly:
- Accept and pass through context for request-scoped logging
- Bridge printf-style formatting to slog using
fmt.Sprintf- Use the global logger via thread-safe
GetLogger()- Implement the OCM SDK logger interface
Based on learnings, this properly uses context-aware logging with operation ID, account ID, and transaction ID when present in the context.
40-44: Note: Fatal terminates the process immediately.The
Fatalmethod correctly logs the fatal message and then callsos.Exit(1), which immediately terminates the process. This bypasses deferred function calls and cleanup handlers.This is the expected behavior for fatal errors, but ensure Fatal is only called for truly unrecoverable errors where immediate termination is appropriate.
46-64: Appropriate use of context.Background() for level checks.The level-enabled methods correctly use
context.Background()for checking if a log level is enabled. This is appropriate because:
- Log level configuration is typically a global setting, not context-specific
- The checks don't need request-scoped context values
- This resolves the past context inconsistency issue
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
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 (2)
pkg/db/db_session/default.go (1)
100-120: Fix context propagation to preserve request-scoped data.Creating a new
context.Background()on line 101 breaks the context chain. SincewaitForNotificationis called fromnewListener(line 136), which receives a context parameter, this loses critical request-scoped fields (operation ID, account ID, transaction ID) that should propagate through the logging calls.Based on learnings, as per coding guidelines for
pkg/db/**/*.go.🔄 Proposed fix to pass context through the call chain
Update the function signature to accept context:
-func waitForNotification(l *pq.Listener, callback func(id string)) { - ctx := context.Background() +func waitForNotification(ctx context.Context, l *pq.Listener, callback func(id string)) { for { select { case n := <-l.Notify:And update the call site on line 136:
logger.Info(ctx, "Starting channeling monitor", "channel", channel) for { - waitForNotification(listener, callback) + waitForNotification(ctx, listener, callback) }pkg/auth/helpers.go (1)
12-22: Enhance error logging with structured fields.The current implementation logs
err.Error()as a plain string, which loses the structured information available in theServiceErrortype. This makes log filtering, alerting, and correlation more difficult.♻️ Proposed refactor to use structured logging
func handleError(ctx context.Context, w http.ResponseWriter, code errors.ServiceErrorCode, reason string) { operationID := logger.GetOperationID(ctx) err := errors.New(code, "%s", reason) if err.HttpCode >= 400 && err.HttpCode <= 499 { - logger.Info(ctx, err.Error()) + logger.Info(ctx, "Client error during authentication", + "error_code", err.Code, + "reason", err.Reason, + "http_code", err.HttpCode, + "operation_id", operationID) } else { - logger.Error(ctx, err.Error()) + logger.Error(ctx, "Server error during authentication", + "error_code", err.Code, + "reason", err.Reason, + "http_code", err.HttpCode, + "operation_id", operationID) } writeJSONResponse(w, err.HttpCode, err.AsOpenapiError(operationID)) }Based on coding guidelines requiring structured logging with context-aware log fields.
🤖 Fix all issues with AI agents
In @cmd/hyperfleet-api/server/logging/request_logging_middleware.go:
- Around line 59-77: The responseWriter's statusCode is being initialized to
http.StatusOK elsewhere, making the check in responseWriter.Write (if
rw.statusCode == 0 { rw.statusCode = http.StatusOK }) dead; fix by removing the
explicit initialization so statusCode defaults to 0 and the Write method
correctly sets it to 200 when WriteHeader wasn't called—locate the
responseWriter construction/initialization and stop pre-setting statusCode to
http.StatusOK (keep the WriteHeader and Write methods as-is), ensuring the
wrapper follows the standard pattern of starting with statusCode == 0.
In @pkg/errors/errors.go:
- Line 9: The build is failing because the generated OpenAPI package referenced
by the import "github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi"
is missing; run the repository code generator (make generate or make
generate-all) which uses the generate target (Dockerfile.openapi) to recreate
pkg/api/openapi, then re-run your build so the symbols used in errors.go (the
openapi models referenced on lines ~154–184) resolve.
In @pkg/handlers/framework.go:
- Around line 31-40: In handleError, replace the current
logger.Info/Logger.Error calls that only pass err.Error() with structured
logging that includes operationID and ServiceError fields (err.Code,
err.HttpCode, err.Reason) so logs are queryable; update the logger.Info and
logger.Error invocations (inside function handleError) to pass a message plus
these structured fields (operationID, code, http_code, reason) and keep the
existing writeJSONResponse call unchanged.
In @pkg/logger/context.go:
- Around line 14-22: OpIDHeader is currently typed as contextKey but represents
an HTTP header name; change it to a plain string constant (e.g., OpIDHeader
string = "X-Operation-ID") or move it out of the contextKey block so it is not
part of the contextKey type, and keep the other keys (OpIDKey, TraceIDCtxKey,
SpanIDCtxKey, etc.) as contextKey; update any uses of OpIDHeader to expect a
string header name rather than a context key.
In @pkg/middleware/masking.go:
- Around line 50-67: MaskBody currently returns the original body when
json.Unmarshal or json.Marshal fails, which can leak sensitive data; change
MaskBody so that when m.enabled is true and JSON parsing/marshaling fails it
does NOT return the raw body but instead (1) logs a warning and returns a
deterministic redacted placeholder (e.g., "[REDACTED]" or "{}") and/or (2) calls
a new fallback function (e.g., maskTextFallback) that applies simple text-based
regex heuristics to redact emails, credit-card-like sequences, API keys/tokens,
and form-encoded key-values before returning the redacted bytes; implement
maskTextFallback and invoke it from MaskBody on both json.Unmarshal and
json.Marshal error paths while preserving existing behavior when m.enabled is
false and still using maskRecursive for successful JSON parsing.
In @pkg/middleware/otel.go:
- Around line 18-50: OTelMiddleware currently enriches context with trace and
span IDs via logger.WithTraceID and logger.WithSpanID; add analogous calls
logger.WithAccountID and logger.WithTransactionID inside the enrichedHandler
before r = r.WithContext(ctx) so downstream logs include those fields. Extract
account_id and transaction_id from the incoming request (e.g.,
r.Header.Get("X-Account-ID") / "X-Transaction-ID" or existing context values set
earlier) and only add them when non-empty; ensure names match your logger
helpers and keep operation_id enrichment as-is.
🧹 Nitpick comments (11)
pkg/errors/errors.go (1)
117-118: Consider propagating context to error constructors.Using
context.Background()here means the error log won't includeoperation_id,trace_id, or other context-aware fields, making it harder to correlate with the originating request.Since
New()and its wrapper functions (e.g.,NotFound,GeneralError) don't currently accept a context parameter, this may require a broader refactoring. However, for better observability, consider:
- Adding a context parameter to error constructors
- Or, deferring the logging to the error handler (where context is available)
🔧 Potential refactor to accept context
Example approach (requires updating all error constructor call sites):
-func New(code ServiceErrorCode, reason string, values ...interface{}) *ServiceError { +func New(ctx context.Context, code ServiceErrorCode, reason string, values ...interface{}) *ServiceError { var err *ServiceError exists, err := Find(code) if !exists { - ctx := context.Background() logger.Errorf(ctx, "Undefined error code used: %d", code) err = &ServiceError{ Code: ErrorGeneral, Reason: "Unspecified error", HttpCode: 500, } } // ... }Then update wrapper functions:
-func NotFound(reason string, values ...interface{}) *ServiceError { - return New(ErrorNotFound, reason, values...) +func NotFound(ctx context.Context, reason string, values ...interface{}) *ServiceError { + return New(ctx, ErrorNotFound, reason, values...) }cmd/hyperfleet-api/server/healthcheck_server.go (1)
43-63: Consider using structured logging for consistency.The changes correctly replace glog with the centralized logger. However, the formatted string logging (
logger.Infof) could be enhanced with structured key-value pairs for better log parsing and filtering.♻️ Optional refactor to structured logging
func (s healthCheckServer) Start() { ctx := context.Background() var err error if env().Config.HealthCheck.EnableHTTPS { if env().Config.Server.HTTPSCertFile == "" || env().Config.Server.HTTPSKeyFile == "" { check( fmt.Errorf("unspecified required --https-cert-file, --https-key-file"), "Can't start https server", ) } // Serve with TLS - logger.Infof(ctx, "Serving HealthCheck with TLS at %s", env().Config.HealthCheck.BindAddress) + logger.Info(ctx, "Serving HealthCheck with TLS", + "bind_address", env().Config.HealthCheck.BindAddress, + "tls_enabled", true) err = s.httpServer.ListenAndServeTLS(env().Config.Server.HTTPSCertFile, env().Config.Server.HTTPSKeyFile) } else { - logger.Infof(ctx, "Serving HealthCheck without TLS at %s", env().Config.HealthCheck.BindAddress) + logger.Info(ctx, "Serving HealthCheck without TLS", + "bind_address", env().Config.HealthCheck.BindAddress, + "tls_enabled", false) err = s.httpServer.ListenAndServe() } check(err, "HealthCheck server terminated with errors") - logger.Info(ctx, "HealthCheck server terminated") + logger.Info(ctx, "HealthCheck server terminated", "server", "healthcheck") }Based on coding guidelines encouraging structured logging with key-value pairs for better observability.
cmd/hyperfleet-api/migrate/cmd.go (1)
33-56: LGTM! Proper resource management and logging.The migration to structured logging is well-implemented:
- Background context created at start (line 33)
- Structured logging throughout with appropriate log levels
- Success confirmation added (line 56)
The dual connection-close pattern (defer + explicit close before os.Exit) is correct:
- Defer (lines 41-45) handles cleanup on success
- Explicit close (lines 50-52) ensures cleanup before
os.Exit(1)since defers don't run when the process exitsThis is the proper pattern for cobra command handlers that use
os.Exit.📝 Optional: Add clarifying comment
Consider adding a comment explaining why connection cleanup appears twice:
defer func() { + // Cleanup on successful completion (defers don't run on os.Exit) if closeErr := connection.Close(); closeErr != nil { logger.Error(ctx, "Failed to close database connection", "error", closeErr) } }() if err := db.Migrate(connection.New(ctx)); err != nil { logger.Error(ctx, "Migration failed", "error", err) - // Close connection before exit to avoid resource leak + // Explicit close required before os.Exit (bypasses defers) if closeErr := connection.Close(); closeErr != nil {This clarifies the pattern for future maintainers.
cmd/hyperfleet-api/main.go (1)
25-52: LGTM with optional enhancement opportunity.The initialization flow correctly prioritizes logger setup before any logging occurs. Flag parsing and error handling are properly routed through the centralized logger.
Optional: Consider passing context to commands
The context created on line 28 is currently only used in error handlers. If subcommands need context for structured logging (as per the coding guidelines), consider setting it on the Cobra command:
func main() { // Initialize logger first (before any logging occurs) initDefaultLogger() ctx := context.Background() // Parse flags (needed for cobra compatibility) if err := flag.CommandLine.Parse([]string{}); err != nil { logger.Error(ctx, "Failed to parse flags", "error", err) os.Exit(1) } rootCmd := &cobra.Command{ Use: "hyperfleet", Long: "hyperfleet serves as a template for new microservices", } + rootCmd.SetContext(ctx) // All subcommands under root migrateCmd := migrate.NewMigrateCommand() serveCmd := servecmd.NewServeCommand()cmd/hyperfleet-api/servecmd/cmd.go (1)
122-122: Consider logging hostname resolution failure.The error from
os.Hostname()is silently ignored. While an empty hostname is acceptable fallback behavior, logging a debug message when hostname resolution fails would aid troubleshooting in containerized environments where hostname configuration may be significant.🔧 Optional enhancement
// Get hostname - hostname, _ := os.Hostname() + hostname, err := os.Hostname() + if err != nil { + logger.Debug(ctx, "Failed to resolve hostname", "error", err) + }pkg/middleware/masking.go (1)
13-17: Optional: Extract redaction string as a constant.The redaction placeholder
"***REDACTED***"is duplicated inMaskHeaders(line 38) andmaskMapRecursive(line 85). Consider extracting it as a package-level constant to improve maintainability.♻️ Suggested refactor
+const redactionPlaceholder = "***REDACTED***" + // MaskingMiddleware handles sensitive data masking for logging type MaskingMiddleware struct { enabled bool sensitiveHeaders []string sensitiveFields []string }Then update usage:
func (m *MaskingMiddleware) MaskHeaders(headers http.Header) http.Header { // ... for key, values := range headers { if m.isSensitiveHeader(key) { - masked[key] = []string{"***REDACTED***"} + masked[key] = []string{redactionPlaceholder} } else { masked[key] = values } } // ... }func (m *MaskingMiddleware) maskMapRecursive(data map[string]interface{}) { for key, value := range data { if m.isSensitiveField(key) { - data[key] = "***REDACTED***" + data[key] = redactionPlaceholder continue } // ... } }Also applies to: 28-44, 82-87
pkg/config/logging.go (1)
103-125: Optional: Filter empty strings from parsed lists.The
GetSensitiveHeadersListandGetSensitiveFieldsListmethods trim whitespace but don't filter empty strings. If the configuration contains consecutive commas (e.g.,"Authorization,,Cookie"), the resulting slice will contain empty strings, which could cause false positives in sensitivity checks.♻️ Suggested enhancement
func (l *LoggingConfig) GetSensitiveHeadersList() []string { if l.Masking.SensitiveHeaders == "" { return []string{} } headers := strings.Split(l.Masking.SensitiveHeaders, ",") + result := make([]string, 0, len(headers)) for i := range headers { headers[i] = strings.TrimSpace(headers[i]) + if headers[i] != "" { + result = append(result, headers[i]) + } } - return headers + return result } func (l *LoggingConfig) GetSensitiveFieldsList() []string { if l.Masking.SensitiveFields == "" { return []string{} } fields := strings.Split(l.Masking.SensitiveFields, ",") + result := make([]string, 0, len(fields)) for i := range fields { fields[i] = strings.TrimSpace(fields[i]) + if fields[i] != "" { + result = append(result, fields[i]) + } } - return fields + return result }pkg/logger/context.go (1)
60-66: Optional: Inconsistent return signature in GetOperationID.
GetOperationIDreturns onlystring, while all otherGet*functions (GetTraceID,GetSpanID, etc.) follow the standard Go idiom of returning(string, bool). This inconsistency makes it impossible for callers to distinguish between "operation ID not present in context" and "operation ID is an empty string."Consider aligning with the other getters for API consistency:
♻️ Suggested refactor
-// GetOperationID retrieves operation ID from context -func GetOperationID(ctx context.Context) string { - if opID, ok := ctx.Value(OpIDKey).(string); ok { - return opID - } - return "" -} +// GetOperationID retrieves operation ID from context +func GetOperationID(ctx context.Context) (string, bool) { + opID, ok := ctx.Value(OpIDKey).(string) + return opID, ok +}Note: This is a breaking API change, so evaluate whether existing callers can be updated.
pkg/logger/logger.go (3)
44-48: Consider adding nil check forcfgparameter.If
NewHyperFleetHandleris called with a nil config, the function will panic when accessingcfg.Level. Adding a guard would make the API more defensive.🛠️ Suggested fix
func NewHyperFleetHandler(cfg *LogConfig) *HyperFleetHandler { + if cfg == nil { + cfg = &LogConfig{ + Level: slog.LevelInfo, + Format: FormatJSON, + Output: os.Stdout, + } + } var baseHandler slog.Handler opts := &slog.HandlerOptions{
145-164: Consider filteringlog/sloginternal frames from stack trace.The filter excludes
runtime.andtesting.frames but may include internallog/slogframes which aren't useful for debugging application errors.🛠️ Suggested enhancement
if !strings.Contains(frame.Function, "runtime.") && - !strings.Contains(frame.Function, "testing.") { + !strings.Contains(frame.Function, "testing.") && + !strings.Contains(frame.Function, "log/slog.") { stackTrace = append(stackTrace,
265-279: Formatted variants (*ffunctions) lose structured logging benefits.These functions format args into the message string, losing the key-value structure that
slogis designed for. Per coding guidelines emphasizing structured logging, consider adding a doc comment warning users to prefer the non-formatted variants with structured args.📝 Suggested documentation
+// Debugf logs a debug message with formatted string. +// Prefer Debug() with structured args (e.g., slog.String("key", "value")) +// for better log analysis and querying capabilities. func Debugf(ctx context.Context, format string, args ...interface{}) { GetLogger().DebugContext(ctx, fmt.Sprintf(format, args...)) } +// Infof logs an info message with formatted string. +// Prefer Info() with structured args for better log analysis. func Infof(ctx context.Context, format string, args ...interface{}) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (54)
README.mdcmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/servecmd/cmd.gocmd/hyperfleet-api/server/api_server.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/server/logging/formatter.gocmd/hyperfleet-api/server/logging/formatter_json.gocmd/hyperfleet-api/server/logging/logging.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gocmd/hyperfleet-api/server/logging/responseinfo.gocmd/hyperfleet-api/server/logging/writer.gocmd/hyperfleet-api/server/metrics_server.gocmd/hyperfleet-api/server/routes.gocmd/hyperfleet-api/server/server.godocs/logging.mdgo.modpkg/api/error.gopkg/auth/authz_middleware_mock.gopkg/auth/helpers.gopkg/config/config.gopkg/config/logging.gopkg/config/logging_test.gopkg/db/context.gopkg/db/db_session/default.gopkg/db/db_session/test.gopkg/db/db_session/testcontainer.gopkg/db/migrations.gopkg/db/transaction_middleware.gopkg/errors/errors.gopkg/handlers/cluster_status.gopkg/handlers/framework.gopkg/handlers/helpers.gopkg/handlers/metadata.gopkg/handlers/nodepool_status.gopkg/handlers/openapi.gopkg/logger/context.gopkg/logger/http.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/ocm_bridge.gopkg/logger/operationid_middleware.gopkg/middleware/masking.gopkg/middleware/masking_test.gopkg/middleware/otel.gopkg/middleware/schema_validation.gopkg/services/cluster.gopkg/services/generic.gopkg/services/node_pool.gopkg/services/status_aggregation.gopkg/telemetry/otel.gotest/helper.gotest/integration/integration_test.go
💤 Files with no reviewable changes (6)
- cmd/hyperfleet-api/server/logging/writer.go
- cmd/hyperfleet-api/server/logging/logging.go
- cmd/hyperfleet-api/server/logging/formatter.go
- cmd/hyperfleet-api/server/logging/formatter_json.go
- cmd/hyperfleet-api/server/logging/responseinfo.go
- pkg/logger/operationid_middleware.go
🧰 Additional context used
📓 Path-based instructions (12)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Files:
pkg/handlers/openapi.gocmd/hyperfleet-api/migrate/cmd.gopkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/metrics_server.gopkg/db/context.gotest/helper.gopkg/logger/logger_test.gopkg/telemetry/otel.gopkg/auth/helpers.gopkg/middleware/otel.gocmd/hyperfleet-api/server/server.gopkg/services/generic.gopkg/handlers/helpers.gopkg/handlers/nodepool_status.gopkg/middleware/schema_validation.gopkg/db/migrations.gopkg/config/config.gopkg/handlers/cluster_status.gocmd/hyperfleet-api/server/api_server.gopkg/errors/errors.gopkg/handlers/metadata.gopkg/config/logging.gocmd/hyperfleet-api/main.gopkg/logger/http.gopkg/services/cluster.gocmd/hyperfleet-api/server/routes.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/middleware/masking.gopkg/api/error.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/services/status_aggregation.gopkg/middleware/masking_test.gocmd/hyperfleet-api/servecmd/cmd.gopkg/logger/context.gopkg/config/logging_test.gopkg/services/node_pool.gopkg/db/transaction_middleware.gopkg/handlers/framework.gotest/integration/integration_test.gopkg/logger/ocm_bridge.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/logger/logger.go
pkg/handlers/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Files:
pkg/handlers/openapi.gopkg/handlers/helpers.gopkg/handlers/nodepool_status.gopkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/handlers/framework.go
pkg/{dao,handlers}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Files:
pkg/handlers/openapi.gopkg/handlers/helpers.gopkg/handlers/nodepool_status.gopkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/handlers/framework.go
pkg/{handlers,services,dao}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Files:
pkg/handlers/openapi.gopkg/services/generic.gopkg/handlers/helpers.gopkg/handlers/nodepool_status.gopkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/services/cluster.gopkg/services/status_aggregation.gopkg/services/node_pool.gopkg/handlers/framework.go
pkg/{handlers,services,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Files:
pkg/handlers/openapi.gopkg/db/context.gopkg/services/generic.gopkg/handlers/helpers.gopkg/handlers/nodepool_status.gopkg/db/migrations.gopkg/handlers/cluster_status.gopkg/handlers/metadata.gopkg/services/cluster.gopkg/db/db_session/test.gopkg/services/status_aggregation.gopkg/services/node_pool.gopkg/db/transaction_middleware.gopkg/handlers/framework.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
pkg/**/*{auth,middleware}*.go
📄 CodeRabbit inference engine (AGENTS.md)
JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Files:
pkg/auth/authz_middleware_mock.gopkg/db/transaction_middleware.go
pkg/db/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use PostgreSQL 14.2 with GORM ORM for database operations
Files:
pkg/db/context.gopkg/db/migrations.gopkg/db/db_session/test.gopkg/db/transaction_middleware.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
pkg/{dao,db}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables
Files:
pkg/db/context.gopkg/db/migrations.gopkg/db/db_session/test.gopkg/db/transaction_middleware.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
pkg/services/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
pkg/services/**/*.go: Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Files:
pkg/services/generic.gopkg/services/cluster.gopkg/services/status_aggregation.gopkg/services/node_pool.go
pkg/{dao,services}/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Files:
pkg/services/generic.gopkg/services/cluster.gopkg/services/status_aggregation.gopkg/services/node_pool.go
pkg/api/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Files:
pkg/api/error.go
test/integration/**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Files:
test/integration/integration_test.go
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,db}/**/*.go : Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/migrate/cmd.gopkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/metrics_server.gopkg/db/context.gopkg/auth/helpers.gopkg/middleware/otel.gocmd/hyperfleet-api/server/server.gopkg/services/generic.gopkg/handlers/helpers.gopkg/middleware/schema_validation.gopkg/db/migrations.gocmd/hyperfleet-api/server/api_server.gopkg/errors/errors.gopkg/handlers/metadata.gopkg/services/cluster.gopkg/db/db_session/test.gopkg/api/error.gopkg/services/status_aggregation.gopkg/logger/context.gopkg/db/transaction_middleware.gopkg/handlers/framework.gotest/integration/integration_test.gopkg/logger/ocm_bridge.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Applied to files:
pkg/handlers/openapi.gotest/helper.gocmd/hyperfleet-api/server/api_server.gopkg/errors/errors.gogo.modtest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/migrate/cmd.gopkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/metrics_server.gopkg/db/context.godocs/logging.mdtest/helper.gopkg/logger/logger_test.gopkg/telemetry/otel.gopkg/auth/helpers.gocmd/hyperfleet-api/server/server.gopkg/services/generic.gopkg/handlers/helpers.gopkg/middleware/schema_validation.gopkg/db/migrations.gopkg/handlers/cluster_status.gocmd/hyperfleet-api/server/api_server.gopkg/errors/errors.gopkg/handlers/metadata.gopkg/config/logging.gocmd/hyperfleet-api/main.gopkg/services/cluster.gocmd/hyperfleet-api/server/routes.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/healthcheck_server.gopkg/api/error.gopkg/services/status_aggregation.gocmd/hyperfleet-api/servecmd/cmd.gopkg/logger/context.gopkg/config/logging_test.gopkg/services/node_pool.gopkg/db/transaction_middleware.gopkg/handlers/framework.gotest/integration/integration_test.gopkg/logger/ocm_bridge.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.gopkg/logger/logger.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Applied to files:
pkg/handlers/openapi.gotest/helper.gopkg/errors/errors.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)
Applied to files:
pkg/handlers/openapi.gopkg/auth/helpers.gocmd/hyperfleet-api/server/server.gopkg/handlers/helpers.gopkg/middleware/schema_validation.gopkg/errors/errors.gopkg/handlers/metadata.gopkg/api/error.gopkg/services/status_aggregation.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Applied to files:
pkg/handlers/openapi.gopkg/auth/helpers.gopkg/handlers/helpers.gocmd/hyperfleet-api/server/logging/request_logging_middleware.gopkg/handlers/framework.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Applied to files:
pkg/handlers/openapi.gopkg/db/db_session/default.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Applied to files:
pkg/handlers/openapi.gotest/helper.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/server/healthcheck_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.gocmd/hyperfleet-api/server/metrics_server.gotest/helper.gocmd/hyperfleet-api/server/server.gocmd/hyperfleet-api/server/api_server.gopkg/errors/errors.gocmd/hyperfleet-api/main.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/servecmd/cmd.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/server/metrics_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Applied to files:
pkg/handlers/openapi.gocmd/hyperfleet-api/migrate/cmd.gopkg/db/context.gopkg/db/migrations.gopkg/db/db_session/test.gopkg/db/transaction_middleware.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Applied to files:
pkg/handlers/openapi.gopkg/services/generic.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.gotest/helper.gocmd/hyperfleet-api/server/server.gopkg/db/migrations.gocmd/hyperfleet-api/main.gopkg/db/db_session/test.gocmd/hyperfleet-api/server/healthcheck_server.gocmd/hyperfleet-api/servecmd/cmd.gogo.modtest/integration/integration_test.gopkg/db/db_session/default.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gotest/helper.gopkg/db/migrations.gopkg/db/db_session/test.gogo.modpkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/db/migrations/**/*.go : Store spec and conditions as JSONB in PostgreSQL to enable complex field queries
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/db/migrations.gopkg/db/db_session/test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/telemetry/otel.gopkg/db/migrations.gopkg/services/cluster.gopkg/db/db_session/test.gopkg/services/status_aggregation.gogo.modtest/integration/integration_test.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/services/node_pool.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All database sessions must be retrieved from context via db.NewContext(ctx) rather than creating new database connections
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.gopkg/db/context.gopkg/db/migrations.gopkg/db/db_session/test.gopkg/api/error.gopkg/db/transaction_middleware.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : Always retrieve database sessions from context in DAO methods; never create direct gorm.Open() connections
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gopkg/db/context.gopkg/db/migrations.gopkg/db/db_session/test.gopkg/db/transaction_middleware.gopkg/db/db_session/default.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration
Applied to files:
cmd/hyperfleet-api/migrate/cmd.gocmd/hyperfleet-api/environments/framework.gotest/helper.gopkg/config/logging_test.gotest/integration/integration_test.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization
Applied to files:
pkg/auth/authz_middleware_mock.gocmd/hyperfleet-api/server/api_server.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must accept context.Context as the first parameter for transaction propagation
Applied to files:
cmd/hyperfleet-api/environments/framework.gopkg/db/context.gopkg/errors/errors.gopkg/api/error.gopkg/db/transaction_middleware.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Applied to files:
test/helper.gogo.mod
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Applied to files:
pkg/services/generic.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)
Applied to files:
pkg/handlers/nodepool_status.gopkg/handlers/cluster_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise
Applied to files:
pkg/handlers/nodepool_status.gopkg/handlers/cluster_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Applied to files:
pkg/handlers/cluster_status.gopkg/services/status_aggregation.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
Applied to files:
pkg/db/db_session/test.gotest/integration/integration_test.gopkg/db/db_session/testcontainer.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to pkg/dao/**/*.go : All DAO interface methods must include Create, Get, List, Update, Delete operations with consistent signatures taking context.Context
Applied to files:
pkg/db/transaction_middleware.go
📚 Learning: 2026-01-08T01:23:20.634Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.634Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation
Applied to files:
test/integration/integration_test.go
🧬 Code graph analysis (36)
pkg/handlers/openapi.go (1)
pkg/logger/logger.go (2)
Info(253-255)Error(261-263)
cmd/hyperfleet-api/migrate/cmd.go (4)
pkg/logger/logger.go (2)
Error(261-263)Info(253-255)pkg/db/db_session/default.go (1)
NewProdFactory(33-37)pkg/db/migrations.go (1)
Migrate(17-24)pkg/errors/errors.go (1)
New(112-132)
pkg/auth/authz_middleware_mock.go (1)
pkg/logger/logger.go (1)
Info(253-255)
cmd/hyperfleet-api/environments/framework.go (3)
pkg/logger/logger.go (4)
Infof(269-271)Errorf(277-279)Info(253-255)Error(261-263)cmd/hyperfleet-api/environments/types.go (2)
Database(36-38)Clients(67-69)pkg/db/session.go (1)
SessionFactory(12-20)
cmd/hyperfleet-api/server/metrics_server.go (2)
pkg/logger/logger.go (1)
Info(253-255)cmd/hyperfleet-api/server/server.go (1)
Server(13-18)
test/helper.go (2)
pkg/logger/logger.go (6)
Error(261-263)Info(253-255)Debug(249-251)Warn(257-259)LogConfig(25-32)InitGlobalLogger(170-181)cmd/hyperfleet-api/server/api_server.go (1)
NewAPIServer(30-101)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (11)
ParseLogLevel(210-223)Error(261-263)Errorf(277-279)LogFormat(15-15)FormatText(19-19)FormatJSON(21-21)ParseLogFormat(226-235)ParseLogOutput(238-247)Info(253-255)Debug(249-251)Warn(257-259)pkg/logger/context.go (6)
WithTraceID(25-27)WithSpanID(30-32)OpIDKey(15-15)WithClusterID(35-37)WithResourceType(40-42)WithResourceID(45-47)
pkg/auth/helpers.go (1)
pkg/logger/logger.go (2)
Info(253-255)Error(261-263)
pkg/middleware/otel.go (1)
pkg/logger/context.go (2)
WithTraceID(25-27)WithSpanID(30-32)
cmd/hyperfleet-api/server/server.go (1)
pkg/logger/logger.go (1)
Error(261-263)
pkg/handlers/helpers.go (1)
pkg/logger/logger.go (1)
Error(261-263)
pkg/handlers/nodepool_status.go (1)
pkg/logger/logger.go (1)
Warn(257-259)
pkg/middleware/schema_validation.go (1)
pkg/logger/logger.go (3)
Info(253-255)Error(261-263)Warn(257-259)
pkg/db/migrations.go (2)
pkg/errors/errors.go (1)
New(112-132)pkg/logger/logger.go (1)
Error(261-263)
pkg/config/config.go (1)
pkg/config/logging.go (2)
LoggingConfig(12-19)NewLoggingConfig(35-50)
pkg/handlers/cluster_status.go (1)
pkg/logger/logger.go (1)
Warn(257-259)
pkg/errors/errors.go (1)
pkg/logger/logger.go (1)
Errorf(277-279)
pkg/handlers/metadata.go (2)
pkg/logger/logger.go (1)
Error(261-263)pkg/api/error.go (1)
SendPanic(70-81)
cmd/hyperfleet-api/main.go (1)
pkg/logger/logger.go (4)
Error(261-263)LogConfig(25-32)FormatJSON(21-21)InitGlobalLogger(170-181)
pkg/services/cluster.go (1)
pkg/logger/logger.go (1)
Info(253-255)
pkg/db/db_session/test.go (2)
pkg/logger/logger.go (1)
Errorf(277-279)pkg/db/db_session/default.go (1)
Default(20-29)
cmd/hyperfleet-api/server/healthcheck_server.go (1)
pkg/logger/logger.go (2)
Infof(269-271)Info(253-255)
pkg/api/error.go (1)
pkg/logger/logger.go (1)
Error(261-263)
cmd/hyperfleet-api/server/logging/request_logging_middleware.go (3)
pkg/middleware/masking.go (1)
MaskingMiddleware(13-17)pkg/logger/logger.go (1)
Info(253-255)pkg/logger/http.go (5)
HTTPMethod(10-12)HTTPPath(15-17)HTTPUserAgent(30-32)HTTPStatusCode(20-22)HTTPDuration(25-27)
pkg/services/status_aggregation.go (1)
pkg/logger/logger.go (1)
Warn(257-259)
pkg/middleware/masking_test.go (2)
pkg/config/logging.go (2)
LoggingConfig(12-19)MaskingConfig(28-32)pkg/middleware/masking.go (1)
NewMaskingMiddleware(20-26)
cmd/hyperfleet-api/servecmd/cmd.go (3)
pkg/logger/logger.go (9)
Error(261-263)Warn(257-259)Info(253-255)ParseLogLevel(210-223)ParseLogFormat(226-235)FormatJSON(21-21)ParseLogOutput(238-247)LogConfig(25-32)ReconfigureGlobalLogger(186-191)cmd/hyperfleet-api/environments/framework.go (1)
Environment(54-56)pkg/telemetry/otel.go (2)
InitTraceProvider(16-57)Shutdown(60-65)
pkg/config/logging_test.go (1)
pkg/config/logging.go (2)
NewLoggingConfig(35-50)LoggingConfig(12-19)
pkg/services/node_pool.go (1)
pkg/logger/logger.go (1)
Info(253-255)
pkg/db/transaction_middleware.go (3)
pkg/logger/logger.go (1)
Error(261-263)pkg/errors/errors.go (1)
GeneralError(191-193)pkg/logger/context.go (1)
GetOperationID(61-66)
pkg/handlers/framework.go (1)
pkg/logger/logger.go (2)
Info(253-255)Error(261-263)
test/integration/integration_test.go (1)
pkg/logger/logger.go (2)
Infof(269-271)Warn(257-259)
pkg/logger/ocm_bridge.go (1)
pkg/logger/logger.go (5)
Debug(249-251)GetLogger(200-207)Info(253-255)Warn(257-259)Error(261-263)
pkg/db/db_session/default.go (1)
pkg/logger/logger.go (3)
Info(253-255)Debug(249-251)Error(261-263)
pkg/db/db_session/testcontainer.go (4)
pkg/logger/logger.go (5)
Info(253-255)Errorf(277-279)Infof(269-271)Debug(249-251)Error(261-263)pkg/errors/errors.go (1)
New(112-132)pkg/client/ocm/client.go (1)
Config(17-24)pkg/db/migrations.go (1)
Migrate(17-24)
pkg/logger/logger.go (1)
pkg/logger/context.go (6)
GetTraceID(69-72)GetSpanID(75-78)GetOperationID(61-66)GetClusterID(81-84)GetResourceType(87-90)GetResourceID(93-96)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go
[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)
(typecheck)
update update update Replace OCMLogger with logger update Use atomic.Value instead of sync.once,metux update
|
@coderabbitai review |
|
@coderabbitai summary |
✅ Actions performedSummary regeneration triggered. |
|
coderabbit does not work well. Close the PR and move to #31 |
Observability upgrade: migrates from glog to slog structured logging, adds OpenTelemetry distributed tracing, and implements data masking for sensitive data protection.
What's New
Structured Logging (slog)
OpenTelemetry Tracing
Data Masking
Documentation & Testing
Summary
@coderabbitai summary