elastic / apm-agent-rum-js

https://www.elastic.co/guide/en/apm/agent/rum-js/current/index.html
MIT License
275 stars 133 forks source link

pageLoadTransactionName config not used #1347

Open nicolasguilhem opened 1 year ago

nicolasguilhem commented 1 year ago

I am using pageLoadTransactionName as the documentation says (https://www.elastic.co/guide/en/apm/agent/rum-js/current/custom-transaction-name.html) but transaction name doesn't change for page-load.

Seems that transaction name take config only if tr.name === NAME_UNKNOWN :

How to change "page-load" transaction name ? Transaction name is initialised with "undefined". How could it be initialised to NAME_UNKNOWN ?

devcorpio commented 1 year ago

Hi @nicolasguilhem,

Thanks for reaching out!

Thanks, Alberto

nicolasguilhem commented 1 year ago

I am using "@elastic/apm-rum-angular": "2.1.7" (extracted from package.json)

Agent initialization is done with (added console.log just before to be sure that value expected is correct) :

          console.log(window.location.pathname);
          apmService.init({
            serverUrl: environmentService.environment.apm.serverUrl,
            serviceName: environmentService.environment.apm.serviceName,
            distributedTracing:
              environmentService.environment.apm.distributedTracing,
            distributedTracingOrigins: [
              environmentService.environment.apm.distributedTracingOrigins,
            ],
            pageLoadTransactionName: window.location.pathname,
          });
devcorpio commented 1 year ago

hmm, the config looks good.

I assume you are initializing the agent from the application module or component as the docs describe.

Questions:

Screenshot 2023-03-09 at 16 48 19

In Chromium browsers an event payload is sent compressed, you will need to follow the steps here to see the payload decompressed. An alternative is to use a non-chromium browser such as Firefox, or Safari. Sharing a HAR file - making sure the events are not compressed - would be an alternative if you want.

Please, redact all the information that you deem sensitive.

Cheers, Alberto

nicolasguilhem commented 1 year ago

Thanks @devcorpio for helping ;)

First of all, agent is initialized at Angular initialization using APP_INITIALIZER in initializer factory :

@NgModule({
  declarations: [AppComponent],
  imports: [importedModules],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializer,
      deps: [
        KeycloakService,
        ApmService,
        EnvironmentService,
        ElectronService,
        LoadingService,
        BackendStatusService,
      ],
      multi: true,
    },
    {
      provide: ErrorHandler,
      useClass: ApmErrorHandler,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Next, transaction name of page-load is not "undefined" but is calculated with URL present in browser. I finnaly found how transaction name is set at beginning with "Unknown". It is set in constructor of SpanBase here (inherited by Transaction class).

If I remove pageLoadTransactionName, it doesn't change, transaction name of page-load is the one calculated as default (URL).

Value is checked in Kibana wich is in version 7.17.8.

I can't use the snippet you provided as the APM Rum Angular does not expose an "observe" method with this signature. The method is used by AP Rum Angular for route-change transactions (see here) ... But i'll try next week with apmService.apm.observe ...., i'll check payload too next week.

Thanks a lot @devcorpio

devcorpio commented 1 year ago

Hi @nicolasguilhem,

But i'll try next week with apmService.apm.observe ...., i'll check payload too next week.

apmService.init({

init returns an instance of apm, then you could use:

const apm = apmService.init(...

and then

  apm.observe("transaction:end", (tr: any) => {
      console.log("tr", tr)
  })

Thanks, Alberto

nicolasguilhem commented 1 year ago

I've done tests and result with the code above is :

            const apm = apmService.init({
            serverUrl: environmentService.environment.apm.serverUrl,
            serviceName: environmentService.environment.apm.serviceName,
            distributedTracing:
              environmentService.environment.apm.distributedTracing,
            distributedTracingOrigins: [
              environmentService.environment.apm.distributedTracingOrigins,
            ],
          });
          const wantedTransactionName = window.location.pathname;
          console.log('wantedTransactionName', wantedTransactionName);
          apm.config({ pageLoadTransactionName: wantedTransactionName });
          apm.observe('transaction:end', (tr) => console.log('tr', tr));

(also tried with pageLoadTransactionName directly in init and the result is the same).

console logs are : (can't past printscreen ...)

wantedTransactionName /mes-contextes
tr Transaction {name: '/mes-contextes?idContexte=2', type: 'page-load', options: {…}, id: 'e700f060d847a6b9', traceId: '870cd2362c15d7bdc96ce396335626e1', …}
blocked: false
breakdownTimings: []
captureTimings: true
context: {page: {…}, response: {…}}
ended: true
experience: {tbt: 3271, cls: 0, longtask: {…}}
id: "e700f060d847a6b9"
marks: {agent: {…}, navigationTiming: {…}}
name: "/mes-contextes"
onEnd: ƒ ()
length: 0
name: ""
prototype: {constructor: ƒ}
arguments: (...)
caller: (...)
options: 
      canReuse: true
      managed: true
      pageLoadSampled: false
      pageLoadSpanId: ""
      pageLoadTraceId: ""
      pageLoadTransactionName: "/mes-contextes"
      reuseThreshold: undefined
      transactionSampleRate: 1
nicolasguilhem commented 1 year ago

@devcorpio

and payload of XHR "events" is (removed some spans and sensitive datas) :

{
    "metadata": {
        "service": {
            "name": "xxxxxxxxxxxxxxxxxxxxxxxx-web-ihm",
            "agent": {
                "name": "rum-js",
                "version": "5.12.0"
            },
            "language": {
                "name": "javascript"
            }
        }
    }
}
{
    "transaction": {
        "id": "86cd1dfe5f348fc4",
        "trace_id": "ba9644455aceedd0fbbb3bdc7eaa0b67",
        "name": "/mes-contextes?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=",
        "type": "page-load",
        "duration": 2545,
        "context": {
            "page": {
                "referer": "",
                "url": "http://localhost:4200/mes-contextes?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite="
            },
            "response": {
                "transfer_size": 300,
                "encoded_body_size": 822,
                "decoded_body_size": 822
            }
        },
        "marks": {
            "agent": {
                "largestContentfulPaint": 132,
                "firstContentfulPaint": 68,
                "timeToFirstByte": 4,
                "domInteractive": 395,
                "domComplete": 1286
            },
            "navigationTiming": {
                "fetchStart": 0,
                "domainLookupStart": 0,
                "domainLookupEnd": 0,
                "connectStart": 0,
                "connectEnd": 0,
                "requestStart": 2,
                "responseStart": 4,
                "responseEnd": 5,
                "domLoading": 20,
                "domInteractive": 395,
                "domContentLoadedEventStart": 1206,
                "domContentLoadedEventEnd": 1206,
                "domComplete": 1286,
                "loadEventStart": 1286,
                "loadEventEnd": 1286
            }
        },
        "span_count": {
            "started": 21
        },
        "sampled": true,
        "sample_rate": 1,
        "experience": {
            "tbt": 1057,
            "cls": 0,
            "longtask": {
                "count": 4,
                "sum": 1257,
                "max": 811
            }
        }
    }
}
nicolasguilhem commented 1 year ago

i am asking myself if it could be a conflict with Angular router event NavigationEnd as this event is fired on page load (here.

This is supposed to be only for "route-change" but on "page-load", maybe transaction name is override ?

devcorpio commented 1 year ago

page load related:

You want /mes-contextes for the transaction name, is that right?

In the beacon, the name I'm seeing is:

/mes-contextes?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=

you want the agent to remove ?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=, Is that right?

What does happen if you set the of pageLoadTransactionName to something hardcoded (e.g. this-is-a-test)? I'm assuming that you will see something like /this-is-a-test?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=, right?

The agent is adding the query parameters to the name and you don't want that. Is my assumption correct?

If you don't want the query parameters, then you can take advantage of the apm.observe

      apm.observe('transaction:end', (tr) => {
           console.log('tr', tr));

                 if (tr.type === 'page-load') {
                   tr.name = wantedTransactionName
                  }
      }) 

That line will make sure the query parameters are not added anymore.

Let me know if this helps you

Cheers, Alberto

devcorpio commented 1 year ago

btw, page-load transactions happen where there are hard-navigations (interactions that imply a page refresh) and route-changehappens when there is a soft navigation (e.g. SPA navigation).

This is supposed to be only for "route-change" but on "page-load", maybe transaction name is override ?

It might be a possibility yes. We'll look at that. Although, with the snippet provided in the previous comment you will be able to set the name as you are expecting

Hope that helps!

Cheers, Alberto

nicolasguilhem commented 1 year ago

You want /mes-contextes for the transaction name, is that right?

Yes, you're completly right

In the beacon, the name I'm seeing is:

/mes-contextes?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=

you want the agent to remove ?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=, Is that right?

That's it ! 👍

What does happen if you set the of pageLoadTransactionName to something hardcoded (e.g. this-is-a-test)? I'm assuming that you will see something like /this-is-a-test?idContexte=2&_elastic_inspect_beacon_=true&codeModele=&traitement=&idControleQualite=, right?

The agent is adding the query parameters to the name and you don't want that. Is my assumption correct?

Haven't tried this. Will try it. If you don't want the query parameters, then you can take advantage of the apm.observe

      apm.observe('transaction:end', (tr) => {
           console.log('tr', tr));

                 if (tr.type === 'page-load') {
                   tr.name = wantedTransactionName
                  }
      }) 

That line will make sure the query parameters are not added anymore.

Yes, i'll use this snippet as a workaround.

Hope that helps!

Yes it is ! Muchas gracias 🙇