opentelemetry-js icon indicating copy to clipboard operation
opentelemetry-js copied to clipboard

Dynamic Header for OTLPTraceExporter - Package @opentelemetry/exporter-trace-otlp-http

Open prebours opened this issue 3 years ago • 8 comments
trafficstars

Is your feature request related to a problem?

I am using the package @opentelemetry/exporter-trace-otlp-http to export the trace from the browser to the tracing server.

The tracing server is behind an authenticated proxy, where the token is provided through the authorization header.

Currently, we can provide custom headers when the exporter is created:

 const collectorOptions = {
    url, // url is optional and can be omitted - default is http://localhost:55681/v1/traces
    headers: {
      'authorization': `Bearer ${token}`
    }, // an optional object containing custom headers to be sent with each request
    concurrencyLimit: 10, // an optional limit on pending requests
  }

  const provider = new WebTracerProvider()
  provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter(
    collectorOptions
  )))

The token can change overtime (when it is renewed for example). I would need a way to provide an up-to-date token to the exporter before the exporter sends the payload.

Describe the solution you'd like

The easiest way would be to provide a way to update the header.

const collectorOptions = {
    url, // url is optional and can be omitted - default is http://localhost:55681/v1/traces
    headers: {
      'authorization': `Bearer ${token}`
    }, // an optional object containing custom headers to be sent with each request
    concurrencyLimit: 10, // an optional limit on pending requests
  }
  
  const exporter = new OTLPTraceExporter(
    collectorOptions
  )
  const provider = new WebTracerProvider()
  provider.addSpanProcessor(new SimpleSpanProcessor(exporter))

.... store exporter as a global variable

// when the token is updated
exporter.setHeader({
 'authorization': `Bearer ${token}`
})

Describe alternatives you've considered

An alternative could be to provide a callback. But it would mean that the token is stored somehow in a global variable. It may not be the workflow that people have. I have my token that is actually updated through an redux action.

const collectorOptions = {
    url, 
    headers: () => {
       return {
          authorization: `Bearer ${getTokenFromAGlobalFunction()}`
        }
    }.
    concurrencyLimit: 10, // an optional limit on pending requests
  }

Or would it be possible to clear the span processor and add a new one?

provider.clearSpanProcessor() // does it exist?
provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter(
    collectorOptions
  )))

Other comments

What would happen if the token is nil? Is there a way to desactivate tracing until the token is issue?

prebours avatar Apr 18 '22 18:04 prebours

Hmm there are several ways this could be solved I guess

  • The setHeaders call you suggested
  • A more general setConfig call
  • A headers callback which is called on each export request to get a new set of headers
  • passing the headers object by reference and mutating it (this might actually already work) but is probably the least stable

dyladan avatar Apr 18 '22 18:04 dyladan

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

github-actions[bot] avatar Jun 20 '22 06:06 github-actions[bot]

This issue was closed because it has been stale for 14 days with no activity.

github-actions[bot] avatar Jul 04 '22 06:07 github-actions[bot]

This is a feature I'd be very interested in - I'd like to add my auth token to the headers so I can validate serverside if traces come from an authenticated source.

Josh-a-e avatar Sep 11 '22 14:09 Josh-a-e

Hi, are there any news about this issue?

With the current implementation it seems that the while oauth mechanism will not because its not possible to renew the token used for authentication.

eloo-abi avatar Mar 03 '23 07:03 eloo-abi

In case someone is looking for a workaround. This will overwrite the Authorization header every time an export is made:

import { ReadableSpan } from '@opentelemetry/sdk-trace-web';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { ExportResult } from '@opentelemetry/core';
import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';

...

class CustomOTLPTraceExporter extends OTLPTraceExporter {
  private readonly getToken: () => string | undefined;
  private _headers: Record<string, unknown>;

  constructor(config: OTLPExporterNodeConfigBase, getToken: () => string | undefined) {
    super(config);
    this.getToken = getToken;
    this._headers = { ...config.headers };
  }

  export(items: ReadableSpan[], resultCallback: (result: ExportResult) => void) {
    this._headers = { ...this._headers, Authorization: `Bearer ${this.getToken()}` };
    return super.export(items, resultCallback);
  }
}

...

const exporter = new CustomOTLPTraceExporter({ url: collectorPath, headers: {} }, getToken);

Where getToken is your callback to get a valid token on every export call.

tarasvarshava-oviva avatar Jun 27 '24 15:06 tarasvarshava-oviva