Conversation
- Add custom PosthogLogger adapter to integrate with Atmos logging - Redirect PostHog errors to debug level instead of stdout/stderr - Ensure telemetry failures don't impact user experience - Add unit tests to verify logger behavior - Fix issue where PostHog was logging directly to stderr This addresses the issue where PostHog errors like '502 Bad Gateway' were appearing in user output and breaking CLI tests. Now all PostHog errors are properly handled through our logging system and only appear at debug level. Fixes DEV-3633 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds PostHog and Silent loggers, threads a telemetry Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as Atmos CLI
participant Telemetry as Telemetry Module
participant PH as PostHog Client
participant Logger as Selected Logger
User->>CLI: run command
CLI->>Telemetry: Capture(event)
Telemetry->>PH: NewClient(token, Config{Logger: Logger})
note right of Logger #E8F5E9: Logger = PosthogLogger (routes to Atmos log)\nor SilentLogger (no-op)
PH->>Logger: emit internal logs
Logger->>Telemetry: route messages (DEBUG, with posthog tags or no-op)
Telemetry->>PH: Enqueue(event)
CLI->>Telemetry: exit -> Close()
Telemetry->>PH: Flush/send queued events
PH->>Logger: emit send result logs
Logger->>CLI: debug-level output only (if enabled)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Use log.With('component', 'posthog') to add context to all PostHog messages
- Remove redundant message prefixes since component context identifies the source
- Add 'posthog_level' field to preserve PostHog's original log level in errors
- Update tests to verify component context appears in all log messages
- Ensure logger instances are created after log level changes in tests
This improves on the previous fix by using proper structured logging context
instead of message prefixes, making logs more consistent with Atmos conventions.
- Replace log.With('component', 'posthog') with log.WithPrefix('posthog')
- Cleaner output format: 'DEBU posthog: message' instead of K/V pairs
- Fix misleading 'Telemetry event captured' message timing
- Change to 'Telemetry event enqueued' since actual send happens on Close()
- Update tests to verify prefix appears in log output
This provides cleaner, more readable log output while still clearly
identifying PostHog messages with the 'posthog:' prefix.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
pkg/telemetry/telemetry_test.go (3)
316-375: Gate live PostHog integration test behind flag/env and avoid hardcoded token.Avoid external calls in unit CI and don’t commit secrets. Skip unless explicitly enabled and read token from env.
Apply:
func TestTelemetryPosthogIntegrationCaptureMethod(t *testing.T) { - // Use test PostHog integration token and valid endpoint. - token := TestPosthogIntegrationToken + if testing.Short() || os.Getenv("ATMOS_RUN_POSTHOG_INTEGRATION") != "1" { + t.Skipf("Skipping PostHog integration test (set ATMOS_RUN_POSTHOG_INTEGRRATION=1 to run).") + } + token := os.Getenv("POSTHOG_TEST_TOKEN") + if token == "" { + t.Skipf("Skipping: POSTHOG_TEST_TOKEN is not set.") + } endpoint := "https://us.i.posthog.com/"And add import:
import ( "errors" "fmt" + "os" "math/rand/v2" "runtime" "testing" )
382-387: Same gating for wrong-endpoint integration test.Mirror the guard and env handling here to prevent network calls by default.
func TestTelemetryPosthogIntegrationWrongEndpointCaptureMethod(t *testing.T) { - // Use test PostHog integration token but with incorrect endpoint. - token := TestPosthogIntegrationToken + if testing.Short() || os.Getenv("ATMOS_RUN_POSTHOG_INTEGRATION") != "1" { + t.Skipf("Skipping PostHog integration test (set ATMOS_RUN_POSTHOG_INTEGRATION=1 to run).") + } + token := os.Getenv("POSTHOG_TEST_TOKEN") + if token == "" { + t.Skipf("Skipping: POSTHOG_TEST_TOKEN is not set.") + }
32-32: Add ctrl.Finish (use t.Cleanup) after creating gomock controllersUnmet/overmet gomock expectations won't fail tests unless the controller is finished—add t.Cleanup(ctrl.Finish) (or defer ctrl.Finish) immediately after each controller creation.
- Affected call sites (fix these):
- pkg/telemetry/telemetry_test.go — lines: 32, 75, 121, 171, 222, 274, 326, 392
- pkg/telemetry/utils_test.go — lines: 27, 65, 114, 155, 178, 214, 270, 326, 389, 419
- Also convert inline uses like pager.NewMockPageCreator(gomock.NewController(t)) (e.g., internal/exec/describe_dependents_test.go at 132, 213, 261) to an assigned controller and finish it.
Apply this diff at each site:
ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish)pkg/telemetry/telemetry.go (1)
54-56: Fix properties type mismatch (compile-time).posthog.Capture.Properties is posthog.Properties; tests pass posthog.Properties. Current signature takes map[string]interface{}.
-// Capture sends a telemetry event to PostHog with the given event name and properties. +// Capture sends a telemetry event to PostHog with the given event name and properties. func (t *Telemetry) Capture(eventName string, properties map[string]interface{}) bool { +// Capture sends a telemetry event to PostHog with the given event name and properties. +// properties must be posthog.Properties to match the PostHog client API. +func (t *Telemetry) Capture(eventName string, properties posthog.Properties) bool {Alternatively, cast at callsite:
- Properties: properties, + Properties: posthog.Properties(properties),Pick one approach and keep tests consistent (they already use posthog.Properties).
🧹 Nitpick comments (8)
pkg/telemetry/telemetry_test.go (2)
19-20: Remove hardcoded token constant.Keep secrets out of VCS; rely on env as shown above.
-const ( - TestPosthogIntegrationToken = "phc_7s7MrHWxPR2if1DHHDrKBRgx7SvlaoSM59fIiQueexS" -) +// Integration token is supplied via POSTHOG_TEST_TOKEN when tests are explicitly enabled.
26-31: Use deterministic randomness or seed.Non-deterministic rand can complicate reproducing failures; either seed test-local RNG or use fixed values.
pkg/telemetry/telemetry.go (3)
72-77: Trap Close() errors at debug.Silent ignore can mask flush failures; log them at debug without user impact.
- defer func() { - // Ensure client close doesn't panic or output errors - if client != nil { - client.Close() - } - }() + defer func() { + // Ensure client close doesn't panic or output errors. + if client != nil { + if cerr := client.Close(); cerr != nil { + log.Debug("PostHog client close failed", "error", cerr) + } + } + }()
8-20: Deduplicate doc comments.Two identical blocks above TelemetryClientProvider. Keep one concise godoc.
-// TelemetryClientProvider is a function type that creates a PostHog client -// given a token and configuration. This allows for dependency injection -// and easier testing by providing mock implementations. -// TelemetryClientProvider is a function type that creates a PostHog client -// given a token and configuration. The configuration is passed by pointer to -// avoid copying large structs and to allow tests to modify it. +// TelemetryClientProvider creates a PostHog client given a token and configuration. +// The configuration is passed by pointer to avoid copying and to allow tests to modify it.
48-53: Godot: end comments with periods.Several comment lines end without periods; golangci-lint (godot) will complain.
Also applies to: 79-81, 91-93
pkg/telemetry/posthog_logger_test.go (2)
84-103: Restore original log level in SilentLogger test.Avoid cross-test level bleed.
func TestSilentLogger(t *testing.T) { - defer log.SetOutput(io.Discard) // Reset output after test + defer log.SetOutput(io.Discard) // Reset output after test + orig := log.GetLevel() + defer log.SetLevel(orig)
105-127: Same: restore level in DiscardLogger test.func TestDiscardLogger(t *testing.T) { - defer log.SetOutput(io.Discard) // Reset output after test + defer log.SetOutput(io.Discard) // Reset output after test + orig := log.GetLevel() + defer log.SetLevel(orig)pkg/telemetry/posthog_logger.go (1)
25-30: Godot: add periods to inline comments.Several comment lines are missing trailing periods; fix to satisfy golangci-lint godot.
- // Convert printf-style to structured logging + // Convert printf-style to structured logging. - // Convert printf-style to structured logging at debug level - // to avoid cluttering user output with telemetry info + // Convert printf-style to structured logging at debug level. + // To avoid cluttering user output with telemetry info. - // Convert printf-style to structured logging + // Convert printf-style to structured logging. - // Only log PostHog errors at debug level to avoid polluting user output. - // Telemetry failures should not impact the user experience. + // Only log PostHog errors at debug level to avoid polluting user output. + // Telemetry failures should not impact the user experience.Also applies to: 36-40, 44-47, 52-56
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
pkg/telemetry/posthog_logger.go(1 hunks)pkg/telemetry/posthog_logger_test.go(1 hunks)pkg/telemetry/telemetry.go(2 hunks)pkg/telemetry/telemetry_test.go(8 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags
Use interfaces for external dependencies to facilitate mocking
All code must pass golangci-lint checks
Follow Go's error handling idioms
Use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider using a custom error type for domain-specific errors
Follow standard Go coding style
Use gofmt and goimports to format code
Prefer short, descriptive variable names
Use snake_case for environment variables
Document all exported functions, types, and methods
Document complex logic with inline comments
Follow Go's documentation conventions
Use Viper for configuration management
Support configuration via files, environment variables, and flags
Follow the precedence order: flags > environment variables > config file > defaults
**/*.go: All comments in Go code must end with periods (enforced by golangci-lint godot).
Wrap all returned errors using static errors from the errors package; never return dynamic errors directly.
Always bind environment variables with viper.BindEnv() and provide ATMOS_ alternatives for each external var.
Separate structured logging from UI output: use stderr for prompts/errors to user; stdout only for data; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd or telemetry.CaptureCmdString and never capture user data.
Ensure cross-platform compatibility: prefer SDKs to external binaries, use filepath/os/runtime for portability, and add build constraints when needed.
Files:
pkg/telemetry/posthog_logger_test.gopkg/telemetry/telemetry.gopkg/telemetry/posthog_logger.gopkg/telemetry/telemetry_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for testing multiple scenarios
Include integration tests for command flows
Test CLI end-to-end when possible
Use test fixtures for complex inputs
Consider using testify/mock for creating mock implementations
**/*_test.go: Always use t.Skipf() with a reason for skipped tests; never use t.Skip() or reasonless t.Skipf().
Test files must mirror implementation structure and naming (e.g., aws_ssm_store_test.go).
Use table-driven unit tests and mock interfaces for external dependencies; target >80% coverage.
Files:
pkg/telemetry/posthog_logger_test.gopkg/telemetry/telemetry_test.go
pkg/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests reside under pkg/ alongside implementations.
Files:
pkg/telemetry/posthog_logger_test.gopkg/telemetry/telemetry_test.go
🧠 Learnings (4)
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
pkg/telemetry/posthog_logger_test.go
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*_test.go : Test both happy paths and error conditions
Applied to files:
pkg/telemetry/posthog_logger_test.go
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*_test.go : Consider using testify/mock for creating mock implementations
Applied to files:
pkg/telemetry/telemetry_test.go
📚 Learning: 2025-09-07T15:13:17.831Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T15:13:17.831Z
Learning: Applies to **/*_test.go : Use table-driven unit tests and mock interfaces for external dependencies; target >80% coverage.
Applied to files:
pkg/telemetry/telemetry_test.go
🧬 Code graph analysis (3)
pkg/telemetry/posthog_logger_test.go (1)
pkg/telemetry/posthog_logger.go (3)
NewPosthogLogger(19-23)NewSilentLogger(63-65)NewDiscardLogger(90-92)
pkg/telemetry/telemetry.go (1)
pkg/telemetry/posthog_logger.go (1)
NewPosthogLogger(19-23)
pkg/telemetry/posthog_logger.go (1)
pkg/logger/logger.go (1)
Logger(32-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: Summary
🔇 Additional comments (8)
pkg/telemetry/telemetry_test.go (2)
39-39: Good swap to gomock.Any() for config arg.This decouples tests from posthog.Config internals while keeping call counts precise.
Also applies to: 82-83, 128-128, 178-178, 229-229, 281-281, 333-333, 399-399
3-15: Confirmed — go.mod declares go 1.24.6 (>=1.22). math/rand/v2 is supported; no change required.pkg/telemetry/telemetry.go (1)
61-66: Nice: inject custom PostHog logger.This prevents stderr pollution and respects global log levels.
Confirm whether PostHog emits network issues via Warnf; if so, consider demoting Warnf to Debug to keep default/info clean.
pkg/telemetry/posthog_logger_test.go (2)
12-49: Solid coverage of log methods.Assertions catch prefix and error-level tagging.
129-171: Great: validates no stderr pollution at INFO, visible at DEBUG with metadata.Matches PR objectives.
pkg/telemetry/posthog_logger.go (3)
20-23: Prefix-based default logger is fine.Works with global level/output and keeps messages scoped.
33-40: Consider demoting Warnf to Debug (verify first).If PostHog uses Warnf for transient network issues, these would surface at default/info. Demote to Debug if that happens in practice.
58-66: No-op loggers look good.Silent/Discard implementations are simple and safe. Keep.
Also applies to: 94-108
… logging - Add `logging` field to TelemetrySettings to control PostHog SDK logging - Default to false for cleaner user experience - PostHog SDK uses SilentLogger when logging=false (default) - PostHog SDK uses PosthogLogger when logging=true - Support environment variable ATMOS_TELEMETRY_LOGGING - Remove omitempty tag from logging field to ensure consistent serialization - Add comprehensive tests for logging configuration - Telemetry collection remains independent of logging setting This allows users to keep telemetry enabled while suppressing PostHog's internal debug messages (network errors, buffer status, etc.) that can clutter logs. Users can enable PostHog logging when debugging telemetry issues by setting telemetry.logging=true or ATMOS_TELEMETRY_LOGGING=true. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (9)
pkg/schema/schema.go (1)
253-254: Make logging tag consistent with other telemetry fields.To avoid emitting
logging: falseon marshal and to match neighboring tags, addomitempty.- Logging bool `yaml:"logging" json:"logging" mapstructure:"logging"` + Logging bool `yaml:"logging,omitempty" json:"logging,omitempty" mapstructure:"logging"`pkg/telemetry/telemetry_logger_selection_test.go (2)
16-40: Deduplicate the two subtests to satisfy dupl lint and reduce noise.Refactor into a small helper; keep assertions unchanged.
func TestTelemetryLoggerSelectionBasedOnFlag(t *testing.T) { - // Test with logging enabled - should use PosthogLogger - t.Run("LoggingEnabled", func(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - // Create a custom mock provider to inspect the config - var capturedConfig *posthog.Config - mockProvider := func(token string, config *posthog.Config) (posthog.Client, error) { - capturedConfig = config - mockClient := mock_telemetry.NewMockClient(ctrl) - mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(1) - mockClient.EXPECT().Close().Return(nil).Times(1) - return mockClient, nil - } - - // Create telemetry with logging enabled - telemetry := NewTelemetry(true, "test-token", "https://test.com", "test-id", true, mockProvider) - success := telemetry.Capture("test", map[string]interface{}{}) - - assert.True(t, success) - assert.NotNil(t, capturedConfig) - assert.NotNil(t, capturedConfig.Logger) - // Verify it's a PosthogLogger by checking type - _, isPosthogLogger := capturedConfig.Logger.(*PosthogLogger) - assert.True(t, isPosthogLogger, "Should use PosthogLogger when logging is enabled") - }) - - // Test with logging disabled - should use SilentLogger - t.Run("LoggingDisabled", func(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - // Create a custom mock provider to inspect the config - var capturedConfig *posthog.Config - mockProvider := func(token string, config *posthog.Config) (posthog.Client, error) { - capturedConfig = config - mockClient := mock_telemetry.NewMockClient(ctrl) - mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(1) - mockClient.EXPECT().Close().Return(nil).Times(1) - return mockClient, nil - } - - // Create telemetry with logging disabled - telemetry := NewTelemetry(true, "test-token", "https://test.com", "test-id", false, mockProvider) - success := telemetry.Capture("test", map[string]interface{}{}) - - assert.True(t, success) - assert.NotNil(t, capturedConfig) - assert.NotNil(t, capturedConfig.Logger) - // Verify it's a SilentLogger by checking type - _, isSilentLogger := capturedConfig.Logger.(*SilentLogger) - assert.True(t, isSilentLogger, "Should use SilentLogger when logging is disabled") - }) + run := func(name string, logging bool) { + t.Run(name, func(t *testing.T) { + t.Helper() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + var capturedConfig *posthog.Config + mockProvider := func(token string, config *posthog.Config) (posthog.Client, error) { + capturedConfig = config + mockClient := mock_telemetry.NewMockClient(ctrl) + mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(1) + mockClient.EXPECT().Close().Return(nil).Times(1) + return mockClient, nil + } + telemetry := NewTelemetry(true, "test-token", "https://test.com", "test-id", logging, mockProvider) + success := telemetry.Capture("test", map[string]interface{}{}) + assert.True(t, success) + assert.NotNil(t, capturedConfig) + assert.NotNil(t, capturedConfig.Logger) + if logging { + _, isPosthogLogger := capturedConfig.Logger.(*PosthogLogger) + assert.True(t, isPosthogLogger, "Should use PosthogLogger when logging is enabled.") + } else { + _, isSilentLogger := capturedConfig.Logger.(*SilentLogger) + assert.True(t, isSilentLogger, "Should use SilentLogger when logging is disabled.") + } + }) + } + run("LoggingEnabled", true) + run("LoggingDisabled", false) }Also applies to: 43-67
12-14: Fix comment periods to satisfy godot.End sentences with periods.
-// TestTelemetryLoggerSelectionBasedOnFlag tests that the correct logger is selected -// based on the logging flag during client creation. +// TestTelemetryLoggerSelectionBasedOnFlag tests that the correct logger is selected. +// It is based on the logging flag during client creation. -// Verify it's a PosthogLogger by checking type +// Verify it's a PosthogLogger by checking type. -// Verify it's a SilentLogger by checking type +// Verify it's a SilentLogger by checking type. -// TestTelemetryConstructorWithLogging tests that the telemetry constructor correctly -// handles the logging parameter. +// TestTelemetryConstructorWithLogging tests that the telemetry constructor correctly. +// It handles the logging parameter.Also applies to: 38-38, 65-65, 70-72
pkg/telemetry/telemetry.go (2)
8-14: Remove duplicate doc comments.Two identical comment blocks for both the type and provider are repeated back‑to‑back.
-// TelemetryClientProvider is a function type that creates a PostHog client -// given a token and configuration. This allows for dependency injection -// and easier testing by providing mock implementations. -// TelemetryClientProvider is a function type that creates a PostHog client -// given a token and configuration. The configuration is passed by pointer to -// avoid copying large structs and to allow tests to modify it. +// TelemetryClientProvider is a function type that creates a PostHog client given a token and configuration. +// The configuration is passed by pointer to avoid copying and to allow tests to inspect/modify it. type TelemetryClientProvider func(string, *posthog.Config) (posthog.Client, error) -// PosthogClientProvider is the default implementation of TelemetryClientProvider -// that creates a real PostHog client using the provided token and configuration. -// PosthogClientProvider is the default implementation of TelemetryClientProvider -// that creates a real PostHog client using the provided token and configuration. +// PosthogClientProvider is the default implementation of TelemetryClientProvider that creates a real PostHog client. func PosthogClientProvider(token string, config *posthog.Config) (posthog.Client, error) {Also applies to: 16-22
63-71: Tighten comments for godot and log close errors at debug.End sentences with periods and surface Close errors at debug without leaking to users.
- // Create PostHog client using the provided client provider with custom logger - // This ensures PostHog errors don't leak to stdout/stderr - // Select logger based on logging configuration + // Create PostHog client using the provided client provider with a custom logger. + // This ensures PostHog errors don't leak to stdout/stderr. + // Select logger based on logging configuration. var logger posthog.Logger if t.logging { - logger = NewPosthogLogger() // Use our custom logger adapter that routes to Atmos logging + logger = NewPosthogLogger() // Use our custom logger adapter that routes to Atmos logging. } else { - logger = NewSilentLogger() // Completely suppress PostHog internal logging + logger = NewSilentLogger() // Completely suppress PostHog internal logging. } @@ - defer func() { - // Ensure client close doesn't panic or output errors + defer func() { + // Ensure client close doesn't panic or output errors. if client != nil { - client.Close() + if cerr := client.Close(); cerr != nil { + log.Debug("Could not close PostHog client", "error", cerr) + } } }() @@ - // Log at debug level to avoid polluting user output with telemetry errors + // Log at debug level to avoid polluting user output with telemetry errors. log.Debug("Could not enqueue event", "error", err) return false } - // Note: Event is only sent when client.Close() is called in the deferred function - log.Debug("Telemetry event enqueued") + // Note: Event is only sent when client.Close() is called in the deferred function. + log.Debug("Telemetry event enqueued")Also applies to: 82-87, 97-103
pkg/telemetry/utils_test.go (2)
537-563: Consolidate logging config tests + restore env var safely.These three tests are near-identical and can be table‑driven. Also, preserve/restore ATMOS_TELEMETRY_LOGGING to avoid cross‑test leakage.
Apply this diff to replace the three tests with one table‑driven test that restores the original env var:
-// TestGetTelemetryFromConfigWithLoggingEnabled tests that logging can be enabled via environment variable. -func TestGetTelemetryFromConfigWithLoggingEnabled(t *testing.T) { - currentEnvVars := PreserveCIEnvVars() - defer RestoreCIEnvVars(currentEnvVars) - - ctrl := gomock.NewController(t) - mockClientProvider := mock_telemetry.NewMockTelemetryClientProviderMock(ctrl) - mockClient := mock_telemetry.NewMockClient(ctrl) - - // Expect no client creation since we're just testing config loading. - mockClientProvider.EXPECT().NewMockClient(gomock.Any(), gomock.Any()).Return(mockClient, nil).Times(0) - mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(0) - mockClient.EXPECT().Close().Return(nil).Times(0) - - // Enable logging via environment variable. - os.Setenv("ATMOS_TELEMETRY_LOGGING", "true") - defer os.Unsetenv("ATMOS_TELEMETRY_LOGGING") - - // Get telemetry configuration. - telemetry := getTelemetryFromConfig(mockClientProvider.NewMockClient) - - // Verify logging is enabled. - assert.NotNil(t, telemetry) - assert.True(t, telemetry.logging, "Logging should be enabled when ATMOS_TELEMETRY_LOGGING=true") -} - -// TestGetTelemetryFromConfigWithLoggingDisabled tests that logging can be disabled via environment variable. -func TestGetTelemetryFromConfigWithLoggingDisabled(t *testing.T) { - currentEnvVars := PreserveCIEnvVars() - defer RestoreCIEnvVars(currentEnvVars) - - ctrl := gomock.NewController(t) - mockClientProvider := mock_telemetry.NewMockTelemetryClientProviderMock(ctrl) - mockClient := mock_telemetry.NewMockClient(ctrl) - - // Expect no client creation since we're just testing config loading. - mockClientProvider.EXPECT().NewMockClient(gomock.Any(), gomock.Any()).Return(mockClient, nil).Times(0) - mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(0) - mockClient.EXPECT().Close().Return(nil).Times(0) - - // Explicitly disable logging via environment variable. - os.Setenv("ATMOS_TELEMETRY_LOGGING", "false") - defer os.Unsetenv("ATMOS_TELEMETRY_LOGGING") - - // Get telemetry configuration. - telemetry := getTelemetryFromConfig(mockClientProvider.NewMockClient) - - // Verify logging is disabled. - assert.NotNil(t, telemetry) - assert.False(t, telemetry.logging, "Logging should be disabled when ATMOS_TELEMETRY_LOGGING=false") -} - -// TestGetTelemetryFromConfigWithLoggingDefault tests the default logging configuration. -func TestGetTelemetryFromConfigWithLoggingDefault(t *testing.T) { - currentEnvVars := PreserveCIEnvVars() - defer RestoreCIEnvVars(currentEnvVars) - - ctrl := gomock.NewController(t) - mockClientProvider := mock_telemetry.NewMockTelemetryClientProviderMock(ctrl) - mockClient := mock_telemetry.NewMockClient(ctrl) - - // Expect no client creation since we're just testing config loading. - mockClientProvider.EXPECT().NewMockClient(gomock.Any(), gomock.Any()).Return(mockClient, nil).Times(0) - mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(0) - mockClient.EXPECT().Close().Return(nil).Times(0) - - // Ensure ATMOS_TELEMETRY_LOGGING is not set. - os.Unsetenv("ATMOS_TELEMETRY_LOGGING") - - // Get telemetry configuration. - telemetry := getTelemetryFromConfig(mockClientProvider.NewMockClient) - - // Verify logging defaults to false (as configured in atmos.yaml). - assert.NotNil(t, telemetry) - assert.False(t, telemetry.logging, "Logging should default to false") -} +func TestGetTelemetryFromConfigLoggingVariants(t *testing.T) { + currentEnvVars := PreserveCIEnvVars() + defer RestoreCIEnvVars(currentEnvVars) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClientProvider := mock_telemetry.NewMockTelemetryClientProviderMock(ctrl) + mockClient := mock_telemetry.NewMockClient(ctrl) + + // No client creation; config‑only. + mockClientProvider.EXPECT().NewMockClient(gomock.Any(), gomock.Any()).Return(mockClient, nil).Times(0) + mockClient.EXPECT().Enqueue(gomock.Any()).Return(nil).Times(0) + mockClient.EXPECT().Close().Return(nil).Times(0) + + cases := []struct { + name string + hasEnv bool + envVal string + want bool + }{ + {"enabled", true, "true", true}, + {"disabled", true, "false", false}, + {"default", false, "", false}, // atmos.yaml default is false. + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + const key = "ATMOS_TELEMETRY_LOGGING" + old, had := os.LookupEnv(key) + if tc.hasEnv { + os.Setenv(key, tc.envVal) + } else { + os.Unsetenv(key) + } + t.Cleanup(func() { + if had { + os.Setenv(key, old) + } else { + os.Unsetenv(key) + } + }) + + telemetry := getTelemetryFromConfig(mockClientProvider.NewMockClient) + assert.NotNil(t, telemetry) + assert.Equal(t, tc.want, telemetry.logging, "unexpected logging value for case %q", tc.name) + }) + } +}Also applies to: 565-589, 590-614
543-546: Finish gomock controllers.Add deferred ctrl.Finish() to assert expectations promptly.
ctrl := gomock.NewController(t) +defer ctrl.Finish()Also applies to: 569-572, 595-598, 620-623, 642-645
pkg/telemetry/telemetry_test.go (2)
333-339: Gate the networked integration test.This creates a real client and will hit the network. Gate behind an env flag or testing.Short to avoid flaky CI.
Add at the top of the test:
if testing.Short() || os.Getenv("RUN_POSTHOG_INTEGRATION") == "" { t.Skipf("Skipping PostHog integration test; set RUN_POSTHOG_INTEGRATION=1 to enable.") }
399-406: Also gate the wrong-endpoint integration test.Same concern; guard to keep CI green when offline.
Use the same guard as suggested for the other integration test.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
pkg/config/atmos.yaml(1 hunks)pkg/config/load.go(1 hunks)pkg/schema/schema.go(1 hunks)pkg/telemetry/telemetry.go(3 hunks)pkg/telemetry/telemetry_logger_selection_test.go(1 hunks)pkg/telemetry/telemetry_test.go(17 hunks)pkg/telemetry/utils.go(2 hunks)pkg/telemetry/utils_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags
Use interfaces for external dependencies to facilitate mocking
All code must pass golangci-lint checks
Follow Go's error handling idioms
Use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider using a custom error type for domain-specific errors
Follow standard Go coding style
Use gofmt and goimports to format code
Prefer short, descriptive variable names
Use snake_case for environment variables
Document all exported functions, types, and methods
Document complex logic with inline comments
Follow Go's documentation conventions
Use Viper for configuration management
Support configuration via files, environment variables, and flags
Follow the precedence order: flags > environment variables > config file > defaults
**/*.go: All comments in Go code must end with periods (enforced by golangci-lint godot).
Wrap all returned errors using static errors from the errors package; never return dynamic errors directly.
Always bind environment variables with viper.BindEnv() and provide ATMOS_ alternatives for each external var.
Separate structured logging from UI output: use stderr for prompts/errors to user; stdout only for data; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd or telemetry.CaptureCmdString and never capture user data.
Ensure cross-platform compatibility: prefer SDKs to external binaries, use filepath/os/runtime for portability, and add build constraints when needed.
Files:
pkg/schema/schema.gopkg/telemetry/telemetry_logger_selection_test.gopkg/config/load.gopkg/telemetry/telemetry.gopkg/telemetry/utils.gopkg/telemetry/telemetry_test.gopkg/telemetry/utils_test.go
**/*.{yaml,yml}
📄 CodeRabbit inference engine (CLAUDE.md)
YAML configs should support Go templating using provided template functions.
Files:
pkg/config/atmos.yaml
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for testing multiple scenarios
Include integration tests for command flows
Test CLI end-to-end when possible
Use test fixtures for complex inputs
Consider using testify/mock for creating mock implementations
**/*_test.go: Always use t.Skipf() with a reason for skipped tests; never use t.Skip() or reasonless t.Skipf().
Test files must mirror implementation structure and naming (e.g., aws_ssm_store_test.go).
Use table-driven unit tests and mock interfaces for external dependencies; target >80% coverage.
Files:
pkg/telemetry/telemetry_logger_selection_test.gopkg/telemetry/telemetry_test.gopkg/telemetry/utils_test.go
pkg/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests reside under pkg/ alongside implementations.
Files:
pkg/telemetry/telemetry_logger_selection_test.gopkg/telemetry/telemetry_test.gopkg/telemetry/utils_test.go
🧠 Learnings (7)
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-09-07T15:13:17.831Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T15:13:17.831Z
Learning: Applies to **/*.go : Always bind environment variables with viper.BindEnv() and provide ATMOS_ alternatives for each external var.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-04-10T20:48:22.687Z
Learnt from: samtholiya
PR: cloudposse/atmos#1147
File: pkg/config/load.go:0-0
Timestamp: 2025-04-10T20:48:22.687Z
Learning: In the `bindEnv` function in `pkg/config/load.go`, panic is used deliberately instead of returning errors because errors from `BindEnv` would only occur due to developer mistakes. Using panic helps with early detection of these developer errors during initialization.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
PR: cloudposse/atmos#1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*.go : Use Viper for managing configuration, environment variables, and flags
Applied to files:
pkg/config/load.go
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*.go : Use Viper for configuration management
Applied to files:
pkg/config/load.go
📚 Learning: 2025-09-07T15:13:17.831Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T15:13:17.831Z
Learning: Applies to **/*.go : For non-standard execution paths, capture telemetry with telemetry.CaptureCmd or telemetry.CaptureCmdString and never capture user data.
Applied to files:
pkg/telemetry/utils_test.go
🧬 Code graph analysis (5)
pkg/telemetry/telemetry_logger_selection_test.go (4)
pkg/telemetry/mock/mock_posthog_client.go (1)
NewMockClient(32-36)pkg/telemetry/telemetry.go (1)
NewTelemetry(39-48)pkg/telemetry/posthog_logger.go (2)
PosthogLogger(14-16)SilentLogger(60-60)pkg/telemetry/mock/mock_telemetry_provider.go (1)
NewMockTelemetryClientProviderMock(32-36)
pkg/telemetry/telemetry.go (2)
pkg/logger/logger.go (1)
Logger(32-35)pkg/telemetry/posthog_logger.go (2)
NewPosthogLogger(19-23)NewSilentLogger(63-65)
pkg/telemetry/utils.go (1)
pkg/telemetry/telemetry.go (2)
Telemetry(27-34)NewTelemetry(39-48)
pkg/telemetry/telemetry_test.go (3)
pkg/telemetry/mock/mock_posthog_client.go (1)
NewMockClient(32-36)pkg/telemetry/telemetry.go (1)
NewTelemetry(39-48)pkg/telemetry/mock/mock_telemetry_provider.go (1)
NewMockTelemetryClientProviderMock(32-36)
pkg/telemetry/utils_test.go (3)
pkg/telemetry/ci.go (2)
PreserveCIEnvVars(86-115)RestoreCIEnvVars(124-129)pkg/telemetry/mock/mock_telemetry_provider.go (1)
NewMockTelemetryClientProviderMock(32-36)pkg/telemetry/mock/mock_posthog_client.go (1)
NewMockClient(32-36)
🪛 GitHub Check: golangci-lint
pkg/telemetry/telemetry_logger_selection_test.go
[failure] 16-16:
16-40 lines are duplicate of pkg/telemetry/telemetry_logger_selection_test.go:43-67
[failure] 43-43:
43-67 lines are duplicate of pkg/telemetry/telemetry_logger_selection_test.go:16-40
pkg/telemetry/telemetry.go
[failure] 39-39:
argument-limit: maximum number of arguments per function exceeded; max 5 but got 6
pkg/telemetry/telemetry_test.go
[failure] 441-441:
441-477 lines are duplicate of pkg/telemetry/telemetry_test.go:481-517
[failure] 481-481:
481-517 lines are duplicate of pkg/telemetry/telemetry_test.go:441-477
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Summary
🔇 Additional comments (7)
pkg/config/load.go (1)
123-124: Env binding added correctly.Binding
settings.telemetry.loggingtoATMOS_TELEMETRY_LOGGINGfollows our selective BindEnv pattern and long‑term learnings. LGTM.pkg/config/atmos.yaml (1)
15-15: Defaultlogging: falseis appropriate.Keeps PostHog internal logs quiet at info level by default. LGTM.
pkg/telemetry/utils.go (1)
76-77: Approve — logging plumbed into Telemetry.
All NewTelemetry call sites include the new logging bool (verified in pkg/telemetry/utils.go:93 and the tests).pkg/telemetry/utils_test.go (2)
615-636: LGTM: capture with logging enabled.Good coverage for the captureCmdString path with logging enabled.
637-658: LGTM: capture with logging disabled.Happy path and closure expectations look right.
pkg/telemetry/telemetry_test.go (2)
39-39: LGTM: expectations updated to new constructor shape.Mocks align with NewTelemetry’s new signature; no issues.
Also applies to: 82-82, 128-128, 144-144, 229-229, 281-281, 295-295, 420-420
473-474: Incorrect — telemetry.Capture accepts map[string]interface{}; no change required.Capture is defined as
func (t *Telemetry) Capture(eventName string, properties map[string]interface{}) boolin pkg/telemetry/telemetry.go, and the tests in pkg/telemetry/telemetry_test.go (around lines 473–474 and 513–514) that pass a map are correct.Likely an incorrect or invalid review comment.
- Add Infof and Printf methods to PosthogLogger, SilentLogger, and DiscardLogger for interface completeness - Refactor NewTelemetry to use Options struct to comply with golangci-lint max params rule - Convert duplicate logging tests to table-driven TestTelemetryLogging for better maintainability - Update test snapshots to reflect new logging field in configuration - Route all PostHog log messages to Debug level to avoid cluttering user output 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…proach - Fix linter duplication warning by converting TestTelemetryLoggerSelectionBasedOnFlag to table-driven test - Reduces code duplication while maintaining same test coverage - Improves test maintainability and readability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove DiscardLogger implementation as it duplicates SilentLogger functionality - Keep SilentLogger as the single no-op logger implementation - Update telemetry documentation with new posthog_logging configuration option - Document how to enable PostHog internal logging for debugging - Simplify test coverage by removing DiscardLogger tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update snapshots to include new `logging: false` field in telemetry config - Update snapshots to reflect "Telemetry event enqueued" message change - Regenerated snapshots for tests affected by telemetry improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update additional snapshots that were missed in previous commit - Update atmos_describe_config tests to include logging: false field - Update logging-related tests for "Telemetry event enqueued" message - Ensure all snapshots are now consistent with telemetry improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
tests/snapshots/TestCLICommands_Valid_log_file_in_env_should_be_priortized_over_config.stdout.golden (2)
6-7: Duplicate ENV log lines.The repeated “Found ENV variable ATMOS_VERSION_CHECK_ENABLED=false” suggests init is running twice or logging isn’t deduped. Worth tightening to reduce snapshot brittleness.
1-1: Typo in filename: “priortized” → “prioritized”.Recommend renaming test/snapshot to avoid future search misses and minor papercuts.
tests/snapshots/TestCLICommands_Valid_log_level_in_flag_should_be_priortized_over_env_and_config.stderr.golden (2)
2-4: Reduce duplicated ENV logs (non-blocking)Same line logged thrice adds noise to snapshots; consider consolidating detection logs or logging once per variable.
If helpful, I can draft a tiny helper that memoizes ENV discovery logs to avoid repeats.
1-1: Fix typo: "priortized" → "prioritized" in test case names
- tests/test-cases/log-level-validation.yaml:103 — "Valid log level in env should be priortized over config"
- tests/test-cases/log-level-validation.yaml:122 — "Valid log level in flag should be priortized over env and config"
- tests/test-cases/log-level-validation.yaml:143 — "Valid log file in env should be priortized over config"
- tests/test-cases/log-level-validation.yaml:164 — "Valid log file in flag should be priortized over env and config"
Rename "priortized" → "prioritized" in those test names and regenerate snapshots for consistency.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
tests/snapshots/TestCLICommands_Valid_Log_Level_in_Environment_Variable.stderr.golden(1 hunks)tests/snapshots/TestCLICommands_Valid_log_file_in_env_should_be_priortized_over_config.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_Valid_log_file_in_flag_should_be_priortized_over_env_and_config.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_Valid_log_level_in_env_should_be_priortized_over_config.stderr.golden(1 hunks)tests/snapshots/TestCLICommands_Valid_log_level_in_flag_should_be_priortized_over_env_and_config.stderr.golden(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- tests/snapshots/TestCLICommands_Valid_log_file_in_flag_should_be_priortized_over_env_and_config.stdout.golden
- tests/snapshots/TestCLICommands_Valid_log_level_in_env_should_be_priortized_over_config.stderr.golden
🧰 Additional context used
🪛 Gitleaks (8.28.0)
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden
[high] 142-142: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Build (macos-latest, macos)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: website-deploy-preview
- GitHub Check: Lint (golangci)
- GitHub Check: Analyze (go)
- GitHub Check: Summary
🔇 Additional comments (2)
tests/snapshots/TestCLICommands_Valid_Log_Level_in_Environment_Variable.stderr.golden (1)
5-5: 'captured' → 'enqueued' snapshot update looks rightMatches the new enqueue flow and keeps debug-only visibility.
Stale snapshot found: tests/snapshots/TestCLICommands_atmos_vendor_pull_custom_detector_credentials_leakage.stderr.golden:93 contains "DEBU Telemetry event captured" — change to "DEBU Telemetry event enqueued" and re-run the snapshot/leak checks. Verification note: the script failed to complete the non-debug scan ("/dev/fd/63: No such file or directory"); re-run in an environment that supports /dev/fd or adjust the script to avoid process substitution.
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)
143-143: Good: new telemetry.logging surfaced in CLI outputPresence of
"logging": falsematches the new default and PR intent to suppress PostHog chatter by default.
tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden
Show resolved
Hide resolved
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden
Outdated
Show resolved
Hide resolved
...apshots/TestCLICommands_Valid_log_file_in_env_should_be_priortized_over_config.stdout.golden
Show resolved
Hide resolved
...stCLICommands_Valid_log_level_in_flag_should_be_priortized_over_env_and_config.stderr.golden
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1491 +/- ##
==========================================
+ Coverage 56.10% 56.25% +0.14%
==========================================
Files 277 278 +1
Lines 29158 29214 +56
==========================================
+ Hits 16360 16433 +73
+ Misses 11004 10985 -19
- Partials 1794 1796 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Add PostHog token masking to sanitizeOutput function in cli_test.go - Replace all real PostHog tokens in golden snapshots with phc_TEST_TOKEN_PLACEHOLDER - Ensures no real telemetry tokens appear in test snapshots - Real tokens remain in config files where they're needed for functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…h-posthog-to-avoid-user-impact
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tests/cli_test.go (2)
348-352: Precompile regex at package scope; optional pattern hardening.Minor perf/readability win: compile once and reuse. Optionally add word boundaries and a loose length to reduce accidental overmatches.
Apply this diff here:
- posthogTokenRegex := regexp.MustCompile(`phc_[a-zA-Z0-9_]+`) - result = posthogTokenRegex.ReplaceAllString(result, "phc_TEST_TOKEN_PLACEHOLDER") + result = rePosthogToken.ReplaceAllString(result, "phc_TEST_TOKEN_PLACEHOLDER")And add near the top of the file (package scope):
var rePosthogToken = regexp.MustCompile(`\bphc_[A-Za-z0-9_]{10,64}\b`)If you prefer to keep the original character class, retain it but still precompile.
348-352: Masking implemented; no PostHog tokens found in snapshots.
Scan of tests/snapshots returned no phc_ tokens besides phc_TEST_TOKEN_PLACEHOLDER.
- Optional: centralize this masking in sanitizeOutput for consistency.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
pkg/config/load.go(1 hunks)tests/cli_test.go(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_config_imports.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_atmos_describe_configuration.stdout.golden(1 hunks)tests/snapshots/TestCLICommands_indentation.stdout.golden(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- tests/snapshots/TestCLICommands_atmos_describe_configuration.stdout.golden
- pkg/config/load.go
- tests/snapshots/TestCLICommands_atmos_describe_config_imports.stdout.golden
- tests/snapshots/TestCLICommands_indentation.stdout.golden
- tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags
Use interfaces for external dependencies to facilitate mocking
All code must pass golangci-lint checks
Follow Go's error handling idioms
Use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider using a custom error type for domain-specific errors
Follow standard Go coding style
Use gofmt and goimports to format code
Prefer short, descriptive variable names
Use snake_case for environment variables
Document all exported functions, types, and methods
Document complex logic with inline comments
Follow Go's documentation conventions
Use Viper for configuration management
Support configuration via files, environment variables, and flags
Follow the precedence order: flags > environment variables > config file > defaults
**/*.go: All comments in Go code must end with periods (enforced by golangci-lint godot).
Wrap all returned errors using static errors from the errors package; never return dynamic errors directly.
Always bind environment variables with viper.BindEnv() and provide ATMOS_ alternatives for each external var.
Separate structured logging from UI output: use stderr for prompts/errors to user; stdout only for data; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
For non-standard execution paths, capture telemetry with telemetry.CaptureCmd or telemetry.CaptureCmdString and never capture user data.
Ensure cross-platform compatibility: prefer SDKs to external binaries, use filepath/os/runtime for portability, and add build constraints when needed.
Files:
tests/cli_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for testing multiple scenarios
Include integration tests for command flows
Test CLI end-to-end when possible
Use test fixtures for complex inputs
Consider using testify/mock for creating mock implementations
**/*_test.go: Always use t.Skipf() with a reason for skipped tests; never use t.Skip() or reasonless t.Skipf().
Test files must mirror implementation structure and naming (e.g., aws_ssm_store_test.go).
Use table-driven unit tests and mock interfaces for external dependencies; target >80% coverage.
Files:
tests/cli_test.go
tests/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Integration tests reside under tests/ using fixtures in tests/test-cases/.
Files:
tests/cli_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: website-deploy-preview
- GitHub Check: Summary
🔇 Additional comments (1)
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)
142-143: Good call on the token redaction.The change to use
phc_TEST_TOKEN_PLACEHOLDERaddresses the security scanner concerns raised in prior reviews. PostHog project API keys (phc_ prefix) are safe to be public, but using clearly fake placeholders in tests avoids triggering leak detection tools and maintains clean compliance practices.The addition of the
logging: falsefield correctly reflects the new telemetry configuration option introduced in this PR.
…h-posthog-to-avoid-user-impact
- Add missing periods to comments in cli_test.go to satisfy godot linter - Fix documentation to use correct field name `telemetry.logging` instead of `telemetry.posthog_logging` - Update environment variable in docs from ATMOS_TELEMETRY_POSTHOG_LOGGING to ATMOS_TELEMETRY_LOGGING - Documentation now matches actual implementation in code and test snapshots 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…1491) * fix(telemetry): prevent PostHog errors from leaking to user output - Add custom PosthogLogger adapter to integrate with Atmos logging - Redirect PostHog errors to debug level instead of stdout/stderr - Ensure telemetry failures don't impact user experience - Add unit tests to verify logger behavior - Fix issue where PostHog was logging directly to stderr This addresses the issue where PostHog errors like '502 Bad Gateway' were appearing in user output and breaking CLI tests. Now all PostHog errors are properly handled through our logging system and only appear at debug level. Fixes DEV-3633 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [autofix.ci] apply automated fixes * feat(telemetry): improve PostHog logger with structured context - Use log.With('component', 'posthog') to add context to all PostHog messages - Remove redundant message prefixes since component context identifies the source - Add 'posthog_level' field to preserve PostHog's original log level in errors - Update tests to verify component context appears in all log messages - Ensure logger instances are created after log level changes in tests This improves on the previous fix by using proper structured logging context instead of message prefixes, making logs more consistent with Atmos conventions. * [autofix.ci] apply automated fixes * refactor(telemetry): use WithPrefix for PostHog logger context - Replace log.With('component', 'posthog') with log.WithPrefix('posthog') - Cleaner output format: 'DEBU posthog: message' instead of K/V pairs - Fix misleading 'Telemetry event captured' message timing - Change to 'Telemetry event enqueued' since actual send happens on Close() - Update tests to verify prefix appears in log output This provides cleaner, more readable log output while still clearly identifying PostHog messages with the 'posthog:' prefix. * [autofix.ci] apply automated fixes * feat(telemetry): add configuration option to control PostHog internal logging - Add `logging` field to TelemetrySettings to control PostHog SDK logging - Default to false for cleaner user experience - PostHog SDK uses SilentLogger when logging=false (default) - PostHog SDK uses PosthogLogger when logging=true - Support environment variable ATMOS_TELEMETRY_LOGGING - Remove omitempty tag from logging field to ensure consistent serialization - Add comprehensive tests for logging configuration - Telemetry collection remains independent of logging setting This allows users to keep telemetry enabled while suppressing PostHog's internal debug messages (network errors, buffer status, etc.) that can clutter logs. Users can enable PostHog logging when debugging telemetry issues by setting telemetry.logging=true or ATMOS_TELEMETRY_LOGGING=true. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [autofix.ci] apply automated fixes * refactor(telemetry): improve logger interfaces and update test snapshots - Add Infof and Printf methods to PosthogLogger, SilentLogger, and DiscardLogger for interface completeness - Refactor NewTelemetry to use Options struct to comply with golangci-lint max params rule - Convert duplicate logging tests to table-driven TestTelemetryLogging for better maintainability - Update test snapshots to reflect new logging field in configuration - Route all PostHog log messages to Debug level to avoid cluttering user output 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor(telemetry): convert logger selection test to table-driven approach - Fix linter duplication warning by converting TestTelemetryLoggerSelectionBasedOnFlag to table-driven test - Reduces code duplication while maintaining same test coverage - Improves test maintainability and readability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove redundant DiscardLogger and update telemetry docs - Remove DiscardLogger implementation as it duplicates SilentLogger functionality - Keep SilentLogger as the single no-op logger implementation - Update telemetry documentation with new posthog_logging configuration option - Document how to enable PostHog internal logging for debugging - Simplify test coverage by removing DiscardLogger tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test: update golden snapshots for telemetry changes - Update snapshots to include new `logging: false` field in telemetry config - Update snapshots to reflect "Telemetry event enqueued" message change - Regenerated snapshots for tests affected by telemetry improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test: update remaining golden snapshots for telemetry changes - Update additional snapshots that were missed in previous commit - Update atmos_describe_config tests to include logging: false field - Update logging-related tests for "Telemetry event enqueued" message - Ensure all snapshots are now consistent with telemetry improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: mask PostHog tokens in test snapshots - Add PostHog token masking to sanitizeOutput function in cli_test.go - Replace all real PostHog tokens in golden snapshots with phc_TEST_TOKEN_PLACEHOLDER - Ensures no real telemetry tokens appear in test snapshots - Real tokens remain in config files where they're needed for functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: correct comment periods and documentation field names - Add missing periods to comments in cli_test.go to satisfy godot linter - Fix documentation to use correct field name `telemetry.logging` instead of `telemetry.posthog_logging` - Update environment variable in docs from ATMOS_TELEMETRY_POSTHOG_LOGGING to ATMOS_TELEMETRY_LOGGING - Documentation now matches actual implementation in code and test snapshots 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
|
These changes were released in v1.191.0. |
what
telemetry.posthog_logging) to control PostHog internal loggingwhy
It was failing builds due to snapshots changing.
Solution Details
Custom Logger System
Created two logger implementations:
New Configuration Option
Added
telemetry.posthog_loggingsetting:atmos.yamlorATMOS_TELEMETRY_POSTHOG_LOGGINGenvironment variableBehavior at Different Log Levels
When
posthog_logging: true:When
posthog_logging: false(default):Test Coverage
Added comprehensive unit tests that verify:
Documentation
Updated telemetry documentation to explain:
posthog_loggingconfiguration optionatmos.yamland environment variablesreferences
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Improvements
Tests
Documentation