APM for external plugin server side

Hello,

I am creating an external kibana plugin in React, which has both public and server side, using ES and Kibana 8.13.0 (also testing in 8.14.3)

I would like to have APM for the same. I have successfully added APM for the public side. But, in the server side, it throws error that the start() function of elastic apm cannot be called more than once. On further investigation, I found the reason for the same is an active APM for Kibana.

When I print elasticApm.isStarted(), it returns true....... and elasticApm.getServiceName() returns kibana.

How can I achieve APM for external plugin server side.

Thanks

Hi @Sheereen,

Can you confirm which agents you're using on the UI and server side? Are you using the Elastic APM Node.js agent or Elastic RUM agent and where are you using each?

Hi,

Thanks for the reply

In the plugin UI side, I am using RUM agent, and initializing the same in the setUp() function of plugin.ts, using the init() function of '@elastic/apm-rum'.

In the server side, I am using the Node Js agent, and initializing the same in setUp() function of plugin.ts, using the start() function of 'elastic-apm-node'. When I start, I get an error in Kibana console that start() can be called only once. So I printed out isStarted() and also the agent object, and found APM for kibana is already running (serviceName: kibana).

Thanks

Thanks for confirming. Can you share your setup configuration for both please?

Plugin UI

In public/plugin.ts

 public setup(core: CoreSetup): DcmMinimalPluginSetup {
    // Register an application into the side navigation menu
    core.application.register({
        ...
    });

    // Add this to the very top of the first file loaded in your app
    const apm = initElasticApm({
          serviceName: 'plugin-frontend',
          serverUrl: 'https://<ip>:8200',
          environment: 'dev',
          serviceVersion: '1.0',
    });
    apm.addLabels({ group: 'plugin' });

    return {};
  }




Plugin Server

In server/plugin.ts

constructor(initializerContext: PluginInitializerContext) {
    this.logger = initializerContext.logger.get();

    console.log(ElasticAPM.isStarted()); // Prints true, so the following LOC is never executed

    if (!ElasticAPM.isStarted()) {
        // Add this to the very top of the first file loaded in your app
        const apm: ElasticAPM.Agent = ElasticAPM.start({
            serviceName: 'plugin-backend',
            serverUrl: 'https://<ip>:8200',
            environment: 'dev',
            verifyServerCert: false,
            serviceVersion: '1.0',
            captureBody: 'all',
            captureErrorLogStackTraces: 'always',
            captureExceptions: true,
            captureHeaders: true,
            captureSpanStackTraces: true,
            globalLabels: { group: 'plugin' },
    });
}

Hi @carly.richmond

Any input on this?

Thanks

Hi Sheereen,

Thanks for your patience. I'm assuming you're seeing this issue as part of your local development?

I've been having a dig around, and I think the issue you're seeing is that the APM agent is already initialized as it's shipped with Kibana for debugging purposes. So by initializing the agent in your plugin you're attempting to start it again.

Have you tried configuring the agent with your additional options in the config/kibana.dev.yml and see if that does what you need to do?

Hi Carly,

Thanks for the response

Yes, I am running kibaa in dev mode and using kibana.dev.yml as the config file.

I haven't tried adding the agent initialization to the kibana.dev.yml file. But is it possible. It is a yml file write , and I donot think such function calls are possible there. Do you have any example or reference for the same?

Thanks,

Oh yes... I think this m8 be the answer

elastic.apm.active: false

I will try and let you know

Thanks

1 Like

Hi @carly.richmond ,

I gave the following in kibana.dev.yml

elastic:
  apm:
    active: false
    contextPropagationOnly: false

I donot get any erros, but when I start the APM, it still picks up the kibana apm configuration and starts the same.

// Add this to the very top of the first file loaded in your app
      const apm: ElasticAPM.Agent = ElasticAPM.start({
        ...ELASTIC_APM_OPTIONS.BE,
        globalLabels: {
          ...ELASTIC_APM_OPTIONS.COMMON.globalLabels,
        },
      });

I have clearly specified my own configuration, but when I print apm, it has the Kibana apm ip and settings. It is actually taking a combo of kibana settings and my custom settings. So kibana apm settings overrides my custom settings ({...custom_settings, ...kibana_settings}).

Let me try mentioning the apm url and other settings in kibana.dev.yml itself and check. It m8 work. Though, is it a good approach?

I also tried mentioning the apm config file, that also did not work.

Thanks

Hi @carly.richmond ,

Any updates?

Thanks

Hi @Sheereen,

Did you try adding the APM url settings in kibana.dev.yml to see if that works?

Yes I tried... din't work

elastic:
  apm:
    active: true
    configFile: <confilg_file_path>/plugin-elastic-apm-node.js
    serviceName: plugin_server
    serverUrl: https://<ip>:8200
    secretToken: <secret_token>
    verifyServerCert: true
    serverCaCertFile: <cert_file_path>/ca.crt
    serviceVersion: 1.0
    environment: dev
    centralConfig: false
    breakdownMetrics: true
    transactionSampleRate: 0.1
    captureBody: all
    captureErrorLogStackTraces: always
    captureExceptions: true
    captureHeaders: true
    captureSpanStackTraces: true

I also tried with confile file, as u can see in the above
Below are the contents of the config file, plugin-elastic-apm-node.js

module.exports = {
    serviceName: 'plugin_server',
    serverUrl: 'https://<ip>:8200',
    secretToken: <secret_token>,
    verifyServerCert: true,
    serverCaCertFile: '<cert_file_path>/ca.crt',
    serviceVersion: 1.0,
    environment: 'dev',
    captureBody: 'all',
    captureErrorLogStackTraces: 'always',
    captureExceptions: true,
    captureHeaders: true,
    captureSpanStackTraces: true
  }

None of these work. The apm config in kibana replaces the custom config I provide, so the serviceName and serverUrl gets replaced.

Thanks for sharing. Is this instrumentation for production or local development purposes? If it's only necessary for local debugging adding the settings temporarily to the Kibana APM config could be an option.

Right now. I am testing on Kibana dev mode.

But in near future, I would like to use it in production.

How can I add to Kibana APM config? Is it via kibana.dev.yml ? I yes, then I have tried that and doesn't work.

Thanks for the update @Sheereen. I've been out on vacation so just getting back to this. Looking at the testing steps in the documentation adding the config to config/kibana.dev.yml should be the correct approach.

Do you see any errors or warnings in the logs at all?