What is the right way to configure/enable an Elastic APM agent in a Nuxtjs project?
I referred this documentation for a custom NodeJS app. The key takeaway was:
It’s important that the agent is started before you require any other modules in your Node.js application - i.e. before http and before your router etc.
I added the following snippet in nuxt.config.js, but the APM agent is not started or working. I do not see any errors in the app logs.
var apm = require('elastic-apm-node').start({
serviceName: 'nuxt-app',
serverUrl: 'http://ELK_APM_SERVER:8200'
})
Is there any other way to do this?
What is the right way to configure/enable an Elastic APM agent in a Nuxtjs project?
I referred this documentation for a custom NodeJS app. The key takeaway was:
It’s important that the agent is started before you require any other modules in your Node.js application - i.e. before http and before your router etc.
I added the following snippet in nuxt.config.js, but the APM agent is not started or working. I do not see any errors in the app logs.
var apm = require('elastic-apm-node').start({
serviceName: 'nuxt-app',
serverUrl: 'http://ELK_APM_SERVER:8200'
})
Is there any other way to do this?
Share Improve this question edited Dec 28, 2020 at 22:58 Shankar asked Dec 28, 2020 at 22:19 ShankarShankar 2,8453 gold badges30 silver badges58 bronze badges 2- 1 There's a number of different ways to run a nuxt application (static site, server rendered, dev mode, start/prod mode) -- could you update your question with information on how you're starting your nuxt application? – Alana Storm Commented Dec 29, 2020 at 17:32
- @AlanStorm At the time of posting the question, the project was server rendered with "nuxt start" in NodeJS. – Shankar Commented Dec 30, 2020 at 23:29
4 Answers
Reset to default 4We managed to get this working using a custom Nuxt module which explicitly requires the Node modules to instrument after it has initiated the APM module.
modules/elastic-apm.js
:
const apm = require('elastic-apm-node');
const defu = require('defu');
module.exports = function() {
this.nuxt.hook('ready', async(nuxt) => {
const runtimeConfig = defu(nuxt.options.privateRuntimeConfig, nuxt.options.publicRuntimeConfig);
const config = (runtimeConfig.elastic && runtimeConfig.elastic.apm) || {};
if (!config.serverUrl) {
return;
}
if (!apm.isStarted()) {
await apm.start(config);
// Now explicitly require the modules we want APM to hook into, as otherwise
// they would not be instrumented.
//
// Docs: https://www.elastic.co/guide/en/apm/agent/nodejs/master/custom-stack.html
// Modules: https://github./elastic/apm-agent-nodejs/tree/master/lib/instrumentation/modules
require('http');
require('http2');
require('https');
}
});
}
nuxt.config.js
:
module.exports = {
// Must be in modules, not buildModules
modules: ['~/modules/elastic-apm'],
publicRuntimeConfig: {
elastic: {
apm: {
serverUrl: process.env.ELASTIC_APM_SERVER_URL,
serviceName: 'my-nuxt-app',
usePathAsTransactionName: true // prevent "GET unknown route" transactions
}
}
}
};
All the answers are outdated and from beginning incorrect (17.02.2022)
To make it work follow these steps:
1.) Create a nodeApm.js in your root dir with the following content:
const nodeApm = require('elastic-apm-node')
if (!nodeApm.isStarted()) {
nodeApm.start()
}
2.) Use environment variables to store your config. For example:
ELASTIC_APM_SERVICE_NAME=NUXT_PRODUCTION
ELASTIC_APM_SECRET_TOKEN=yoursecrettokenhere
3.) Edit your package.json
"scripts": {
// if you want apm also on dev to test, add it also here
"dev": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt",
...
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
...
! Be awere that in ~2022 the node_modules bin folder has lost the "." in the directory name
! In all othere anwsers people forget the start parameter at the end
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
Based on what I've seen it looks like there isn't a "right" way to do this with the stock nuxt
mand line application. The problem seems to be that while nuxt.config.js
is the first time a user has a chance to add some javascript, that the nuxt
mand line application bootstraps the Node's HTTP frameworks before this config file is required
. This means the elastic agent (or any APM agent) doesn't have a chance to hook into the modules.
The current remendations from the Nuxt team appears to be
Invoke
nuxt
manually via-r
{ "scripts": { "start": "node -r elastic-apm-node node_modules/nuxt/.bin/nuxt" } }
Skip
nuxt
and use NuxtJS programmatically as a middleware in your framework of choiceconst { loadNuxt } = require('nuxt') const nuxtPromise = loadNuxt('start') app.use((req, res) => { nuxtPromise.then(nuxt => nuxt.render(req, res)) })
Based on Alan Storm answer (from Nuxt team) I made it work but with a little modification:
- I created a file named nodeApm.js where I added the following code:
const nodeApm = require('elastic-apm-node') if (!nodeApm.isStarted()) { ... // configuration magic }
- In script sections I added:
"start": "node -r ./nodeApm.js node_modules/nuxt/.bin/nuxt"