Skip to content

feat(otel): bootstrap OTel SDK with autoexport/autoprop#33

Merged
bramwelt merged 6 commits into
mainfrom
tbramwell/LFXV2-1735-otel-sdk-bootstrap
May 19, 2026
Merged

feat(otel): bootstrap OTel SDK with autoexport/autoprop#33
bramwelt merged 6 commits into
mainfrom
tbramwell/LFXV2-1735-otel-sdk-bootstrap

Conversation

@bramwelt

Copy link
Copy Markdown
Contributor

Summary

  • Add pkg/utils/otel.go — bootstraps OpenTelemetry SDK using autoexport/autoprop packages, eliminating manual exporter boilerplate
  • Add pkg/utils/otel_test.go — tests for config, sampler, and SDK init (uses OTEL_*_EXPORTER=none so no external deps required)
  • Call SetupOTelSDKWithConfig from main.go after InitStructureLogConfig(), with graceful 25s shutdown timeout
  • Enable OTEL_SERVICE_NAME in charts/lfx-v2-voting-service/values.yaml; all other exporter/endpoint/sampler config delegated to ArgoCD overrides via standard OTEL_* env vars

The service already had otelhttp.NewHandler and slogotel.OtelHandler wired, but no SDK initialization — so no TracerProvider was registered and no spans were exported. This fixes that.

Design decisions

  • autoexport/autoprop — matches meeting-service migration; zero exporter boilerplate, standard OTEL_* env vars control everything
  • Only OTEL_SERVICE_NAME in chart defaults — endpoint, protocol, sampler set in ArgoCD production overrides, keeping chart safe for local dev (no exporter configured = no-op)

Test plan

  • make build — passes
  • make test (pkg/utils) — all OTel tests pass; OTEL_*_EXPORTER=none used so no external deps needed
  • Pre-existing race in TestEventProcessor_Start — confirmed present on main before this change, unrelated

Closes LFXV2-1735

🤖 Generated with Claude Code

Add pkg/utils/otel.go with SetupOTelSDKWithConfig using the
autoexport/autoprop packages to eliminate exporter boilerplate.
All exporter, endpoint, and propagator config is delegated to
standard OTEL_* env vars. Call SetupOTelSDKWithConfig from main
with graceful shutdown so spans are exported on exit. Enable
OTEL_SERVICE_NAME in Helm chart.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Issue: LFXV2-1735
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
@bramwelt bramwelt requested a review from a team as a code owner May 13, 2026 19:38
Copilot AI review requested due to automatic review settings May 13, 2026 19:38
Comment thread go.mod

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This license expression (BSD-3-Clause AND LicenseRef-scancode-google-patent-license-golang) is the standard Go patent grant that accompanies all Google-contributed Go dependencies. It is not a code issue — it requires the license policy allowlist to be updated to permit the LicenseRef-scancode-google-patent-license-golang identifier. Leaving this thread open for the policy team to action.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds first-class OpenTelemetry SDK bootstrapping to the voting service using autoexport and autoprop, so existing HTTP/log instrumentation can produce/export telemetry by registering SDK providers at startup.

Changes:

  • Add pkg/utils/otel.go to initialize trace/metric/log providers and propagators via standard OTEL_* environment variables.
  • Add pkg/utils/otel_test.go to validate env-driven config, sampler behavior, and SDK init/shutdown with exporters disabled.
  • Initialize the OTel SDK from cmd/voting-api/main.go and set a default OTEL_SERVICE_NAME in the Helm chart values.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/utils/otel.go New OTel SDK bootstrap utility (resource, sampler, providers, shutdown).
pkg/utils/otel_test.go New tests covering env config, sampler parsing, and init/shutdown behavior.
cmd/voting-api/main.go Wires OTel SDK initialization and graceful shutdown into service startup.
charts/lfx-v2-voting-service/values.yaml Sets default OTEL_SERVICE_NAME and documents that other OTel env is overridden in ArgoCD.
go.mod Adds required OpenTelemetry dependencies (autoexport/autoprop + SDK/log/metric).
go.sum Adds dependency checksums for the newly introduced modules.
Comments suppressed due to low confidence (3)

pkg/utils/otel_test.go:36

  • This test uses os.Setenv/os.Unsetenv instead of t.Setenv, which means environment restoration depends on the defer and can still leak when the test fails early or subtests are added. Prefer t.Setenv (and t.Cleanup for any additional restoration) for safer, race-free env handling.
	_ = os.Setenv("OTEL_SERVICE_NAME", "test-service")
	_ = os.Setenv("OTEL_SERVICE_VERSION", "1.2.3")
	defer func() {
		_ = os.Unsetenv("OTEL_SERVICE_NAME")
		_ = os.Unsetenv("OTEL_SERVICE_VERSION")
	}()

pkg/utils/otel_test.go:180

  • The subtest setup unsets env vars with os.Unsetenv (no automatic restoration), which can leak state across other tests in this package when the runner has OTEL_* variables set. Prefer setting explicit empty values via t.Setenv (or saving/restoring with t.Cleanup) instead of globally unsetting.
		t.Run(tt.sampler+"_"+tt.arg, func(t *testing.T) {
			_ = os.Unsetenv("OTEL_TRACES_SAMPLER")
			_ = os.Unsetenv("OTEL_TRACES_SAMPLER_ARG")
			if tt.sampler != "" {
				t.Setenv("OTEL_TRACES_SAMPLER", tt.sampler)
			}
			if tt.arg != "" {
				t.Setenv("OTEL_TRACES_SAMPLER_ARG", tt.arg)
			}

pkg/utils/otel_test.go:216

  • This test unsets OTEL_SERVICE_* via os.Unsetenv without restoring prior values, which can leak into subsequent tests in this package. Prefer t.Setenv with empty values (or save/restore with t.Cleanup) to keep test environment isolation.
	t.Setenv("OTEL_TRACES_EXPORTER", "none")
	t.Setenv("OTEL_METRICS_EXPORTER", "none")
	t.Setenv("OTEL_LOGS_EXPORTER", "none")
	_ = os.Unsetenv("OTEL_SERVICE_NAME")
	_ = os.Unsetenv("OTEL_SERVICE_VERSION")


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/utils/otel.go Outdated
Comment thread pkg/utils/otel.go
Comment thread pkg/utils/otel_test.go
Comment thread pkg/utils/otel_test.go
andrest50
andrest50 previously approved these changes May 18, 2026
- Conditionally add service.version attribute only when non-empty
- Remove hard-coded 1s batch timeout; use SDK default (5s)
- Replace os.Unsetenv/os.Setenv in tests with t.Setenv
- Use strings.Contains for sampler Description() assertion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Issue: LFXV2-1735
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
@bramwelt

Copy link
Copy Markdown
Contributor Author

Review feedback addressed (commit 1dc95a1)

All 4 actionable copilot threads have been resolved:

Thread Change
Empty service.version in newResource service.version attribute is now only added when cfg.ServiceVersion != ""
Hard-coded 1s batch timeout Removed trace.WithBatchTimeout(time.Second); SDK default (5s) used instead. "time" import removed.
os.Unsetenv without restore in tests All os.Unsetenv/os.Setenv+defer patterns replaced with t.Setenv throughout otel_test.go. "os" import removed.
Brittle sampler Description() assertion Replaced exact string match with strings.Contains(s.Description(), "TraceIDRatioBased")

The license compliance thread (thread 1) has been responded to but left open — it requires a policy allowlist update for LicenseRef-scancode-google-patent-license-golang, which is the standard Go patent grant and not a code issue.

@bramwelt

Copy link
Copy Markdown
Contributor Author

Review feedback addressed

All 4 copilot review threads have been resolved in commit 1dc95a1:

Thread Change
Empty service.version in newResource service.version attribute only added when cfg.ServiceVersion != ""
Hard-coded 1s batch timeout Removed trace.WithBatchTimeout(time.Second) — uses SDK default (5s). Removed unused "time" import
os.Unsetenv without restore in tests Replaced all os.Unsetenv/os.Setenv+defer patterns with t.Setenv throughout otel_test.go. Removed "os" import
Brittle sampler Description() assertion Replaced exact string match with strings.Contains(s.Description(), "TraceIDRatioBased")

The license compliance thread (github-license-compliance on go.mod) has been left open — it requires the policy allowlist to be updated to permit LicenseRef-scancode-google-patent-license-golang (the standard Google patent grant on Go dependencies), not a code change.

andrest50
andrest50 previously approved these changes May 18, 2026
Copilot AI review requested due to automatic review settings May 18, 2026 21:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Comment thread pkg/utils/otel.go
Comment thread pkg/utils/otel.go Outdated
Comment thread cmd/voting-api/main.go
Comment thread pkg/utils/otel.go
Address review comments from copilot[bot]:

- pkg/utils/otel.go: guard service.name attribute on non-empty value
- pkg/utils/otel.go: fix ServiceVersion doc comment re: default
- pkg/utils/otel.go: loosen OTEL_*_EXPORTER doc to reference autoexport
- cmd/voting-api/main.go: fix comment ("Command-line" → "Environment variable")

Resolves 4 review threads.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Issue: LFXV2-1735
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
@bramwelt

Copy link
Copy Markdown
Contributor Author

Second-round review follow-up

Addressed all 4 actionable copilot[bot] threads from the second review pass (commit f4b6093):

Thread File Fix
service.name always set even when empty pkg/utils/otel.go:133 Added cfg.ServiceName != "" guard, matching the existing service.version pattern
ServiceVersion doc comment inaccurate pkg/utils/otel.go:33 Updated to (no default; caller may set from build-time ldflags)
OTEL_*_EXPORTER doc too restrictive pkg/utils/otel.go:68 Loosened to (as supported by autoexport, e.g. "otlp", "none", "stdout")
Command-line/environment comment incorrect cmd/voting-api/main.go:54 Changed to Environment variable

The license-compliance thread (go.mod) is left unresolved — it requires a policy allowlist update, not a code change.

Copilot AI review requested due to automatic review settings May 19, 2026 03:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Comment thread pkg/utils/otel.go
Comment thread go.mod Outdated
Address review comments from copilot-pull-request-reviewer:

- pkg/utils/otel.go: default sampler to parentbased_always_on per
  the OpenTelemetry spec; handle always_on explicitly in switch
- go.mod: upgrade otelhttp v0.65.0 → v0.68.0 to align all
  contrib/* deps to the same release line

Resolves 2 review threads.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Issue: LFXV2-1735
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
@bramwelt

Copy link
Copy Markdown
Contributor Author

Third-round review follow-up

Addressed 2 new copilot[bot] threads (commit 8b57de3):

Thread File Fix
Default sampler should be parentbased_always_on per OTel spec pkg/utils/otel.go:168 Changed default case to trace.ParentBased(trace.AlwaysSample()); added explicit "always_on" case; updated doc comment
Mixed contrib/* versions (otelhttp v0.65.0 vs others at v0.68.0) go.mod:20 Upgraded otelhttp v0.65.0 → v0.68.0

The license-compliance thread (go.mod) remains open — policy team action required.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated no new comments.

@bramwelt bramwelt merged commit e8e8faa into main May 19, 2026
13 checks passed
@bramwelt bramwelt deleted the tbramwell/LFXV2-1735-otel-sdk-bootstrap branch May 19, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants