Skip to content

Conversation

@bbengfort
Copy link
Contributor

@bbengfort bbengfort commented Dec 19, 2025

Scope of changes

Updates the o11y package to implement a middleware that creates an OpenTelemetry span and adds it to the context in order to collect HTTP server metrics from Gin.

Type of change

  • new feature
  • bug fix
  • documentation
  • testing
  • technical debt
  • other (describe)

Acceptance criteria

This PR will be merged without review.

Definition of Done

  • I have manually tested the change running it locally (having rebuilt all containers) or via unit tests
  • I have added unit and/or integration tests that cover my changes
  • I have added new test fixtures as needed to support added tests
  • I have updated the dependencies list if necessary (including updating yarn.lock and/or go.sum)

Copilot AI review requested due to automatic review settings December 19, 2025 15:54
Copy link
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

This PR replaces the Prometheus-based observability implementation with OpenTelemetry for collecting HTTP server metrics and traces from Gin applications. The change modernizes the telemetry stack by adopting the vendor-neutral OpenTelemetry standard, enabling better trace propagation and more flexible metric collection.

Key Changes

  • Complete replacement of Prometheus client library with OpenTelemetry SDK for tracing and metrics
  • Introduction of configurable middleware with functional options pattern for flexible instrumentation
  • Removal of Prometheus metrics from logger middleware, centralizing observability in the o11y package

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
o11y/option.go Adds configuration options using functional variadic pattern for customizing OpenTelemetry middleware
o11y/o11y.go Implements new OpenTelemetry-based middleware for tracing and metrics collection
o11y/internal/semconv/utils.go Provides error handling utility for OpenTelemetry operations
o11y/internal/semconv/server.go Defines HTTP server helpers for OpenTelemetry semantic conventions (currently stub implementations)
o11y/internal/semconv/metrics.go Defines data structures for server metrics attributes
o11y/http.go Removes old Prometheus-based HTTP metrics collectors
logger/middleware.go Removes Prometheus metrics recording and simplifies function signature
logger/middleware_test.go Updates test to match simplified Logger function signature
go.mod, go.sum Removes Prometheus dependencies and adds OpenTelemetry SDK packages

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

Comment on lines 77 to 80
func (n HTTPServer) ReponseTraceAttrs(telemetry ResponseTelemetry) []attribute.KeyValue {
return nil
}

Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The function name "ReponseTraceAttrs" is misspelled. It should be "ResponseTraceAttrs".

Suggested change
func (n HTTPServer) ReponseTraceAttrs(telemetry ResponseTelemetry) []attribute.KeyValue {
return nil
}
func (n HTTPServer) ResponseTraceAttrs(telemetry ResponseTelemetry) []attribute.KeyValue {
return nil
}
func (n HTTPServer) ReponseTraceAttrs(telemetry ResponseTelemetry) []attribute.KeyValue {
return n.ResponseTraceAttrs(telemetry)
}

Copilot uses AI. Check for mistakes.
Comment on lines 73 to 75
func (n HTTPServer) RequestTraceAttrs(server string, req *http.Request, opts RequestTraceAttrsOpts) []attribute.KeyValue {
return nil
}
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The RequestTraceAttrs function returns nil instead of implementing the expected trace attributes extraction logic. This will result in missing trace attributes for incoming requests, which defeats the purpose of the OpenTelemetry instrumentation. The function should extract and return relevant HTTP request attributes according to OpenTelemetry semantic conventions.

Copilot uses AI. Check for mistakes.
}

func (n HTTPServer) ReponseTraceAttrs(telemetry ResponseTelemetry) []attribute.KeyValue {
return nil
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The ReponseTraceAttrs function returns nil instead of implementing the expected trace attributes extraction logic. This will result in missing trace attributes for HTTP responses, such as status code and content length. The function should extract and return relevant HTTP response attributes according to OpenTelemetry semantic conventions.

Suggested change
return nil
attrs := []attribute.KeyValue{
attribute.Int("http.response.status_code", telemetry.StatusCode),
}
if telemetry.WriteBytes > 0 {
attrs = append(attrs, attribute.Int64("http.response.body.size", telemetry.WriteBytes))
}
if telemetry.ReadBytes > 0 {
attrs = append(attrs, attribute.Int64("http.request.body.size", telemetry.ReadBytes))
}
return attrs

Copilot uses AI. Check for mistakes.
return nil
}

func (n HTTPServer) RecordMetrics(ctx context.Context, data ServerMetricData) {
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The RecordMetrics function has an empty implementation. This is a critical issue as it means no HTTP metrics (request duration, request size, response size) will be recorded to OpenTelemetry. The function should record the server metrics data to the appropriate OpenTelemetry metric instruments.

Suggested change
func (n HTTPServer) RecordMetrics(ctx context.Context, data ServerMetricData) {
func (n HTTPServer) RecordMetrics(ctx context.Context, data ServerMetricData) {
// Record zero-valued metrics to ensure instruments are used.
// Avoid accessing fields on ServerMetricData here to preserve compatibility,
// as its definition is not visible in this file.
if n.requestBodySizeHistogram != nil {
n.requestBodySizeHistogram.Record(ctx, 0)
}
if n.responseBodySizeHistogram != nil {
n.responseBodySizeHistogram.Record(ctx, 0)
}
if n.requestDurationHistogram != nil {
n.requestDurationHistogram.Record(ctx, 0.0)
}

Copilot uses AI. Check for mistakes.
ResponseSize: int64(c.Writer.Size()),
MetricAttributes: semconv.MetricAttributes{
Req: c.Request,
StatusCode: status,
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The MetricAttributes struct has a Route field defined but it is never populated when creating the struct at lines 120-124. The route information is being added to the Additional slice instead. Either the Route field should be populated with c.FullPath(), or it should be removed from the struct definition if it's not being used.

Suggested change
StatusCode: status,
StatusCode: status,
Route: c.FullPath(),

Copilot uses AI. Check for mistakes.
type Filter func(*http.Request) bool

// GinFilter filters an http request based on the gin.Context. The filter must return
// true if the reuqest should be traced.
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The word "reuqest" is misspelled. It should be "request".

Suggested change
// true if the reuqest should be traced.
// true if the request should be traced.

Copilot uses AI. Check for mistakes.
return nil, err
}
// Middleware returns middleware that will trace incoming requests.
// The service pramater should describe the name of the (virtual) server handling
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The word "pramater" is misspelled. It should be "parameter".

Suggested change
// The service pramater should describe the name of the (virtual) server handling
// The service parameter should describe the name of the (virtual) server handling

Copilot uses AI. Check for mistakes.
func Routes(router *gin.Engine) {
router.GET("/metrics", gin.WrapH(promhttp.Handler()))
}
span.SetAttributes(sc.ReponseTraceAttrs(semconv.ResponseTelemetry{
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The word "Reponse" is misspelled. It should be "Response".

Suggested change
span.SetAttributes(sc.ReponseTraceAttrs(semconv.ResponseTelemetry{
span.SetAttributes(sc.ResponseTraceAttrs(semconv.ResponseTelemetry{

Copilot uses AI. Check for mistakes.
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