Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Next.js server instrumentation #2959

Merged
merged 70 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
27b3fb2
feat: Next.js instrumentation
trentm Sep 29, 2022
e0efb1c
fixes: 'error.transaction.*' capture; correct trans.name when error h…
trentm Sep 29, 2022
4e12451
fix: 'make check'
trentm Sep 29, 2022
a2f9b4e
skip dependency-check in the sample a-nextjs-app because it borks on …
trentm Sep 29, 2022
3171814
typo in comment
trentm Oct 4, 2022
146511a
do the config test pennance for new instrumentation modules
trentm Oct 4, 2022
5452607
get routes going with a dev server. now need to move back to instr on…
trentm Oct 5, 2022
67bad71
flushing on server shutdown; DevServer instrumentation; most of the t…
trentm Oct 7, 2022
ce06f35
drop this unused instrumentation module
trentm Oct 7, 2022
dc04846
fix config.test.js
trentm Oct 11, 2022
ff5dd74
more test cases, fixing some edge cases with error capture
trentm Oct 12, 2022
4c739fa
use relative require for elastic-apm-node rather than a relative dep;…
trentm Oct 12, 2022
352fcb6
fix make check
trentm Oct 12, 2022
c25c3fe
update package-lock for the recently dropped relative agent dep
trentm Oct 12, 2022
e51919f
drop the slow to install/build 'sharp' suggested for Next.js prod (ht…
trentm Oct 12, 2022
4ffd5ef
strip down tests that are run for quicker dev; solve the test hang
trentm Oct 13, 2022
b2f31b7
nope to Next.js instr with contextManager=patch config, skip those
trentm Oct 13, 2022
ade6c03
restore full testing
trentm Oct 13, 2022
5e2cc59
some debugging for tests failing in CI
trentm Oct 13, 2022
c556305
fix tests for v14.0 (skip); and hopefully for Windows CI
trentm Oct 13, 2022
18bbd38
test fixes: skip Windows; give 20s for Next.js server to come up on s…
trentm Oct 13, 2022
ce94960
give shell=true on win32 a try for Next.js testing on win32
trentm Oct 13, 2022
382be82
more correct fix for node v18 tests: the issue was ipv4 vs ipv6 disag…
trentm Oct 13, 2022
0e04751
moar trying for Windows tests to get spawn to work
trentm Oct 13, 2022
95c3ad1
nope to Windows testing now, thanks cmd.exe; better dynamic rewrite t…
trentm Oct 13, 2022
0a7f70c
attempt to avoid invalid XML errors/warnings from Jenkins looking at …
trentm Oct 13, 2022
dd55843
fix the recently added stdout/stderr filtering (Buffer -> string)
trentm Oct 13, 2022
07534e5
add TAV testing of Next.js
trentm Oct 13, 2022
7af0031
needed for tav runs in Jenkins
trentm Oct 14, 2022
3a7dc47
Merge branch 'main' into trentm/feat-nextjs
trentm Oct 14, 2022
5c64f03
test another error case: a throw in getServerSideProps
trentm Oct 14, 2022
be1a746
test the /_next/data/... route -- the more important of the various i…
trentm Oct 14, 2022
ed075fb
feat: skip stack frame lines of context for minimized files
trentm Oct 14, 2022
1739501
set metadata.service.framework.*
trentm Oct 14, 2022
9f178ea
move nextPj down after some early test file exits (for when testing w…
trentm Oct 14, 2022
f56988a
move tests to test/instrumentation/modules/next/... where it should be
trentm Oct 14, 2022
0629011
get the next.js version *after* npm ci, else the package.json isn't t…
trentm Oct 14, 2022
f04b509
get dependabot updates for a-nextjs-app test app
trentm Oct 14, 2022
8bb630f
start a Next.js + APM example: this is the state after 'npx create-ne…
trentm Oct 17, 2022
4186e29
steps to add APM support to a Next.js app
trentm Oct 17, 2022
4b9d8c7
first crack at Next.js docs
trentm Oct 18, 2022
1d90b9b
Merge branch 'main' into trentm/feat-nextjs
trentm Oct 18, 2022
b47fb16
add a screenshot
trentm Oct 18, 2022
9d14567
apmsetup.js -> elastic-apm-node/start-next.js; drop the .env file han…
trentm Oct 18, 2022
10ff2d5
fix lint
trentm Oct 18, 2022
f267e38
good for now for docs
trentm Oct 18, 2022
e0c7ac0
get test Next.js app to use start-next.js starter module
trentm Oct 18, 2022
73f5816
missed part of converting the test Next.js app over the using 'start-…
trentm Oct 18, 2022
ac78bf4
next instr docs; clearing out XXXs
trentm Oct 19, 2022
dfecd43
clearning more XXXs
trentm Oct 19, 2022
a7ddf3b
working through XXXs
trentm Oct 19, 2022
ca74a37
cache the wrapping of API endpoint handler modules (i.e. pages/api/*.…
trentm Oct 19, 2022
dac6583
changelog entry; some other doc/comment edits
trentm Oct 20, 2022
ada0a45
Merge branch 'main' into trentm/feat-nextjs
trentm Oct 24, 2022
1729148
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
e621034
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
250b73f
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
1ebd48e
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
931e396
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
b601b22
Update docs/nextjs.asciidoc
trentm Oct 26, 2022
64ca18b
Update examples/nextjs/README.md
trentm Oct 26, 2022
7f7a542
Update examples/nextjs/README.md
trentm Oct 26, 2022
3e2d15b
doc updates (mainly using preview:[]) from Brandon's review
trentm Oct 26, 2022
5ae3a2f
support Next.js 13 and fixes for versions of next before 12.3.1
trentm Oct 27, 2022
33a6510
fix lint
trentm Oct 27, 2022
870c5bb
Merge branch 'main' into trentm/feat-nextjs
trentm Oct 27, 2022
94586a9
changelog tweak after merge
trentm Oct 27, 2022
15c2e9c
test fix: only test next instr with node >=14.6.0 (the min support wi…
trentm Oct 27, 2022
abed53d
clear out last XXXs that were there while this was still on a feature…
trentm Oct 28, 2022
58990ea
a couple final doc/comment edits
trentm Oct 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ci/.jenkins_tav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ TAV:
- mongodb-core
- mysql
- mysql2
- next
- pg
- pug
- redis
Expand Down
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
"node_modules",
"/examples/esbuild/dist",
"/examples/typescript/dist",
"/examples/nextjs",
"/lib/opentelemetry-bridge/opentelemetry-core-mini",
"/test/babel/out.js",
"/test/lambda/fixtures/esbuild-bundled-handler/hello.js",
"/test/instrumentation/modules/next/a-nextjs-app/pages",
"/test/instrumentation/modules/next/a-nextjs-app/components",
"/test/sourcemaps/fixtures/lib",
"/test/sourcemaps/fixtures/src",
"/test/stacktraces/fixtures/dist",
Expand Down
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ updates:
open-pull-requests-limit: 10
reviewers:
- "elastic/apm-agent-node-js"

- package-ecosystem: "npm"
directory: "/test/instrumentation/modules/next/a-nextjs-app"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
reviewers:
- "elastic/apm-agent-node-js"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ node_modules
/test/benchmarks/.tmp
/tmp
/examples/*/dist
.next
21 changes: 21 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Notes:
[[release-notes-3.x]]
=== Node.js Agent version 3.x


==== Unreleased

[float]
Expand All @@ -41,12 +42,31 @@ Notes:

* Enable support for redis v4 ({pull}2945[#2945])

* preview:[] Next.js server-side instrumentation. See the <<nextjs>> document.
+
This adds instrumentation of the Next.js dev server (`next dev`) and prod
server (`next start`). The APM transactions for incoming HTTP requests to the
server will be named appropriately based on Next.js's routing -- both for
user page routes (e.g. `GET /a-dynamic-page/[id]`) and for internal Next.js
routes (e.g. `Next.js _next/data route my-page`,
`Next.js Rewrite route /foo -> /bar`). As well, exceptions in server-side code
(e.g. `getServerSideProps`, server-side run page handlers, API handlers) will
be reported. ({pull}2959[#2959])
+
This is a technical preview to get feedback from Next.js users. The details on
how exactly the instrumentation works may change in future versions.

* Improve container-info gathering to support AWS ECS/Fargate environments.
({issues}2914[#2914])

[float]
===== Bug fixes

* Source lines of context in stacktraces is *no longer reported* for "*.min.js"
files that do not have source-map information. These files are assumed to
be minimized files, for which source line context won't be useful. This
change is to guard against excessively large stacktrace data.

[float]
===== Chores

Expand All @@ -55,6 +75,7 @@ Notes:
central config. The re-fetch delay is clamped to `[5 seconds, 1 day]`.
({issues}2941[#2941])


[[release-notes-3.39.0]]
==== 3.39.0 2022/10/17

Expand Down
Binary file added docs/images/nextjs-my-app-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
212 changes: 212 additions & 0 deletions docs/nextjs.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
:framework: Next.js

[[nextjs]]

ifdef::env-github[]
NOTE: For the best reading experience,
please view this documentation at https://www.elastic.co/guide/en/apm/agent/nodejs/current/nextjs.html[elastic.co]
endif::[]

=== Get started with Next.js

The Elastic APM Node.js agent can be used to trace the Next.js server (`next
start` or `next dev`) that runs your application without the need for code
changes to your app. The APM transactions for incoming HTTP requests to the
server will be named for the https://nextjs.org/docs/routing/introduction[pages]
and https://nextjs.org/docs/api-routes/introduction[API endpoints] in your
application, as well as for internal routes used by Next.js. Errors in code run
on the server will be reported for viewing in the Kibana APM app.

Note that the Node.js APM agent can only instrument _server-side_ code. To
monitor the client-side parts of a Next.js application, see the
{apm-rum-ref}/intro.html[Elastic RUM agent].

NOTE: preview:[] This Next.js instrumentation is a _technical preview_ while we
solicit feedback from Next.js users. If you are a Next.js user, please help us
provide a better Next.js observability experience with your feedback on our
https://discuss.elastic.co/tags/c/apm/nodejs[Discuss forum].


[float]
[[nextjs-prerequisites]]
==== Prerequisites

You need an APM Server to send APM data to. Follow the
{apm-guide-ref}/apm-quick-start.html[APM Quick start] if you have not set one up
yet. You will need your *APM server URL* and an APM server *secret token* (or
*API key*) for configuring the APM agent below.

You will also need a Next.js application to monitor. If you do not have an
existing one to use, you can use the following to create a starter app (see
https://nextjs.org/docs/getting-started[Next.js Getting Started docs] for more):

[source,bash]
----
npx create-next-app@latest # use the defaults
cd my-app
----

You can also take a look at and use this https://github.com/elastic/apm-agent-nodejs/tree/main/examples/nextjs/[Next.js + Elastic APM example app].

NOTE: XXX Until this is merged, the example is at: <https://github.com/elastic/apm-agent-nodejs/tree/trentm/feat-nextjs/examples/nextjs/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XXX cleanup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have a checklist bullet for this in the description above.


[float]
[[nextjs-setup]]
==== Step 1: Add the APM agent dependency

Add the `elastic-apm-node` module as a dependency to your application:

[source,bash]
----
npm install elastic-apm-node --save # or 'yarn add elastic-apm-node'
----

NOTE: XXX Until this is in a release use `npm install "elastic-apm-node@elastic/apm-agent-nodejs#trentm/feat-nextjs"`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XXX cleanup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have a checklist bullet for this in the description above.



[float]
==== Step 2: Start the APM agent

For the APM agent to instrument the Next.js server, it needs to be started
before the Next.js server code is loaded. The best way to do so is by using
Node's https://nodejs.org/api/cli.html#-r---require-module[`--require`] option
to load the "elastic-apm-node/start-next.js" module -- this will start the agent
(plus a little more for Next.js integration).

Edit the "dev" and "start" scripts in your "package.json" as follows:

[source,json]
----
{
// ...
"scripts": {
"dev": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next dev",
"build": "next build",
"start": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next start",
"lint": "next lint"
},
// ...
}
----


[float]
==== Step 3: Configure the APM agent

The APM agent can be
<<configuring-the-agent,configured>>
with environment variables or with an "elastic-apm-node.js" module in the
current working directory. Note that because the APM agent is being loaded
before the Next.js server, the
https://nextjs.org/docs/basic-features/environment-variables[Next.js-supported
".env" files] *cannot* be used to configure the APM agent. We will use an
"elastic-apm-node.js" file here.

Create an "elastic-apm-node.js" file in the application root with the APM server
URL and secret token values from the <<nextjs-prerequisites>> section above:

[source,javascript]
----
// elastic-apm-node.js
module.exports = {
serverUrl: 'https://...', // E.g. https://my-deployment-name.apm.us-west2.gcp.elastic-cloud.com
secretToken: '...'
}
----

The equivalent using environment variables is:

[source,bash]
----
export ELASTIC_APM_SERVER_URL='https://...'
export ELASTIC_APM_SECRET_TOKEN='...'
----

See the <<configuration,agent configuration guide>> for full details on supported configuration variables.


[float]
==== Step 4: Start your Next.js app

[source,bash]
----
npm run dev # or 'npm run build && npm start' for the production server
----

Open <http://localhost:3000> in your browser to load your Next.js app. If you
used the `create-next-app` tool above, it defines an
http://localhost:3000/api/hello[/api/hello] API endpoint. You can provide some
artificial load by running the following in a separate terminal:

[source,bash]
----
while true; do sleep 1; curl -i http://localhost:3000/api/hello; done
----

Visit your Kibana APM app and, after a few seconds, you should see a service
entry for your Next.js app. The service name will be pulled from the "name"
field in "package.json". It can be overriden with
<<service-name,`serviceName`>>. Here is an example:

image::./images/nextjs-my-app-screenshot.png[Kibana APM app showing Next.js my-app]


[float]
[[nextjs-limitations]]
==== Limitations and future work

This Next.js instrumentation has some limitations to be aware of.

Next.js build tooling bundles dependencies (using Webpack) for both client _and_
server-side code execution. The Node.js APM agent does not work when bundled.
See <<start-bundlers>> for details. The implication for Next.js instrumentation
is that you cannot directly import and use the APM agent in your code. That
means that using the <<agent-api>> for manual instrumentation is not currently
possible.

This instrumentation supports naming APM transactions for many internal Next.js
routes. For example, for
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props[server-side
rendering (SSR)] Next.js client code will make requests of the form `GET
/next/_data/$buildId/$page.json`, for which the APM agent names the transaction
`Next.js _next/data route $page`. However, there is a limitation with the
Next.js "public folder catchall" route. HTTP requests that resolve to files in
your "public/" directory, for example `GET /favicon.ico`, will result in a
transaction named `GET unknown route`. See <<nextjs-unknown-routes>> below.

If you notice other limitations or have any suggestions, please give us feedback
on our https://discuss.elastic.co/tags/c/apm/nodejs[Discuss forum].


[float]
[[nextjs-performance-monitoring]]
==== Performance monitoring

Elastic APM automatically measures the performance of your Next.js application.
It records spans for database queries, external HTTP requests, and other slow
operations that happen during requests to your Next.js app. Spans are grouped in
transactions -- by default one for each incoming HTTP request.

[float]
[[nextjs-unknown-routes]]
==== Unknown routes

include::./shared-set-up.asciidoc[tag=unknown-roots]

[float]
[[nextjs-filter-sensitive-information]]
==== Filter sensitive information

include::./shared-set-up.asciidoc[tag=filter-sensitive-info]

[float]
[[nextjs-compatibility]]
==== Compatibility

include::./shared-set-up.asciidoc[tag=compatibility-link]

[float]
[[nextjs-troubleshooting]]
==== Troubleshooting

include::./shared-set-up.asciidoc[tag=troubleshooting-link]
17 changes: 11 additions & 6 deletions docs/set-up.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ To get you off the ground, we've prepared guides for setting up the Agent with a
// This tagged region is used throughout the documentation to link to the framework guides
// Updates made here will be applied elsewhere as well.
// tag::web-frameworks-list[]
* <<lambda>>
* <<express>>
* <<fastify>>
* <<hapi>>
* <<koa>>
* <<nextjs>>
* <<restify>>
* <<fastify>>
* <<typescript>>
* <<lambda>>
* <<nextjs>>
// end::web-frameworks-list[]

Alternatively, you can <<custom-stack>>.
Expand All @@ -26,21 +28,24 @@ Other useful documentation includes:
* <<api>>
* <<troubleshooting>>

include::./lambda.asciidoc[]

include::./express.asciidoc[]

include::./fastify.asciidoc[]

include::./hapi.asciidoc[]

include::./koa.asciidoc[]

include::./restify.asciidoc[]
include::./nextjs.asciidoc[]

include::./fastify.asciidoc[]
include::./restify.asciidoc[]

include::./typescript.asciidoc[]

include::./custom-stack.asciidoc[]

include::./lambda.asciidoc[]

[[starting-the-agent]]
=== Starting the agent
Expand Down Expand Up @@ -97,7 +102,7 @@ A limitation of this approach is that you cannot configure the agent with an opt
[[start-option-node-require-opt]]
===== `node -r elastic-apm-node/start ...`

Another way to start the agent is with the `-r elastic-apm-node/start` https://nodejs.org/api/cli.html#-r---require-module[command line option to `node`]. This will import and start the APM agent before your application code starts. This method allows you to enable the agent _without touching any code_. This is the recommended start method for <<lambda,monitoring AWS Lambda functions>>.
Another way to start the agent is with the `-r elastic-apm-node/start` https://nodejs.org/api/cli.html#-r---require-module[command line option to `node`]. This will import and start the APM agent before your application code starts. This method allows you to enable the agent _without touching any code_. This is the recommended start method for <<lambda,monitoring AWS Lambda functions>> and for tracing <<nextjs,a Next.js server>>.

[source,bash]
----
Expand Down
2 changes: 1 addition & 1 deletion docs/supported-technologies.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ This agent is compatible with {apm-guide-ref}[APM Server] v6.6 and above.

Though you can use Elastic APM <<custom-stack,with any Node.js framework>>,
we automate a few things for the most popular Node.js modules.

These are the frameworks that we officially support:

[options="header"]
Expand All @@ -94,6 +93,7 @@ These are the frameworks that we officially support:
| <<hapi,@hapi/hapi>> | >=17.9.0 <21.0.0 |
| <<hapi,hapi>> | >=9.0.0 <19.0.0 | Deprecated. No longer tested.
| <<koa,Koa>> via koa-router or @koa/router | >=5.2.0 <13.0.0 | Koa doesn't have a built in router, so we can't support Koa directly since we rely on router information for full support. We currently support the most popular Koa router called https://github.com/koajs/koa-router[koa-router].
| <<nextjs,Next.js>> | >=11.1.0 <13.0.0 | (Technical Preview) This instruments Next.js routing to name transactions for incoming HTTP transactions; and reports errors in user pages. It supports the Next.js production server (`next start`) and development server (`next dev`). See the <<nextjs,Getting Started document>>.
| <<restify,Restify>> | >=5.2.0 |
|=======================================================================

Expand Down
3 changes: 3 additions & 0 deletions examples/nextjs/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
Loading