Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an OpenTelemetry-instrumented HTTP middleware module type so incoming HTTP requests are automatically wrapped with otelhttp.NewHandler() and emit tracing spans, wired via the observability plugin.
Changes:
- Register new module type
http.middleware.otelin the observability plugin manifest/factories/schemas. - Add
module.OTelMiddlewareimplementation that wrapshttp.Handlerwithotelhttp. - Add unit tests for the new middleware module and add
otelhttpdependency ingo.mod.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/observability/schemas.go | Adds UI schema for http.middleware.otel and its serverName config. |
| plugins/observability/plugin.go | Declares http.middleware.otel in the observability plugin manifest. |
| plugins/observability/modules.go | Registers the module factory and adds otelMiddlewareFactory. |
| module/http_middleware_otel.go | Implements OTelMiddleware using otelhttp.NewHandler. |
| module/http_middleware_otel_test.go | Adds basic module interface and handler-wrapping tests. |
| go.mod | Promotes otelhttp to a direct dependency. |
| { | ||
| Type: "http.middleware.otel", | ||
| Label: "OTEL HTTP Middleware", | ||
| Category: "observability", | ||
| Description: "Instruments HTTP requests with OpenTelemetry tracing spans", | ||
| ConfigFields: []schema.ConfigFieldDef{ | ||
| {Key: "serverName", Label: "Server Name", Type: schema.FieldTypeString, DefaultValue: "workflow-http", Description: "Server name used as the span operation name", Placeholder: "workflow-http"}, | ||
| }, | ||
| DefaultConfig: map[string]any{"serverName": "workflow-http"}, | ||
| }, |
There was a problem hiding this comment.
The schema for http.middleware.otel is missing the Inputs/Outputs fields that all existing http.middleware.* schemas define (see plugins/http/schemas.go). If this type stays as http.middleware.*, consider aligning the schema shape (and likely Category: "middleware") so UI/schema consumers treat it consistently with other middleware types.
| "log.collector", | ||
| "observability.otel", | ||
| "openapi.generator", | ||
| "http.middleware.otel", |
There was a problem hiding this comment.
Adding a new module type here requires updating the observability plugin’s unit tests (e.g., TestModuleFactories/TestModuleSchemas/TestModuleTypeCoverage in plugins/observability/plugin_test.go) which currently assert an exact set/count of module types. As-is, go test ./... will fail until the new http.middleware.otel type is included in those expected lists/maps.
| "http.middleware.otel", |
| if v, ok := cfg["serverName"].(string); ok && v != "" { | ||
| serverName = v |
There was a problem hiding this comment.
otelMiddlewareFactory dereferences cfg without a nil check. ModuleConfig.Config can be nil when the config: section is omitted (and the engine only injects a map when ConfigDir is set), which would panic at runtime. Treat nil as an empty map (or early-return the default) before reading cfg["serverName"].
| if v, ok := cfg["serverName"].(string); ok && v != "" { | |
| serverName = v | |
| if cfg != nil { | |
| if v, ok := cfg["serverName"].(string); ok && v != "" { | |
| serverName = v | |
| } |
| return map[string]plugin.ModuleFactory{ | ||
| "metrics.collector": metricsCollectorFactory, | ||
| "health.checker": healthCheckerFactory, | ||
| "log.collector": logCollectorFactory, | ||
| "observability.otel": otelTracingFactory, | ||
| "openapi.generator": openAPIGeneratorFactory, | ||
| "http.middleware.otel": otelMiddlewareFactory, | ||
| } |
There was a problem hiding this comment.
This introduces an http.middleware.* module type in the observability plugin, but all other http.middleware.* types are owned/declared by the HTTP plugin (see plugins/http/plugin.go and plugins/http/modules.go). Consider moving the factory+schema+manifest entry to the HTTP plugin (or renaming the type) to keep module-type ownership consistent and avoid future duplicate-type registration conflicts if the HTTP plugin later adds http.middleware.otel.
Summary
http.middleware.otelmodule type to the observability pluginotelhttp.NewHandler()to create spans for every incoming requestserverName(default:workflow-http) used as the span operation nameobservability.otelmodule loaded (uses global TracerProvider, defaults to noop)Test plan
go test ./module/ -run TestOTel -vpassesgo build ./...succeedshttp.middleware.otelin cloud.yaml to verify Jaeger receives HTTP spans🤖 Generated with Claude Code