@stacknext/next 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/configuration.md +88 -0
- package/docs/custom-spans.md +105 -0
- package/docs/index.md +92 -0
- package/docs/installation.md +97 -0
- package/docs/instrumentation.md +98 -0
- package/docs/troubleshooting.md +78 -0
- package/package.json +4 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
description: Environment variables and verbose tracing behavior for @stacknext/next.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
`@stacknext/next` reads environment variables supplied by `stacknext dev`. The
|
|
9
|
+
application does not import `stacknext.config.json` directly; the CLI resolves
|
|
10
|
+
the config and exports the relevant values to the child process.
|
|
11
|
+
|
|
12
|
+
## Environment variables
|
|
13
|
+
|
|
14
|
+
| Variable | Default | Behavior |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `STACKNEXT_COLLECTOR_URL` | none | Required for tracing. Must be loopback. |
|
|
17
|
+
| `STACKNEXT_TOKEN` | none | Required for tracing. At least 16 characters. |
|
|
18
|
+
| `STACKNEXT_PROJECT_NAME` | project name | Reported to the collector. |
|
|
19
|
+
| `STACKNEXT_SERVICE_NAME` | project or `next-app` | OTel service name. |
|
|
20
|
+
| `STACKNEXT_NEXT_VERSION` | none | Used for environment checks. |
|
|
21
|
+
| `STACKNEXT_CAPTURE_FETCH` | `1` | `0` drops `AppRender.fetch` spans. |
|
|
22
|
+
| `STACKNEXT_CAPTURE_ERRORS` | `1` | `0` makes `onRequestError` a no-op. |
|
|
23
|
+
| `STACKNEXT_DEBUG` | unset | `1` enables debug logs. |
|
|
24
|
+
| `NEXT_OTEL_VERBOSE` | unset | `1` enables the documented Next.js verbose span set. |
|
|
25
|
+
|
|
26
|
+
`stacknext dev` sets these from `stacknext.config.json`:
|
|
27
|
+
`instrumentation.captureFetch` → `STACKNEXT_CAPTURE_FETCH`,
|
|
28
|
+
`instrumentation.captureErrors` → `STACKNEXT_CAPTURE_ERRORS`,
|
|
29
|
+
`instrumentation.verbose` → `NEXT_OTEL_VERBOSE`.
|
|
30
|
+
|
|
31
|
+
<!-- coderabbit-ai-generated:v1 -->
|
|
32
|
+
|
|
33
|
+
<!-- coderabbit-ai-generated-section:v1:e042398001c539a0b51d0ae05cbcd223e5aa7ce932217b716003cea788939d36 -->
|
|
34
|
+
|
|
35
|
+
An explicit `NEXT_OTEL_VERBOSE` environment value wins. For example,
|
|
36
|
+
`NEXT_OTEL_VERBOSE=0` disables verbose tracing even when the config says
|
|
37
|
+
`"verbose": true`. `stacknext dev` overwrites `STACKNEXT_CAPTURE_FETCH`,
|
|
38
|
+
`STACKNEXT_CAPTURE_ERRORS` and `STACKNEXT_DEBUG` from configuration (with the
|
|
39
|
+
CLI debug flag also affecting `STACKNEXT_DEBUG`); inherited values for these
|
|
40
|
+
variables do not take precedence.
|
|
41
|
+
|
|
42
|
+
<!-- /coderabbit-ai-generated:v1 -->
|
|
43
|
+
|
|
44
|
+
## Register options vs environment
|
|
45
|
+
|
|
46
|
+
<!-- coderabbit-ai-generated:v1 -->
|
|
47
|
+
|
|
48
|
+
<!-- coderabbit-ai-generated-section:v1:8045c991239c9f407c0469ae1416579f2a27d6f781161eb4253fee1480f382cf -->
|
|
49
|
+
|
|
50
|
+
`enabled`, `captureFetch`, `serviceName` and `nextVersion` control registration
|
|
51
|
+
and instrumentation for that call. When `transport` is omitted,
|
|
52
|
+
`resolveTransport()` uses the environment directly: `projectName` does not
|
|
53
|
+
override the project reported by that transport, and `collectorUrl` only changes
|
|
54
|
+
the self-instrumentation filter. Provide an explicit `transport` override to
|
|
55
|
+
control the collector or project used for telemetry. With that override,
|
|
56
|
+
`serviceName`, `projectName` and `nextVersion` also override its corresponding
|
|
57
|
+
transport values. The transport requires a valid token and loopback URL.
|
|
58
|
+
|
|
59
|
+
<!-- /coderabbit-ai-generated:v1 -->
|
|
60
|
+
|
|
61
|
+
## Verbose tracing
|
|
62
|
+
|
|
63
|
+
`NEXT_OTEL_VERBOSE=1` adds documented Next.js span types. It:
|
|
64
|
+
|
|
65
|
+
- increases stored span volume and dev-server work;
|
|
66
|
+
- can shorten the effective retention of older events when capacity is reached;
|
|
67
|
+
- does **not** enable body, header, cookie, query-value or SQL-parameter
|
|
68
|
+
capture.
|
|
69
|
+
|
|
70
|
+
Use `stacknext coverage` or `get_project_summary` to see whether verbose
|
|
71
|
+
evidence is present. Unknown span types are retained as evidence instead of
|
|
72
|
+
being mapped to a guessed feature.
|
|
73
|
+
|
|
74
|
+
## What cannot be enabled
|
|
75
|
+
|
|
76
|
+
The config schema rejects:
|
|
77
|
+
|
|
78
|
+
- `privacy.captureHeaders`;
|
|
79
|
+
- `privacy.captureRequestBodies`;
|
|
80
|
+
- `privacy.captureSqlParameters`;
|
|
81
|
+
- `privacy.redactSensitiveData: false`.
|
|
82
|
+
|
|
83
|
+
There are no environment variables that bypass these rules.
|
|
84
|
+
|
|
85
|
+
## Related
|
|
86
|
+
|
|
87
|
+
- [@stacknext/core configuration](../../core/docs/configuration.md)
|
|
88
|
+
- the repository `docs/benchmark.md`
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Custom spans
|
|
3
|
+
description: Add application and Server Action spans with withStackNextSpan, withStackNextSpanSync and withStackNextAction.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Custom spans
|
|
7
|
+
|
|
8
|
+
StackNext exports three optional helpers from `@stacknext/next`. They use the
|
|
9
|
+
existing OpenTelemetry context/provider and do **not** create a second SDK.
|
|
10
|
+
|
|
11
|
+
## Async work
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { withStackNextSpan } from '@stacknext/next'
|
|
15
|
+
|
|
16
|
+
const project = await withStackNextSpan(
|
|
17
|
+
'load project',
|
|
18
|
+
{ attributes: { 'project.id': id } },
|
|
19
|
+
async (span) => {
|
|
20
|
+
const project = await loadProject(id)
|
|
21
|
+
span.setAttribute('project.found', project !== null)
|
|
22
|
+
return project
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Supported signatures:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
withStackNextSpan(name, fn, options?)
|
|
31
|
+
withStackNextSpan(name, options, fn)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The callback receives the active OTel `Span`. Return values and thrown errors
|
|
35
|
+
are preserved. By default a thrown exception is recorded unless it is a Next.js
|
|
36
|
+
control-flow error (`NEXT_NOT_FOUND`, `NEXT_REDIRECT*` or
|
|
37
|
+
`NEXT_HTTP_ERROR_FALLBACK*`). Set `recordException: false` to disable recording.
|
|
38
|
+
|
|
39
|
+
## Synchronous work
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { withStackNextSpanSync } from '@stacknext/next'
|
|
43
|
+
|
|
44
|
+
const rows = withStackNextSpanSync(
|
|
45
|
+
'sqlite batch',
|
|
46
|
+
{ attributes: { 'batch.size': 25 } },
|
|
47
|
+
() => runBatch(),
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Same argument forms and error behavior as the async helper.
|
|
52
|
+
|
|
53
|
+
## Server Actions
|
|
54
|
+
|
|
55
|
+
Successful Server Actions do not reach `onRequestError`, so StackNext cannot see
|
|
56
|
+
them automatically. Wrap the action explicitly:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
'use server'
|
|
60
|
+
|
|
61
|
+
import { withStackNextAction } from '@stacknext/next'
|
|
62
|
+
|
|
63
|
+
export async function updateProject(formData: FormData) {
|
|
64
|
+
return withStackNextAction(
|
|
65
|
+
'action updateProject',
|
|
66
|
+
{ attributes: { 'project.id': String(formData.get('id') ?? '') } },
|
|
67
|
+
async () => {
|
|
68
|
+
// Action body.
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`withStackNextAction` sets `stacknext.span.kind = "action"`. It records only the
|
|
75
|
+
span name and attributes you pass; action arguments, `FormData` values and return
|
|
76
|
+
values are never captured automatically.
|
|
77
|
+
|
|
78
|
+
## Options
|
|
79
|
+
|
|
80
|
+
`StackNextManualSpanOptions`:
|
|
81
|
+
|
|
82
|
+
| Option | Type | Default | Meaning |
|
|
83
|
+
| --- | --- | --- | --- |
|
|
84
|
+
| `attributes` | `Record<string, unknown>` | none | Sanitized before enqueueing. |
|
|
85
|
+
| `kind` | OTel `SpanKind` | `INTERNAL` | Span kind. |
|
|
86
|
+
| `recordException` | boolean | `true` | Record non-control-flow errors. |
|
|
87
|
+
|
|
88
|
+
The helpers add `stacknext.manual = true` and `stacknext.span.kind` after caller
|
|
89
|
+
attributes so coverage cannot be spoofed.
|
|
90
|
+
|
|
91
|
+
## Attribute safety
|
|
92
|
+
|
|
93
|
+
Attributes pass through `sanitizeAttributes`: sensitive keys, headers and URL
|
|
94
|
+
query values are redacted. The collector applies a second pass. Do not put large
|
|
95
|
+
payloads or secrets in attribute values.
|
|
96
|
+
|
|
97
|
+
## What the helpers do not do
|
|
98
|
+
|
|
99
|
+
- They do not automatically trace every Server Component or Server Action.
|
|
100
|
+
- They do not measure work you did not wrap.
|
|
101
|
+
- They do not create a new provider or exporter.
|
|
102
|
+
- They do not capture arguments, return values or bodies.
|
|
103
|
+
|
|
104
|
+
For broader guidance see the repository's `docs/custom-instrumentation.md`
|
|
105
|
+
and `docs/server-actions.md`.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "@stacknext/next"
|
|
3
|
+
description: Next.js instrumentation, OpenTelemetry export, request errors and manual spans for StackNext.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @stacknext/next
|
|
7
|
+
|
|
8
|
+
`@stacknext/next` connects a Next.js App Router application to a local
|
|
9
|
+
StackNext collector. It registers an OpenTelemetry `NodeTracerProvider`, converts
|
|
10
|
+
spans to the StackNext wire format, installs a W3C propagator, forwards
|
|
11
|
+
`onRequestError` hooks and exports optional manual span helpers.
|
|
12
|
+
|
|
13
|
+
## Who should read this
|
|
14
|
+
|
|
15
|
+
Application developers installing StackNext. This is a **public integration
|
|
16
|
+
package** and the only instrumentation package a normal project needs.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add -D @stacknext/cli @stacknext/next
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`@stacknext/next` declares `next >=15.0.0 <17` as a peer dependency. It requires
|
|
25
|
+
the Node.js runtime; the `edge` export exists only to keep Edge bundling safe and
|
|
26
|
+
returns an inert module.
|
|
27
|
+
|
|
28
|
+
## Entry points
|
|
29
|
+
|
|
30
|
+
| Import | Contents |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `@stacknext/next` | `register`, `registerStackNext`, `shutdownStackNext`, `getStackNextRegistration`, `onRequestError`, manual span helpers and exporter utilities. |
|
|
33
|
+
| `@stacknext/next` with the `edge` condition | `./dist/edge.js`, an inert module for Edge bundles. |
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
`stacknext init` creates `instrumentation.ts` (or `.js`) that guards on
|
|
38
|
+
`NEXT_RUNTIME === 'nodejs'` and imports StackNext dynamically:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export async function register(): Promise<void> {
|
|
42
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
43
|
+
const stacknext = await import('@stacknext/next')
|
|
44
|
+
await stacknext.register()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function onRequestError(
|
|
48
|
+
error: unknown,
|
|
49
|
+
request: unknown,
|
|
50
|
+
context: unknown,
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
53
|
+
const stacknext = await import('@stacknext/next')
|
|
54
|
+
stacknext.onRequestError(
|
|
55
|
+
error,
|
|
56
|
+
request as Parameters<typeof stacknext.onRequestError>[1],
|
|
57
|
+
context as Parameters<typeof stacknext.onRequestError>[2],
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Do not replace an existing `instrumentation.ts`. Import `registerStackNext` and
|
|
63
|
+
`onRequestError` into the existing hook instead. See
|
|
64
|
+
[Installation](installation.md).
|
|
65
|
+
|
|
66
|
+
## Behavior
|
|
67
|
+
|
|
68
|
+
- `register()` is inert when `STACKNEXT_COLLECTOR_URL` and `STACKNEXT_TOKEN` are
|
|
69
|
+
absent. A production build can ship safely.
|
|
70
|
+
- If another OpenTelemetry tracer provider is already registered, StackNext
|
|
71
|
+
yields to it and does not replace it.
|
|
72
|
+
- Spans are redacted and normalized before enqueueing.
|
|
73
|
+
- The exporter never performs synchronous network I/O.
|
|
74
|
+
- The transport shares one bounded queue with the Drizzle and Prisma adapters.
|
|
75
|
+
- `shutdownStackNext()` flushes buffered spans and is safe to call more than
|
|
76
|
+
once.
|
|
77
|
+
|
|
78
|
+
## Documentation map
|
|
79
|
+
|
|
80
|
+
- [Installation](installation.md) — peer requirements and safe setup.
|
|
81
|
+
- [Instrumentation](instrumentation.md) — `register`, options and lifecycle.
|
|
82
|
+
- [Configuration](configuration.md) — environment variables and verbose tracing.
|
|
83
|
+
- [Custom spans](custom-spans.md) — `withStackNextSpan*` and Server Actions.
|
|
84
|
+
- [Troubleshooting](troubleshooting.md) — no telemetry, provider conflicts and
|
|
85
|
+
Edge warnings.
|
|
86
|
+
|
|
87
|
+
## Related packages
|
|
88
|
+
|
|
89
|
+
- `@stacknext/core` supplies the wire types, redaction and transport.
|
|
90
|
+
- `@stacknext/drizzle` and `@stacknext/prisma` add database query events to the
|
|
91
|
+
same queue.
|
|
92
|
+
- `@stacknext/cli` runs the collector that receives the data.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: Install @stacknext/next safely without replacing existing instrumentation or monitoring.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node.js `>=20.9.0`.
|
|
11
|
+
- Next.js 15 or 16 with the App Router.
|
|
12
|
+
- The Node.js runtime. Edge instrumentation is not supported.
|
|
13
|
+
- A local StackNext collector started by `stacknext dev`.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install --save-dev @stacknext/cli @stacknext/next
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
or:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add -D @stacknext/cli @stacknext/next
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Install inside the Next.js application package, not at a monorepo root.
|
|
28
|
+
|
|
29
|
+
## Create the hook
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx stacknext init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If the project has no `instrumentation.ts`/`.js`, `init` writes one that:
|
|
36
|
+
|
|
37
|
+
1. runs only when `NEXT_RUNTIME === 'nodejs'`;
|
|
38
|
+
2. dynamically imports `@stacknext/next` so Edge bundling does not load Node-only
|
|
39
|
+
modules;
|
|
40
|
+
3. calls `register()` and `onRequestError`.
|
|
41
|
+
|
|
42
|
+
The generated file is idempotent and recognized by `stacknext uninstall`.
|
|
43
|
+
|
|
44
|
+
## Preserve existing instrumentation
|
|
45
|
+
|
|
46
|
+
Never overwrite an existing hook that another monitoring tool owns. Add
|
|
47
|
+
StackNext inside it:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import {
|
|
51
|
+
registerStackNext,
|
|
52
|
+
onRequestError as stackNextOnRequestError,
|
|
53
|
+
} from '@stacknext/next'
|
|
54
|
+
|
|
55
|
+
export async function register() {
|
|
56
|
+
await startExistingMonitoring()
|
|
57
|
+
await registerStackNext()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Only if the file does not already export an error hook.
|
|
61
|
+
export const onRequestError = stackNextOnRequestError
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If `onRequestError` already exists, call
|
|
65
|
+
`stackNextOnRequestError(error, request, context)` inside it.
|
|
66
|
+
|
|
67
|
+
StackNext checks for an already-registered OpenTelemetry provider and leaves it
|
|
68
|
+
untouched. It does not create a second SDK when another APM is active.
|
|
69
|
+
|
|
70
|
+
## Environment
|
|
71
|
+
|
|
72
|
+
`stacknext dev` supplies:
|
|
73
|
+
|
|
74
|
+
| Variable | Purpose |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `STACKNEXT_COLLECTOR_URL` | Loopback collector origin. |
|
|
77
|
+
| `STACKNEXT_TOKEN` | Bearer token for ingest. |
|
|
78
|
+
| `STACKNEXT_PROJECT_NAME` | Project name reported with telemetry. |
|
|
79
|
+
| `STACKNEXT_NEXT_VERSION` | Next.js version for environment checks. |
|
|
80
|
+
| `STACKNEXT_CAPTURE_FETCH` | `0` drops Next.js fetch spans. |
|
|
81
|
+
| `STACKNEXT_CAPTURE_ERRORS` | `0` disables the error hook. |
|
|
82
|
+
| `STACKNEXT_DEBUG` | `1` enables debug logs. |
|
|
83
|
+
|
|
84
|
+
Do not commit these values. The token lives in `.stacknext/run.json` with mode
|
|
85
|
+
`0600` and is generated per run.
|
|
86
|
+
|
|
87
|
+
## Verify
|
|
88
|
+
|
|
89
|
+
With `stacknext dev` running:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx stacknext doctor
|
|
93
|
+
npx stacknext status
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then make one request and confirm `requests` and `spans` increase. If the
|
|
97
|
+
dashboard is empty, see [Troubleshooting](troubleshooting.md).
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Instrumentation
|
|
3
|
+
description: register, registerStackNext and the OpenTelemetry lifecycle used by StackNext.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Instrumentation
|
|
7
|
+
|
|
8
|
+
## `register(options?)`
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { register } from '@stacknext/next'
|
|
12
|
+
|
|
13
|
+
await register()
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Alias for `registerStackNext()`. Call it from the app's `instrumentation.ts`
|
|
17
|
+
`register()` hook. It returns `null` when tracing is disabled or another
|
|
18
|
+
provider is active.
|
|
19
|
+
|
|
20
|
+
## `registerStackNext(options?)`
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { registerStackNext } from '@stacknext/next'
|
|
24
|
+
|
|
25
|
+
const registration = await registerStackNext()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`StackNextRegisterOptions`:
|
|
29
|
+
|
|
30
|
+
| Option | Type | Meaning |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `transport` | `StackNextTransportOptions` | Overrides environment transport configuration. |
|
|
33
|
+
| `collectorUrl` | string | Collector URL, also used to filter self-instrumentation requests. |
|
|
34
|
+
| `serviceName` | string | OTel service name. Defaults to the transport value or `next-app`. |
|
|
35
|
+
| `projectName` | string | Project name reported to the collector. |
|
|
36
|
+
| `nextVersion` | string | Next.js version for the environment snapshot. |
|
|
37
|
+
| `captureFetch` | boolean | Set `false` to drop `AppRender.fetch` spans. |
|
|
38
|
+
| `enabled` | boolean | Set `false` to keep StackNext loaded but inactive. |
|
|
39
|
+
|
|
40
|
+
It returns a `StackNextRegistration` with `provider`, `transport`, `exporter`,
|
|
41
|
+
`serviceName` and `registeredAt`, or `null`.
|
|
42
|
+
|
|
43
|
+
### Registration order
|
|
44
|
+
|
|
45
|
+
1. Return the existing registration if this process already registered.
|
|
46
|
+
2. Return `null` when `enabled: false` or the runtime is not Node.js.
|
|
47
|
+
3. Return `null` when another OTel provider is already registered.
|
|
48
|
+
4. Resolve the shared transport from options or environment.
|
|
49
|
+
5. Return `null` when collector URL/token are absent.
|
|
50
|
+
6. Build a `NodeTracerProvider` with a `BatchSpanProcessor`:
|
|
51
|
+
- scheduled delay 200 ms;
|
|
52
|
+
- queue size 2,048;
|
|
53
|
+
- export batch 256;
|
|
54
|
+
- export timeout 2,000 ms.
|
|
55
|
+
7. Register the provider and install a composite W3C trace-context and baggage
|
|
56
|
+
propagator.
|
|
57
|
+
8. Store the registration globally and hook `beforeExit` to flush.
|
|
58
|
+
|
|
59
|
+
The propagator is required so an incoming `traceparent` from a local Playwright
|
|
60
|
+
capture becomes the parent of the Next.js request trace.
|
|
61
|
+
|
|
62
|
+
## `getStackNextRegistration()`
|
|
63
|
+
|
|
64
|
+
Returns the active registration without creating one. Useful in tests and
|
|
65
|
+
shutdown code.
|
|
66
|
+
|
|
67
|
+
## `shutdownStackNext()`
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { shutdownStackNext } from '@stacknext/next'
|
|
71
|
+
|
|
72
|
+
await shutdownStackNext()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Flushes buffered spans and shuts down the provider and transport. Safe to call
|
|
76
|
+
more than once. Next.js owns process signals; StackNext only hooks
|
|
77
|
+
`beforeExit`.
|
|
78
|
+
|
|
79
|
+
## Manual exporter utilities
|
|
80
|
+
|
|
81
|
+
`StackNextSpanExporter`, `readableSpanToInput`, `spanAttributes` and
|
|
82
|
+
`StackNextSpanExporterOptions` are exported for tests and custom integrations.
|
|
83
|
+
`readableSpanToInput` returns `null` for invalid ids, internal instrumentation
|
|
84
|
+
spans and requests to the StackNext collector itself. It redacts names,
|
|
85
|
+
attributes, resource attributes and status messages.
|
|
86
|
+
|
|
87
|
+
## Self-instrumentation filter
|
|
88
|
+
|
|
89
|
+
Requests to `/__stacknext/` and the collector origin are excluded so the
|
|
90
|
+
dashboard and MCP traffic do not appear as application requests.
|
|
91
|
+
|
|
92
|
+
## What is not automatic
|
|
93
|
+
|
|
94
|
+
- Server Components are not traced individually.
|
|
95
|
+
- Server Actions are not named automatically. See [Custom spans](custom-spans.md).
|
|
96
|
+
- Application functions and arbitrary database drivers are not inferred.
|
|
97
|
+
- Browser/client tracing is out of scope.
|
|
98
|
+
- Edge runtime is not supported.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Troubleshooting
|
|
3
|
+
description: Diagnose missing Next.js telemetry, provider conflicts, Edge warnings and startup failures.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Troubleshooting
|
|
7
|
+
|
|
8
|
+
## The dashboard is empty
|
|
9
|
+
|
|
10
|
+
1. Confirm the app is started through `stacknext dev`, not `next dev`. The CLI
|
|
11
|
+
supplies the collector URL and token.
|
|
12
|
+
2. Run `stacknext doctor`. It checks Node.js, Next.js, the App Router, config,
|
|
13
|
+
instrumentation, the dashboard build and collector health.
|
|
14
|
+
3. Run `stacknext status --json` and inspect `runtime` and `connections`.
|
|
15
|
+
4. Make a request after the app has fully started.
|
|
16
|
+
5. Check `stacknext coverage`: `active` with no requests means the app is
|
|
17
|
+
connected but the feature has not been exercised yet.
|
|
18
|
+
|
|
19
|
+
## `register()` returns `null`
|
|
20
|
+
|
|
21
|
+
Possible causes:
|
|
22
|
+
|
|
23
|
+
- `STACKNEXT_COLLECTOR_URL` or `STACKNEXT_TOKEN` is missing. Start the app with
|
|
24
|
+
`stacknext dev`.
|
|
25
|
+
- Another OpenTelemetry provider is already registered. Run with
|
|
26
|
+
`STACKNEXT_DEBUG=1` and look for the "leaving it untouched" message. StackNext
|
|
27
|
+
intentionally yields instead of replacing another APM.
|
|
28
|
+
- The runtime is not Node.js. Edge is unsupported.
|
|
29
|
+
- `enabled: false` was passed explicitly.
|
|
30
|
+
|
|
31
|
+
## No error records
|
|
32
|
+
|
|
33
|
+
- Check `instrumentation.captureErrors` and `STACKNEXT_CAPTURE_ERRORS`.
|
|
34
|
+
- Confirm `instrumentation.ts` exports `onRequestError`.
|
|
35
|
+
- An existing `onRequestError` must call `stackNextOnRequestError(...)`.
|
|
36
|
+
- Control-flow errors from not-found/redirect responses are intentionally
|
|
37
|
+
excluded from diagnostics.
|
|
38
|
+
- Errors without an active span context are correlated by route/method and a
|
|
39
|
+
30-second window. They may show as fallback-correlated or uncorrelated.
|
|
40
|
+
|
|
41
|
+
## Missing fetch spans
|
|
42
|
+
|
|
43
|
+
Set `instrumentation.captureFetch` to `true` (the default) and ensure
|
|
44
|
+
`STACKNEXT_CAPTURE_FETCH` is not `0`. Only Next.js-emitted fetch spans can be
|
|
45
|
+
captured.
|
|
46
|
+
|
|
47
|
+
## Edge build warnings or failures
|
|
48
|
+
|
|
49
|
+
Keep every StackNext import behind:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Use a dynamic import inside the hook. Do not import `@stacknext/next` at the top
|
|
56
|
+
level of a module that Edge also bundles.
|
|
57
|
+
|
|
58
|
+
## Existing monitoring stopped working
|
|
59
|
+
|
|
60
|
+
StackNext must never replace a provider. If another tool stops receiving data,
|
|
61
|
+
check whether it registered before or after `registerStackNext()` and whether
|
|
62
|
+
the generated hook was merged into the existing `instrumentation.ts` rather than
|
|
63
|
+
replacing it. `stacknext init` prints a manual patch when a file exists.
|
|
64
|
+
|
|
65
|
+
## Telemetry is dropped
|
|
66
|
+
|
|
67
|
+
The in-memory store is bounded by `collector.maxSpans` and
|
|
68
|
+
`collector.retentionMs`. `/api/health`, `stacknext status` and the dashboard
|
|
69
|
+
settings page report drop counters. `NEXT_OTEL_VERBOSE=1` increases span volume
|
|
70
|
+
and can shorten the effective retention window.
|
|
71
|
+
|
|
72
|
+
## Verify
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
stacknext doctor --json
|
|
76
|
+
stacknext status --json
|
|
77
|
+
stacknext coverage --json
|
|
78
|
+
```
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacknext/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Next.js instrumentation and OpenTelemetry exporter for StackNext",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
8
|
-
"dist"
|
|
8
|
+
"dist",
|
|
9
|
+
"docs"
|
|
9
10
|
],
|
|
10
11
|
"main": "./dist/index.js",
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
"./package.json": "./package.json"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"@stacknext/core": "0.
|
|
27
|
+
"@stacknext/core": "0.11.0",
|
|
27
28
|
"@opentelemetry/api": "1.9.0",
|
|
28
29
|
"@opentelemetry/context-async-hooks": "2.12.0",
|
|
29
30
|
"@opentelemetry/core": "2.12.0",
|