autotelic / fastify-opentelemetry

A Fastify plugin that utilizes the OpenTelemetry API to provide request tracing.
MIT License
72 stars 12 forks source link

Feature request: propagate span attributes #63

Closed 10xLaCroixDrinker closed 6 months ago

10xLaCroixDrinker commented 7 months ago

I'd be interested in a feature that allowed you to propagate the span attributes that were added to the parent span down to the child spans created using request.openTelemetry().tracer. I was thinking something along these lines:

get tracer () {
  const tracer = trace.getTracer(moduleName, moduleVersion)

  if (propagateSpanAttributes) {
    const { startSpan } = tracer
    tracer.startSpan = function startSpanWithAttributes (...args) {
      const span = startSpan.apply(tracer, args)
      if (contextMap.has(request)) {
        const activeSpan = trace.getSpan(contextMap.get(request))
        span.setAttributes(activeSpan.attributes)
      } else {
        span.setAttributes(formatSpanAttributes.request(request))
      }
      return span
    }
  }

  return tracer
},

This uses a new option propagateSpanAttributes and when true (default false), gets the attributes from the parent span created by fastify-opentelemetry and applies them to any spans you create by extending tracer.startSpan. If there is no match for the request in the contextMap (e.g. when called in an onResponse hook), it uses formatSpanAttributes.request to create the attributes.

What do you think?

HW13 commented 6 months ago

Hi @10xLaCroixDrinker, thanks for the feature request!

This does sound like it could be useful and it looks like there has been some talk on the otel-js repo about handling shared attributes (https://github.com/open-telemetry/opentelemetry-js/issues/4274).

I do think in this case, the logic here would be better suited in a SpanProcessor though.

Sharing parent attributes could be achieved like so:

class ShareParentAttrsProcessor extends NoopSpanProcessor {
  onStart (span, parentContext) {
    // Check if the span was created by this plugin...
    if (span.instrumentationLibrary.name === '@autotelic/fastify-opentelemetry') {
      const parentSpan = api.trace.getSpan(parentContext)
      if (parentSpan?.attributes) {
        span.setAttributes(parentSpan.attributes)
      }
    }
  }
}

I've pushed a branch with a working example of the above, If you'd like try it out locally -> https://github.com/autotelic/fastify-opentelemetry/blob/eg-propagate-attrs/example/opentelemetry.js

10xLaCroixDrinker commented 6 months ago

Thanks @HW13