Apm-agent-rum: How to restore page-load information when I use custom transaction?

After using custom, the page load message does not appear.

But I want to use APM's performance monitoring capabilities.

My code is as follows, I don’t know how to modify it.

> ampHanleRequest(config: any) {
> 
>         if (this.isLocal()) {
> 
>             return;
> 
>         }
> 
>         const lastIndex = config.url.lastIndexOf("/")
> 
>         this.apm.setCustomContext({
> 
>             name: this.user.name,
> 
>             userName: this.user.name,
> 
>             domainName: this.user.domainName,
> 
>             userId: this.user.id,
> 
>             pageName: document.title,
> 
>             method: config.method,
> 
>             api: config.url.substr(lastIndex + 1).split("?")[0],
> 
>             data: config.data ? JSON.stringify(config.data) : config.url.split("?")[1],
> 
>         })
> 
>         const fullApi = (config.baseURL + config.url).split("/api/")[1].split("?")[0];
> 
>         this.transaction = this.apm.startTransaction(`${this.appName} ${fullApi}`, 'custom')
> 
>         this.httpSpan = this.transaction.startSpan(config.method + (config.url as string), 'external')
> 
>         Object.assign(config.headers, { 'elastic-apm-traceparent': getHeaderValue(this.httpSpan) })
> 
>     }
> 
>     apmHandleResponse(response: any) {
> 
>         if (this.isLocal()) {
> 
>             return;
> 
>         }
> 
>         this.apm.setCustomContext({ responseStatus: response.status })
> 
>         this.httpSpan.end()
> 
>         this.transaction.end()
> 
>     }
> 
>     apmHandleResponseError(error: any) {
> 
>         if (this.isLocal()) {
> 
>             return;
> 
>         }
> 
>         this.apm.setCustomContext({
> 
>             responseStatus: error.response.status,
> 
>             errorMessage: error.response.data.error.message,
> 
>         })
> 
>         this.httpSpan.end()
> 
>         this.transaction.end()
> 
>     }

Hi @wajika,

That does not seem to be correct, you can create any number of custom transactions along with the managed transactions(page-load, rout-change, etc.) created by the agent.

Can you enable the debug logs by setting logLevel: "debug" in the RUM configuration and post here?

Thanks,
Vignesh

@vigneshshanmugam
Hi Vignesh, thank you for your reply.

I don't know if this information is detailed.

@vigneshshanmugam
Can you give me some help?

Apologies for the delay, I am not able to see any page-load transactions in the browser logs, Were you able to see it being captured and reported in the console?

Did you set the instrument: false config by any chance?

Thanks,
Vignesh

After I set instrument: true, there is still no page load log.

Can you help me again?

Apologies for the delay,

From the Chrome devtools picture you posted there, It seems like the RUM agent is loaded after the page-load which explains why it was not able to capture the page-load transaction details.

Could you please check if you can load the agent before the page-load event is fired from the browser?

pic 1

pic 2

pic 1 and pic 2 are increased apm.setInitialPageLoadName The results after.

however apm.setCustomContext And the data disappeared.

setCustomContext code
https://paste.ubuntu.com/p/rC9YYvSXvD/

@vigneshshanmugam
I want to confirm one thing. Can pageload and setCustomContext work at the same time?

hello vigneshshanmugam.

I look forward to your online again, hope you can help me find the reason, thank.

Apologies for the delay, I was on vacation.

Can pageload and setCustomContext work at the same time?

Yes, if you apply context via apm.setCustomContext it would apply to all transactions by default.

From your code, I can see that instrument flag is set to false which means the agent wont be instrumenting page-load transactions. Is this setting as you expected?

Thanks,
Vignesh


@vigneshshanmugam

I set instrument to true and setcustomcontext disappears.
What's going on?

If the instrument flag is false, RUM agent wont be capturing any details from the browser. Check this document - https://www.elastic.co/guide/en/apm/agent/rum-js/current/configuration.html#instrument

If you want to see the transaction data, Please set it to true and you would be able to see all the data as intended.

Thanks,
Vignesh

@vigneshshanmugam
sorry, I didn't mean it correctly. After I set instrument to true, the log of setcustomcontext is lost. In kibana apm ui, only page load records can be seen.

sorry again for my mistake.

@wajka,

No problem, One issue i could think of would be that your setCustomContext is called after the page-load transaction is ended. Could you try with this approach?

apm.init({
  context: {
    custom: {
      foo: 'bar'
    }
  }
})

Thanks,
Vignesh

@vigneshshanmugam
Hello vigneshshanmugam.
We have been communicating for some time, according to your feedback, we have not succeeded after testing.
I am a system administrator and don’t know the frontend code. I provide our package file. Can you help me debug it?

apmApi.ts

import { init as initApm } from '@elastic/apm-rum'


const getHeaderValue = (span: any) => {
    if (span && span.traceId && span.id && span.parentId) {
        const flags = span.sampled ? '01' : '00'
        const id = span.sampled ? span.id : span.parentId
        return '00' + '-' + span.traceId + '-' + id + '-' + flags
    }
}
export class InitApm {
    apm: any;
    env: any;
    appName: string;
    distributedTracingOrigins!: string[];
    serviceName!: string;
    serverUrl!: string;
    user = localStorage.userinfo ? JSON.parse(localStorage.userinfo) : { name: '', userName: '', userId: '', }
    transaction: any = ''
    httpSpan: any = ''
    logLevel: 'trace' | 'debug' | 'info' | 'warn' | 'error'
    constructor(appName: string, env?: any) {
        this.appName = appName;
        this.env = env || {
            env: process.env.NODE_ENV,
            Eenv: {
                development: 'development',
                local: 'local',
                production: 'production',
            }
        }
        this.logLevel = this.isProduction() ? "error" : "debug"
    }
    apmInit() {
        if (this.isLocal()) {
            return;
        }
        if (this.env.env === this.env.Eenv.development || this.env.env === this.env.Eenv.local) {
            this.distributedTracingOrigins = [
                'http://192.168.10.183',
            ]
            this.serviceName = `XXXXX`
            this.serverUrl = this.distributedTracingOrigins[0]
        }
        if (this.env.env === this.env.Eenv.production) {
            this.distributedTracingOrigins = [
                'https://apm.com',
            ]
            this.serviceName = `XXXXX`
            this.serverUrl = this.distributedTracingOrigins[0]
        }
        this.apm = initApm({
            active: true,
            instrument: true,
            logLevel: this.logLevel,
            distributedTracing: true,
            distributedTracingOrigins: this.distributedTracingOrigins,
        //    serviceName: this.serviceName,
            serviceName: `XXXXX`,
            serverUrl: this.serverUrl,
            serviceVersion: '0.0.1',
        })
        return this.apm
    }
    ampHanleRequest(config: any) {
        if (this.isLocal()) {
            return;
        }
        const lastIndex = config.url.lastIndexOf("/")
        this.apm.setCustomContext({
            name: this.user.name,
            userName: this.user.name,
            domainName: this.user.domainName,
            userId: this.user.id,
            pageName: document.title,
            method: config.method,
            api: config.url.substr(lastIndex + 1).split("?")[0],
            data: config.data ? JSON.stringify(config.data) : config.url.split("?")[1],
        })
        const fullApi = (config.baseURL + config.url).split("/api/")[1].split("?")[0];
        this.transaction = this.apm.startTransaction(`${this.appName} ${fullApi}`, 'custom')
        this.httpSpan = this.transaction.startSpan(config.method + (config.url as string), 'external')
        Object.assign(config.headers, { 'elastic-apm-traceparent': getHeaderValue(this.httpSpan) })
    }
    apmHandleResponse(response: any) {
        if (this.isLocal()) {
            return;
        }
        this.apm.setCustomContext({ responseStatus: response.status })
        this.httpSpan.end()
        this.transaction.end()
    }
    apmHandleResponseError(error: any) {
        if (this.isLocal()) {
            return;
        }
        this.apm.setCustomContext({
            responseStatus: error.response.status,
            errorMessage: error.response.data.error.message,
        })
        this.httpSpan.end()
        this.transaction.end()
    }
    isLocal() {
        return false; // this.env.env === this.env.Eenv.local;
    }
    isProduction() {
        return this.env.env === this.env.Eenv.production;
    }
}

axios.ts

// axios-init.js
import axios from 'axios'
import { Message } from "element-ui"
import { env, Eenv } from '@/utils'
import { getToken } from './getToken'
import { InitApm } from '@/plugins/apmApi'

const token = env.apiToken()

function serves(serve: string) {
    // apm
    const apm = new InitApm('masa-ms')
    apm.apmInit();

    const service = axios.create({
        baseURL: serve,
        timeout: 10000,
        headers: { common: { Authorization: 'Bearer ' + token } }
    });

    // axios
    service.interceptors.request.use(
        (config) => {
            config.headers.common.Authorization = 'Bearer ' + env.apiToken()
            apm.ampHanleRequest(config);
            return config;
        },
        (error) => {
            return Promise.reject(error)
        }
    );

    service.interceptors.response.use(
        (response) => {
            // apm
            apm.apmHandleResponse(response);
            return response;
        },
        (error) => {
            // apm
            apm.apmHandleResponseError(error);
            if (error.message.search(/40*/g) > -1 && env.env() === Eenv.local) {
                getToken()
            } else {
                try {
                    if (error.response.data.error.message) {
                        Message.error(error.response.data.error.message)
                    } else if (error.message) {
                        Message.error(error.message)
                    }
                } catch (error) {
                    return Promise.reject(error)
                }
            }
            return Promise.reject(error)
        }
    )
    return service
}

export default serves

I have successfully made pageload and other events appear at the same time.

But the information of setCustomContext did not appear.


Some custom information is not displayed.


For example, the above getLogUsers request is not recorded