Search code examples
vue.jskibanavue-routerelastic-stackelastic-apm

How to integrate Elastic APM to Vuejs SPA?


I integrated Elastic APM as follows to my Vue.js App. It logs successfully to Elastic APM.

However it is not showing the current page name in logs correctly. It seems to always show the first page on which the App has been mounted in APM.

I would like to always see the current page to be linked to the corresponding APM events. Any suggestions how to achieve this?

The documentation says to set pageLoadTransactionName. However it seems to not update this on route change: https://www.elastic.co/guide/en/apm/agent/rum-js/current/custom-transaction-name.html

App.js

  mounted() {
    this.initializeApm();
  },
  methods: {
    initializeApm() {
      const currentPage =
        this.$route.name || window.location.href.split('#/')[1];
      // initialize elastic apm
      const apm = initApm({
        serviceName: this.config.apm.serviceName,
        serverUrl: this.config.apm.serverUrl,
        serviceVersion: this.config.version,
        pageLoadTransactionName: currentPage,
        distributedTracingOrigins: [
          'https://xxx.de',

        ],
        environment: this.config.stage
      });
      apm.setUserContext({
        id: this.getUserIdFromSession,
        username: this.getUserNameFromSession,
        email: this.getUserEmail
      });
    }
  }

Solution

  • When routing to a different subpage you have to set the Route Name manually. You can achieve this via a filter on the 'change-route' type. See apm.addFilter() docs: https://www.elastic.co/guide/en/apm/agent/rum-js/current/agent-api.html#apm-add-filter

    Something like this should work:

    apm.addFilter(payload => {
      if (payload.data) {
        const mappedData = [];
        payload.data.forEach(tr => {
          if (tr.type === 'route-change')
            mappedData.push({
              ...tr,
              name: this.$route.name // overwrite unknown with the current route name
            });
          else mappedData.push(tr);
        });
        payload.data = mappedData;
      }
      return payload;
    });