How do I read the traceparent in angular when using the apm-run-angular library?

We're using APM with an Angular application. We're using the apm-run-angular library. Somewhere in this library it adds a "traceparent" header to the XHR requests We'd like to get access to the "traceparent" header that's sent in these XHR requests. We'd like to read the value and output some information related to it. I can see the value in the Chrome DevTools Network tab, so I know it's there.

I assumed that the apm-run-angular library included an angular interceptor that inserts the "traceparent" header, but I can't find it. I put in an interceptor for debugging purposes to see if I could see the "traceparent" header in the request, but I don't see it.

What adds the "traceparent" header to the XHR headers?

Hi @fakeelasticjr,

Traceparent headers are added automatically to all API requests (XHR and FETCH) and they are tied to spans and not part of transactions.

We dont have an API as such to get these headers, But you could access all these spans and get the traceparent header via this utility exposed from the @elastic/rum-core internals.

import { getDtHeaderValue } from '@elastic/apm-rum-core/src/common/utils'

apm.observe('transaction:start', function (transaction) {
  const spans = transaction.spans

  spans.forEach(span => {
    console.log(getDtHeaderValue(span))
  })
})

Let us know if you need any other help.

Thanks,
Vignesh

Vignesh,

Thank you for your reply. I'm having some trouble with your code. I added the observer to my apm service. I'm finding that the transaction doesn't have any spans when it's started. I can tell that spans are added to the transaction.spans collection after the fact, but they are not added yet when the observer sees a "transaction:start" event.

    apm.observe('transaction:start', (transaction: any) => {
      const spans = transaction.spans;
      if (spans?.length) {
        // control never reaches here, Why???
        spans.forEach(span => {
          console.log(this.getDtHeaderValue(span));
        });
      } else {
        console.log('transaction has no spans', transaction);
        // ^^^^^ control always reaches here
      }
    });

Let me ask my question a different way. I'll use an example. I want to use apm tracing with a websocket connection. I want to start a transaction and pass the traceparent, traceid, etc through the websocket connection so that it's available on my server. This is briefly discussed here Distributed tracing | APM Node.js Agent Reference [3.x] | Elastic

In step #2 it says to get the traceparent using apm.currentTraceparent.

In step #5 it says to have the server use the traceparent when starting a transaction.

How do I do step #2? I can't find any way to get the traceparent in my Angular Typescript code.

@vigneshshanmugam please see my followup question. I'm still having problems

Apologies for the delay

but they are not added yet when the observer sees a "transaction:start" event.

You are right, you can change it to transaction:end in the observe API which would have collected all spans.

RUM agent does not have out of the box support for web socket connection. If you are instrumenting the ws connection using custom spans, then you can get the header value with the internal API and add it as header to the web socket connection.

const tr = apm.startTransaction("websocket-transport", "websocket")

// before the ws connection
const span = tr.startSpan("ws:blah", "custom");
// do the actual ws connection
const tpHeaderValue = getDtHeaderValue(span);

// add the traceparent: tpHeaderValue header to ws connection 

// once the connection is ended
span.end();

How are you communicating with the WS server from the browser? Are you using any library?

Thanks,
Vignesh