Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTEL workflow span attributes #6699

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

stephanos
Copy link
Contributor

@stephanos stephanos commented Oct 23, 2024

What changed?

(1) Adds the following OpenTelemetry (OTEL) span attributes:

  • temporalWorkflowID
  • temporalRunID

(2) Replaces the deprecated approach of OTEL interceptors with stats.Handlers

(3) If there are no exporters, disables the stats.Handlers completely.

Why?

The workflow id allows to correlate traces (which spans are part of) that belong to the same workflow id.

How did you test it?

(1) Added unit tests

(2) Manually

Using

docker run -p 127.0.0.1:4317:4317 -p 127.0.0.1:55679:55679 otel/opentelemetry-collector:0.106.1 2>&1 | tee collector-output.txt

it outputs

image

Potential risks

Breaking change?

Screenshot 2024-10-26 at 10 00 41 AM

Documentation

Is hotfix candidate?

@stephanos stephanos force-pushed the otel-span-wf-attrs branch 4 times, most recently from 8a6fd36 to fa77802 Compare October 26, 2024 16:43
Comment on lines -951 to -960
fx.Provide(
func(r *otelresource.Resource, sps []otelsdktrace.SpanProcessor) []otelsdktrace.TracerProviderOption {
opts := make([]otelsdktrace.TracerProviderOption, 0, len(sps)+1)
opts = append(opts, otelsdktrace.WithResource(r))
for _, sp := range sps {
opts = append(opts, otelsdktrace.WithSpanProcessor(sp))
}
return opts
},
),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Inlined into the next provider to be able to check if there are span processors at all.

fx.Provide(func(lc fx.Lifecycle, opts []otelsdktrace.TracerProviderOption) trace.TracerProvider {
fx.Provide(func(lc fx.Lifecycle, r *otelresource.Resource, sps []otelsdktrace.SpanProcessor) trace.TracerProvider {
if len(sps) == 0 {
return noop.NewTracerProvider()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No need to trace anything if there are no processors (since there are no exporters)

Comment on lines +137 to +149
// annotate span with workflow tags (same ones the Temporal SDKs use)
for _, tag := range c.tags.Extract(s.Payload, methodName) {
var k string
switch tag.Key() {
case "wf-id":
k = "temporalWorkflowID"
case "wf-run-id":
k = "temporalRunID"
default:
continue
}
span.SetAttributes(attribute.Key(k).String(tag.Value().(string)))
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This part is new net behavior. It applies the two attributes, when present.

Comment on lines +70 to +72
if !isEnabled(tp) {
return nil
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is new behavior: when tracing is disabled, it returns nil.

Comment on lines +91 to +93
if !isEnabled(tp) {
return nil
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is new behavior: when tracing is disabled, it returns nil.

tp trace.TracerProvider,
tmp propagation.TextMapPropagator,
) ServerTraceInterceptor {
//nolint:staticcheck
otelInterceptor := otelgrpc.UnaryServerInterceptor(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

otelgrpc.UnaryServerInterceptor is deprecated.

tmp propagation.TextMapPropagator,
) ClientTraceInterceptor {
return ClientTraceInterceptor(
otelgrpc.UnaryClientInterceptor(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

otelgrpc.UnaryClientInterceptor is deprecated.

}

// annotate span with workflow tags (same ones the Temporal SDKs use)
for _, tag := range c.tags.Extract(s.Payload, methodName) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is re-using the existing generated code that can extract Workflow tags from gRPC requests. It seems to do exactly what we need, so I'm not inclined to clone/fork that code.

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.

1 participant