Skip to content

Custom otel support#32

Merged
ankurs merged 6 commits intomainfrom
feat/otel
Sep 24, 2025
Merged

Custom otel support#32
ankurs merged 6 commits intomainfrom
feat/otel

Conversation

@ankurs
Copy link
Copy Markdown
Member

@ankurs ankurs commented Sep 23, 2025

Summary by CodeRabbit

  • New Features

    • Configurable OpenTelemetry OTLP tracing: custom endpoint, headers, compression, insecure mode, sampling ratio, service name/version, and optional OpenTracing bridge; new setup entrypoint to enable it.
    • Added gRPC message size limits to configuration.
  • Documentation

    • README and config docs updated to describe new tracing and config options and links.
  • Chores

    • Upgraded Go toolchain and multiple dependencies (gRPC, OpenTelemetry, Prometheus, New Relic, etc.).

@ankurs ankurs requested a review from Copilot September 23, 2025 06:51
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 23, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a generic OTLP tracing API (OTLPConfig + SetupOpenTelemetry), makes SetupNROpenTelemetry a wrapper, extends config.Config with OTLP and gRPC size fields, updates core initialization to prefer a custom OTLP endpoint before New Relic fallback, updates docs, and upgrades tooling and observability dependencies.

Changes

Cohort / File(s) Summary
Generic OTLP setup API
initializers.go, README.md
Adds exported OTLPConfig type and SetupOpenTelemetry(config OTLPConfig) error; implements generic OTLP initialization (endpoint, headers, compression, insecure, sampling, OpenTracing bridge); SetupNROpenTelemetry now delegates to the generic setup; README anchors/docs updated.
Config struct extensions
config/config.go, config/README.md
Adds exported fields to Config: GRPCMaxSendMsgSize, GRPCMaxRecvMsgSize, OTLPEndpoint, OTLPHeaders, OTLPCompression, OTLPInsecure, OTLPSamplingRatio, OTLPUseOpenTracingBridge with env tags/defaults; README reference updated.
Core initialization & shutdown
core.go
Adds helper parseHeaders(headerString string) map[string]string; changes processConfig to prefer custom OTLP setup using parsed headers and config values, falling back to New Relic OTEL when appropriate; adds error logging for SetupOpenTelemetry failures and improved error handling/logging during shutdown/close.
Dependency & toolchain upgrades
go.mod
Bumps Go/toolchain (1.24.*) and upgrades many deps: OpenTelemetry (v1.38.x family), gRPC/protobuf, Prometheus, New Relic, and assorted transitive updates.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant Core as SetupOpenTelemetry
  participant GRPC as OTLP gRPC Client
  participant Exp as OTLP Exporter
  participant TP as TracerProvider
  participant Bridge as OpenTracing Bridge (optional)

  App->>Core: SetupOpenTelemetry(OTLPConfig)
  Core->>Core: Validate config & apply defaults
  Core->>GRPC: Build client (endpoint, headers, compression, insecure)
  GRPC-->>Core: client options
  Core->>Exp: Create OTLP exporter (grpc)
  Exp-->>Core: exporter ready
  Core->>TP: Build Resource + TracerProvider (sampling)
  TP-->>Core: provider ready
  alt UseOpenTracingBridge
    Core->>Bridge: Install bridge
    Bridge-->>Core: bridge active
  end
  Core-->>App: success / error
Loading
sequenceDiagram
  autonumber
  actor App
  participant CoreProc as processConfig
  participant OTLP as SetupOpenTelemetry
  participant NR as SetupNROpenTelemetry

  App->>CoreProc: processConfig(config)
  alt config.OTLPEndpoint set
    CoreProc->>OTLP: SetupOpenTelemetry(from config)
    OTLP-->>CoreProc: err / success
  else if NewRelicOpenTelemetry enabled
    CoreProc->>NR: SetupNROpenTelemetry(...)
    NR-->>CoreProc: err / success
  else
    CoreProc-->>App: skip OTEL setup
  end
  CoreProc-->>App: continue startup (logs on error)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I twitched my whiskers at endpoints new,
Packed headers tight, compression too.
I bridged the spans and traced the loop,
Hopped over deps with a joyful whoop.
Carrot in paw, I log and chew. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Custom otel support" is concise and accurately reflects the primary change in the diff, which introduces configurable OTLP/OpenTelemetry support (new OTLPConfig and SetupOpenTelemetry) and related config fields; it is specific enough for a reviewer scanning history to understand the main intent without extraneous detail.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/otel

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d956434 and 0a4fb15.

📒 Files selected for processing (1)
  • initializers.go (5 hunks)
🔇 Additional comments (12)
initializers.go (12)

37-37: LGTM! Addresses the gRPC gzip compression issue.

The import of _ "google.golang.org/grpc/encoding/gzip" correctly registers the gzip compressor for side-effect registration, which addresses the previous review comment about potential runtime failures when using gzip compression.


135-171: Well-designed generic OTLP configuration struct.

The OTLPConfig struct provides a comprehensive and flexible configuration interface for OpenTelemetry with clear documentation and sensible defaults. The field choices align well with OTLP specification requirements and the support for gzip compression.


173-200: Excellent documentation with practical examples.

The function documentation provides clear usage examples for different OTLP backends (Jaeger, Honeycomb) which will help developers understand how to configure the generic setup for their specific needs.


201-209: LGTM! Appropriate validation logic.

The validation correctly checks for required fields and provides informative logging when initialization is skipped due to missing configuration.


211-214: Good default compression choice.

Defaulting to gzip compression aligns with best practices as it's widely supported by OTLP servers and is the default compression used by many OpenTelemetry exporters.


216-230: LGTM! Client options configuration is comprehensive.

The client options configuration properly handles endpoint, headers, compression, and insecure connections. The approach is clean and follows the builder pattern effectively.


223-226: Previous compression issue has been resolved.

The gzip compressor import on Line 37 resolves the potential runtime failure issue that was raised in the previous review. The compression configuration logic is now safe to use.


255-259: Good sampling ratio validation with sensible fallback.

The clamping logic ensures valid sampling ratios and provides a reasonable 20% default when invalid values are provided. This prevents configuration errors from causing runtime issues.


267-276: Well-implemented OpenTracing bridge configuration.

The conditional setup of the OpenTracing bridge is properly implemented and addresses the previous concern about empty tracer names by using config.ServiceName as the tracer identifier.


278-278: Informative logging includes endpoint for debugging.

The log message now includes the endpoint information, which will be helpful for debugging and verifying the correct configuration is being used.


282-308: Excellent refactoring: New Relic setup now uses generic implementation.

The refactoring of SetupNROpenTelemetry to use the generic SetupOpenTelemetry function is well-executed. It maintains backward compatibility while reducing code duplication and providing a clean wrapper with New Relic-specific defaults.


322-325: Minor formatting improvement on method filter configuration.

The multi-line formatting for the FilterMethods append operation improves readability compared to the previous single-line version.


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

❤️ Share

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds support for custom OpenTelemetry OTLP exporters, making the framework compatible with any OTLP-compatible backend (Jaeger, Honeycomb, etc.) instead of being limited to New Relic.

  • Introduces a new generic OTLPConfig struct and SetupOpenTelemetry function for configuring any OTLP backend
  • Refactors the existing New Relic OpenTelemetry setup to use the new generic configuration
  • Adds environment variable configuration for custom OTLP settings with precedence over New Relic

Reviewed Changes

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

Show a summary per file
File Description
initializers.go Introduces generic OTLP configuration and refactors New Relic setup to use the new implementation
config/config.go Adds environment variables for custom OTLP configuration
core.go Adds header parsing utility and integration logic for custom OTLP vs New Relic precedence
config/README.md Updates documentation to reflect new OTLP configuration fields
README.md Updates API documentation with new functions and types
go.mod Updates Go version and dependency versions

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread initializers.go Outdated
Comment thread core.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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

🧹 Nitpick comments (11)
initializers.go (5)

134-170: Consider adding environment attribute support to OTLPConfig.

Adding an optional Environment field and emitting semconv.DeploymentEnvironmentKey improves backend filtering.

Apply this diff and wire it in SetupOpenTelemetry:

 type OTLPConfig struct {
@@
 	// Insecure disables TLS verification for the connection
 	// Only use this for local development or testing
 	Insecure bool
+
+	// Environment describes the deployment environment (e.g., "prod", "staging")
+	Environment string
 }

Outside this hunk, in SetupOpenTelemetry’s resource attributes:

 		resource.WithAttributes(
 			// the service name used to display traces in backends
 			semconv.ServiceNameKey.String(config.ServiceName),
 			semconv.ServiceVersionKey.String(config.ServiceVersion),
+			semconv.DeploymentEnvironmentKey.String(config.Environment),
 		),

211-221: Harden exporter connection: add retry/backoff and a bounded dial timeout.

Without retry/timeout, exporter connection can be flaky or hang on startup.

Apply this diff:

 	// Build client options
 	clientOpts := []otlptracegrpc.Option{
 		otlptracegrpc.WithEndpoint(config.Endpoint),
 		otlptracegrpc.WithHeaders(config.Headers),
+		otlptracegrpc.WithRetry(otlptracegrpc.RetryConfig{Enabled: true}),
+		// Block connect so we fail fast within the context timeout below.
+		otlptracegrpc.WithDialOption(grpc.WithBlock()),
 	}
@@
-	otlpExporter, err := otlptrace.New(context.Background(), otlptracegrpc.NewClient(clientOpts...))
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	otlpExporter, err := otlptrace.New(ctx, otlptracegrpc.NewClient(clientOpts...))

Add the missing import in this file:

import (
+	"google.golang.org/grpc"
)

Also applies to: 227-227


251-255: Clamp sampling ratio to [0,1] to avoid invalid sampler configuration.

Protect against misconfigured env values.

-	tracerProvider := sdktrace.NewTracerProvider(
-		sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(config.SamplingRatio))),
+	// Clamp sampling ratio to [0,1]
+	sr := config.SamplingRatio
+	if sr < 0 {
+		sr = 0
+	} else if sr > 1 {
+		sr = 1
+	}
+	tracerProvider := sdktrace.NewTracerProvider(
+		sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(sr))),
 		sdktrace.WithBatcher(otlpExporter),
 		sdktrace.WithResource(r),
 	)

282-294: Skip NR OTLP init when license key is empty.

Avoid unauthorized calls and noisy logs when the license is not set.

 func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) error {
-	// Use the generic SetupOpenTelemetry with New Relic specific configuration
+	// Use the generic SetupOpenTelemetry with New Relic specific configuration
+	if strings.TrimSpace(license) == "" {
+		log.Info(context.Background(), "msg", "not initializing NR OpenTelemetry: empty license key")
+		return nil
+	}
 
 	config := OTLPConfig{
 		Endpoint:             "otlp.nr-data.net:4317",
 		Headers:              map[string]string{"api-key": license},
 		ServiceName:          serviceName,
 		ServiceVersion:       version,
 		SamplingRatio:        ratio,
 		Compression:          "gzip",
 		UseOpenTracingBridge: true,
 	}
 	return SetupOpenTelemetry(config)
 }

257-266: Return a shutdown func to flush spans on graceful stop.

Currently the tracer provider isn’t exposed for Shutdown, risking span loss on exit.

Consider changing the signature to return a shutdown function:

-func SetupOpenTelemetry(config OTLPConfig) error {
+func SetupOpenTelemetry(config OTLPConfig) (func(context.Context) error, error) {
@@
-		return err
+		return nil, err
@@
-	} else {
-		otel.SetTracerProvider(tracerProvider)
-	}
+	} else {
+		otel.SetTracerProvider(tracerProvider)
+	}
@@
-	return nil
+	return tracerProvider.Shutdown, nil

Call sites (e.g., in core.go) can then register this with your existing closers.

core.go (2)

63-79: Harden header parsing: skip empty keys/values and normalize header names.

Prevents invalid metadata (empty key) and aligns with gRPC’s lowercase header requirement.

 func parseHeaders(headerString string) map[string]string {
 	headers := make(map[string]string)
 	if headerString == "" {
 		return headers
 	}
 
 	pairs := strings.Split(headerString, ",")
 	for _, pair := range pairs {
 		kv := strings.SplitN(strings.TrimSpace(pair), "=", 2)
 		if len(kv) == 2 {
-			headers[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
+			key := strings.ToLower(strings.TrimSpace(kv[0]))
+			val := strings.TrimSpace(kv[1])
+			if key == "" || val == "" {
+				continue
+			}
+			headers[key] = val
 		}
 	}
 	return headers
 }

116-141: Log NR OTLP initialization errors; consider not starting Jaeger when OTLP is configured.

  • Errors from SetupNROpenTelemetry are currently ignored.
  • Optional: you initialize Jaeger earlier regardless; when OTLP is enabled, consider skipping Jaeger to avoid redundant init.
 	} else if c.config.NewRelicOpentelemetry {
 		// Fall back to New Relic OpenTelemetry if no custom OTLP is configured
-		SetupNROpenTelemetry(
-			nrName,
-			c.config.NewRelicLicenseKey,
-			c.config.ReleaseName,
-			c.config.NewRelicOpentelemetrySample,
-		)
+		if err := SetupNROpenTelemetry(
+			nrName,
+			c.config.NewRelicLicenseKey,
+			c.config.ReleaseName,
+			c.config.NewRelicOpentelemetrySample,
+		); err != nil {
+			log.Error(context.Background(), "msg", "Failed to setup NR OTLP", "err", err)
+		}
 	}
README.md (1)

145-182: Fix markdown lint: specify language for fenced code blocks in generated docs.

MD040 flagged missing language on code fences. Either:

  • Update comments to use ```go fences so gomarkdoc carries the language, or
  • Exclude generated docs from markdownlint.
go.mod (3)

39-41: Duplicate major versions of backoff (v4 and v5).

Both v4 and v5 are required indirectly. If nothing imports v4 explicitly, drop v4 to reduce graph size.

Run go mod tidy and inspect imports; if no direct/indirect consumer pins v4, remove:

-	github.com/cenkalti/backoff/v4 v4.3.0 // indirect

63-63: Inconsistent OTel internal retry module version.

go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.17.0 is far behind the rest of OTel (v1.38.0) and is likely unnecessary to pin. Let the resolver choose the matching transitive version.

Apply:

-	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.17.0 // indirect

Then run go mod tidy.


72-74: Avoid mixing genproto root and scoped submodules.

You have root google.golang.org/genproto at an older snapshot alongside newer .../googleapis/{api,rpc}. Prefer only the scoped submodules to avoid version skew.

Apply:

-	google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect

Then run go mod tidy to reconcile.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a612afe and 33b4f26.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (6)
  • README.md (8 hunks)
  • config/README.md (2 hunks)
  • config/config.go (1 hunks)
  • core.go (2 hunks)
  • go.mod (2 hunks)
  • initializers.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
core.go (1)
initializers.go (2)
  • OTLPConfig (138-170)
  • SetupOpenTelemetry (200-270)
🪛 markdownlint-cli2 (0.18.1)
README.md

158-158: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


172-172: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (15)
config/README.md (1)

19-144: Config additions look consistent and well documented.

Fields and env tags align with the new OTLP setup flow.

config/config.go (1)

106-129: LGTM — OTLP headers not logged in the repo.

parseHeaders (core.go) parses c.config.OTLPHeaders into OTLPConfig and I found no logging/printing/marshalling of the raw or parsed headers.

go.mod (13)

3-3: Go 1.24 directive: verify CI/tooling availability.

Bumping to go 1.24.0 (toolchain 1.24.1) looks fine. Ensure your CI images and devtooling have Go 1.24.1 to avoid build drift.


12-13: LGTM: interceptor/log bumps.

Incremental, non-breaking updates.


19-19: LGTM: grpc-gateway v2.27.2.


21-21: LGTM: New Relic agent v3.40.1.


23-23: LGTM: Prometheus client_golang v1.23.2.


25-29: LGTM: OTel stack aligned at v1.38.0.

Good version alignment across otel core/exporters/sdk.

Please run go mod tidy to ensure no hidden transitive mismatches remain after this upgrade.


31-32: LGTM: grpc/protobuf updates.

These are compatible with the newer grpc-gateway/OTel libs.


47-47: LGTM: logr v1.4.3.


55-55: LGTM: nrgrpc v1.4.7.


57-60: LGTM: Prometheus indirects refreshed.


62-62: LGTM: go.opentelemetry.io/auto/sdk v1.2.1.


64-66: LGTM: otel metric/trace + proto/otlp.


69-71: LGTM: x/ indirects updated.*

Comment thread go.mod
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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

🧹 Nitpick comments (3)
initializers.go (3)

251-255: Clamp sampling ratio to [0,1] and default to 1.0.

Prevents accidental “no traces” or invalid sampler configs.

+	// Clamp/Default sampling ratio
+	ratio := config.SamplingRatio
+	if ratio <= 0 || ratio > 1 {
+		ratio = 1.0
+	}
 	tracerProvider := sdktrace.NewTracerProvider(
-		sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(config.SamplingRatio))),
+		sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(ratio))),
 		sdktrace.WithBatcher(otlpExporter),
 		sdktrace.WithResource(r),
 	)

251-269: Add a shutdown hook to flush spans on process exit.

Without Shutdown, spans can be dropped on termination.

Proposal:

  • Keep a package-level tracer provider reference in SetupOpenTelemetry.
  • Expose ShutdownOpenTelemetry(ctx) and call it from your signal handler.

Example:

var otelTP *sdktrace.TracerProvider

func SetupOpenTelemetry(cfg OTLPConfig) error {
  // ...
  otelTP = tracerProvider
  // ...
}

func ShutdownOpenTelemetry(ctx context.Context) error {
  if otelTP != nil {
    return otelTP.Shutdown(ctx)
  }
  return nil
}

283-294: Skip NR OTLP init when license is empty (parity with SetupNewRelic).

Avoids unnecessary connection attempts and clearer logs.

 func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) error {
+	if strings.TrimSpace(license) == "" {
+		log.Info(context.Background(), "msg", "not initializing opentelemetry (nr): missing license key")
+		return nil
+	}
 	// Use the generic SetupOpenTelemetry with New Relic specific configuration
 	config := OTLPConfig{
 		Endpoint:             "otlp.nr-data.net:4317",
 		Headers:              map[string]string{"api-key": license},
 		ServiceName:          serviceName,
 		ServiceVersion:       version,
 		SamplingRatio:        ratio,
 		Compression:          "gzip",
 		UseOpenTracingBridge: true,
 	}
 	return SetupOpenTelemetry(config)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33b4f26 and 2b36742.

📒 Files selected for processing (1)
  • initializers.go (3 hunks)
🔇 Additional comments (1)
initializers.go (1)

257-266: LGTM: bridge tracer uses a non-empty, descriptive name.

Using service name resolves prior feedback.

Comment thread initializers.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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

🧹 Nitpick comments (3)
core.go (3)

137-137: Fix inconsistent variable declaration style

There's an extra space before err which makes the declaration inconsistent with the surrounding code style.

-		 err := SetupNROpenTelemetry(
+		err := SetupNROpenTelemetry(

474-479: Consider simplifying the goroutine closure

The goroutine captures both ctx and c, but c is already available in the outer scope. You only need to pass ctx since it's the one that changes scope. Also, the context is already available in the goroutine without passing it explicitly.

-		go func(ctx context.Context, c *cb) {
+		go func() {
 			err := c.httpServer.Shutdown(ctx)
 			if err != nil {
 				log.Error(context.Background(), "msg", "http server shutdown error", "err", err)
 			}
-		}(ctx, c) // shutdown http server gracefully
+		}() // shutdown http server gracefully

65-81: Consider adding unit tests for parseHeaders function

The parseHeaders function handles critical configuration parsing for OTLP headers. Consider adding unit tests to verify correct behavior with various input formats, including edge cases like empty strings, malformed pairs, and pairs with multiple equals signs.

Would you like me to generate comprehensive unit tests for the parseHeaders function to ensure robust header parsing?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b36742 and d956434.

📒 Files selected for processing (1)
  • core.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
core.go (1)
initializers.go (3)
  • OTLPConfig (138-170)
  • SetupOpenTelemetry (200-270)
  • SetupNROpenTelemetry (282-294)
🔇 Additional comments (3)
core.go (3)

77-77: Good improvement over previous review comment

The warning message now includes the actual malformed pair value, which addresses the previous review suggestion about improving debugging.


119-134: Well-structured OTLP configuration precedence

The implementation correctly prioritizes custom OTLP endpoints over New Relic OpenTelemetry, providing good flexibility for users to choose their telemetry backend. The error logging is appropriate for debugging configuration issues.


440-443: Good addition of error logging for resource cleanup

Adding error logging when closing resources improves observability during shutdown. This helps identify potential resource leaks or cleanup failures.

Comment thread core.go
Comment thread core.go
Comment thread core.go
@ankurs ankurs requested a review from Copilot September 23, 2025 09:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 6 out of 7 changed files in this pull request and generated 1 comment.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread core.go
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.

2 participants