Skip to content

Instantly share code, notes, and snippets.

@aledalgrande
Created June 18, 2022 23:00
Show Gist options
  • Save aledalgrande/786afe2500d6c20279250136e0cd56f5 to your computer and use it in GitHub Desktop.
Save aledalgrande/786afe2500d6c20279250136e0cd56f5 to your computer and use it in GitHub Desktop.
Gymnastics needed to instrument Next.JS on Netlify
#!/bin/bash
# make this file executable before pushing: chmod +x lambda_start
args=("$@")
export NODE_OPTIONS='--require ./tracing.dist.js'
exec "${args[@]}"

In your Netlify build settings add this environment variable:

AWS_LAMBDA_EXEC_WRAPPER=./lambda_start

This is the trick to have something to customize the start of your server while preserving all the goodies of Next.JS and it works because we know Netlify is on Lambda. Having production run on something that is private implementations is not great, I know.

The other insight is we're just copying over tracing.dist.js while Netlify's plugin is bundling everything else in one file, so we will not have the node_modules we're requiring on Lambda. Instead of copying over deps of deps in netlify.toml, I decided to create my own bundle with esbuild (remember to add esbuild to your dev deps).

Using a custom server is absolutely a no-go, at that point you might as well just go with Express. Also tried NODE_OPTIONS with --require and it was crashing the build on Netlify at various points, because they decided to have the exact same env vars for both build and runtime.

All this would be super easy if instead either Next.JS or Netlify would provide an entrypoint for devs to use.

¯_(ツ)_/¯

[build]
publish = ".next"
[functions]
included_files = [
"tracing.dist.js",
"lambda_start"
]
{
"scripts": {
"dev": "next dev",
"build": "esbuild --bundle --platform=node --outfile=tracing.dist.js tracing.js && next build",
"start": "next start -p $PORT"
}
}
// in this example I'm using Lightstep, but it could be Datadog or any other Opentelemetry provider
const { lightstep } = require('lightstep-opentelemetry-launcher-node')
const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api')
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
const sdk = lightstep.configureOpenTelemetry({
accessToken: process.env.LIGHTSTEP_API_KEY,
serviceName: 'web',
instrumentations: [getNodeAutoInstrumentations()]
})
if (process.env.NODE_ENV !== 'production') {
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel[(process.env.OTEL_LOG_LEVEL || 'warn').toUpperCase()])
}
sdk.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment