securenow 5.0.0 → 5.0.2
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/CONSUMING-APPS-GUIDE.md +415 -0
- package/NPM_README.md +1328 -0
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +455 -0
- package/docs/ENVIRONMENT-VARIABLES.md +652 -0
- package/docs/EXPRESS-SETUP-GUIDE.md +720 -0
- package/docs/INDEX.md +206 -147
- package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
- package/package.json +4 -2
- package/tracing.d.ts +182 -182
- package/tracing.js +2 -2
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
# Next.js Setup Guide - SecureNow Observability
|
|
2
|
+
|
|
3
|
+
Complete guide to add distributed tracing and logging to your Next.js application using SecureNow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Next.js 13 or higher (works with both App Router and Pages Router)
|
|
10
|
+
- Node.js 18 or higher
|
|
11
|
+
- An OTLP-compatible observability backend
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install securenow
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Start - App Router (Next.js 13+)
|
|
24
|
+
|
|
25
|
+
### Step 1: Install Package
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install securenow
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2: Create `instrumentation.ts`
|
|
32
|
+
|
|
33
|
+
Create `instrumentation.ts` (or `.js`) in your project root (same level as `app/` directory):
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// instrumentation.ts
|
|
37
|
+
export async function register() {
|
|
38
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
39
|
+
// Enable logging
|
|
40
|
+
process.env.SECURENOW_LOGGING_ENABLED = '1';
|
|
41
|
+
|
|
42
|
+
// Initialize tracing and logging
|
|
43
|
+
await import('securenow/register');
|
|
44
|
+
await import('securenow/console-instrumentation');
|
|
45
|
+
|
|
46
|
+
console.log('SecureNow observability initialized');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 3: Enable Instrumentation Hook
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// next.config.js
|
|
55
|
+
/** @type {import('next').NextConfig} */
|
|
56
|
+
const nextConfig = {
|
|
57
|
+
experimental: {
|
|
58
|
+
instrumentationHook: true,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
module.exports = nextConfig;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Step 4: Create `.env.local`
|
|
66
|
+
|
|
67
|
+
```env
|
|
68
|
+
SECURENOW_APPID=my-nextjs-app
|
|
69
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
70
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
71
|
+
SECURENOW_CAPTURE_BODY=1
|
|
72
|
+
NODE_ENV=development
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Step 5: Run Your Application
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm run dev
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
You should see:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
[securenow] OTel SDK started → http://localhost:4318/v1/traces
|
|
85
|
+
[securenow] 📋 Logging: ENABLED → http://localhost:4318/v1/logs
|
|
86
|
+
[securenow] Console instrumentation installed
|
|
87
|
+
SecureNow observability initialized
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Done!** Your Next.js app is now sending traces and logs.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Complete Examples
|
|
95
|
+
|
|
96
|
+
### API Route with Logging
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// app/api/users/route.ts
|
|
100
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
101
|
+
|
|
102
|
+
export async function GET(request: NextRequest) {
|
|
103
|
+
console.log('GET /api/users called', {
|
|
104
|
+
searchParams: Object.fromEntries(request.nextUrl.searchParams),
|
|
105
|
+
headers: Object.fromEntries(request.headers),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const users = await fetchUsersFromDatabase();
|
|
110
|
+
|
|
111
|
+
console.info('Users fetched successfully', {
|
|
112
|
+
count: users.length,
|
|
113
|
+
timestamp: new Date().toISOString(),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return NextResponse.json(users);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Failed to fetch users', {
|
|
119
|
+
error: error.message,
|
|
120
|
+
stack: error.stack,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return NextResponse.json(
|
|
124
|
+
{ error: 'Failed to fetch users' },
|
|
125
|
+
{ status: 500 }
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function POST(request: NextRequest) {
|
|
131
|
+
const body = await request.json();
|
|
132
|
+
|
|
133
|
+
console.info('Creating new user', {
|
|
134
|
+
email: body.email,
|
|
135
|
+
name: body.name,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// Validation
|
|
140
|
+
if (!body.email || !body.name) {
|
|
141
|
+
console.warn('Validation failed', { body });
|
|
142
|
+
return NextResponse.json(
|
|
143
|
+
{ error: 'Email and name required' },
|
|
144
|
+
{ status: 400 }
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const user = await createUserInDatabase(body);
|
|
149
|
+
|
|
150
|
+
console.log('User created successfully', {
|
|
151
|
+
userId: user.id,
|
|
152
|
+
email: user.email,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return NextResponse.json(user, { status: 201 });
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('Failed to create user', {
|
|
158
|
+
error: error.message,
|
|
159
|
+
body,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return NextResponse.json(
|
|
163
|
+
{ error: 'Failed to create user' },
|
|
164
|
+
{ status: 500 }
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Server Component with Logging
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// app/dashboard/page.tsx
|
|
174
|
+
export default async function DashboardPage() {
|
|
175
|
+
console.log('Dashboard page rendering started');
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const data = await fetchDashboardData();
|
|
179
|
+
|
|
180
|
+
console.info('Dashboard data loaded', {
|
|
181
|
+
itemCount: data.items.length,
|
|
182
|
+
timestamp: Date.now(),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<div>
|
|
187
|
+
<h1>Dashboard</h1>
|
|
188
|
+
<div>Items: {data.items.length}</div>
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('Dashboard data fetch failed', {
|
|
193
|
+
error: error.message,
|
|
194
|
+
stack: error.stack,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return <div>Error loading dashboard</div>;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Server Action with Logging
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// app/actions.ts
|
|
206
|
+
'use server';
|
|
207
|
+
|
|
208
|
+
export async function createUser(formData: FormData) {
|
|
209
|
+
const name = formData.get('name') as string;
|
|
210
|
+
const email = formData.get('email') as string;
|
|
211
|
+
|
|
212
|
+
console.info('Form submission received', { name, email });
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const result = await saveUserToDatabase({ name, email });
|
|
216
|
+
|
|
217
|
+
console.log('User saved successfully', {
|
|
218
|
+
userId: result.id,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return { success: true, id: result.id };
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('Form submission failed', {
|
|
224
|
+
error: error.message,
|
|
225
|
+
formData: { name, email },
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return { success: false, error: error.message };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Middleware with Logging
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// middleware.ts
|
|
237
|
+
import { NextResponse } from 'next/server';
|
|
238
|
+
import type { NextRequest } from 'next/server';
|
|
239
|
+
|
|
240
|
+
export function middleware(request: NextRequest) {
|
|
241
|
+
console.log('Middleware executed', {
|
|
242
|
+
path: request.nextUrl.pathname,
|
|
243
|
+
method: request.method,
|
|
244
|
+
userAgent: request.headers.get('user-agent'),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Authentication check
|
|
248
|
+
const token = request.cookies.get('auth-token');
|
|
249
|
+
|
|
250
|
+
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
|
|
251
|
+
console.warn('Unauthorized access attempt', {
|
|
252
|
+
path: request.nextUrl.pathname,
|
|
253
|
+
ip: request.ip,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return NextResponse.redirect(new URL('/login', request.url));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
console.log('Middleware passed', { path: request.nextUrl.pathname });
|
|
260
|
+
return NextResponse.next();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export const config = {
|
|
264
|
+
matcher: ['/dashboard/:path*', '/api/:path*'],
|
|
265
|
+
};
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Pages Router Setup (Next.js 12 and below)
|
|
271
|
+
|
|
272
|
+
### Step 1: Modify `_app.js` or `_app.tsx`
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// pages/_app.tsx
|
|
276
|
+
if (typeof window === 'undefined') {
|
|
277
|
+
// Only run on server-side
|
|
278
|
+
require('securenow/register');
|
|
279
|
+
require('securenow/console-instrumentation');
|
|
280
|
+
console.log('SecureNow initialized');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
import type { AppProps } from 'next/app';
|
|
284
|
+
|
|
285
|
+
function MyApp({ Component, pageProps }: AppProps) {
|
|
286
|
+
return <Component {...pageProps} />;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export default MyApp;
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Step 2: Create `.env.local`
|
|
293
|
+
|
|
294
|
+
```env
|
|
295
|
+
SECURENOW_APPID=my-nextjs-app
|
|
296
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
297
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Step 3: Use in API Routes
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
// pages/api/users.ts
|
|
304
|
+
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
305
|
+
|
|
306
|
+
export default async function handler(
|
|
307
|
+
req: NextApiRequest,
|
|
308
|
+
res: NextApiResponse
|
|
309
|
+
) {
|
|
310
|
+
console.log('API route called', {
|
|
311
|
+
method: req.method,
|
|
312
|
+
query: req.query,
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
if (req.method === 'GET') {
|
|
316
|
+
const users = await fetchUsers();
|
|
317
|
+
console.info('Users fetched', { count: users.length });
|
|
318
|
+
res.status(200).json(users);
|
|
319
|
+
} else if (req.method === 'POST') {
|
|
320
|
+
console.info('Creating user', { body: req.body });
|
|
321
|
+
const user = await createUser(req.body);
|
|
322
|
+
console.log('User created', { userId: user.id });
|
|
323
|
+
res.status(201).json(user);
|
|
324
|
+
} else {
|
|
325
|
+
res.status(405).json({ error: 'Method not allowed' });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Step 4: Run
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
npm run dev
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Environment Variables
|
|
339
|
+
|
|
340
|
+
### Required
|
|
341
|
+
|
|
342
|
+
```env
|
|
343
|
+
# Your application identifier
|
|
344
|
+
SECURENOW_APPID=my-nextjs-app
|
|
345
|
+
|
|
346
|
+
# Your OTLP collector endpoint
|
|
347
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Recommended
|
|
351
|
+
|
|
352
|
+
```env
|
|
353
|
+
# Enable logging
|
|
354
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
355
|
+
|
|
356
|
+
# Enable request body capture (for debugging)
|
|
357
|
+
SECURENOW_CAPTURE_BODY=1
|
|
358
|
+
|
|
359
|
+
# Max body size (default: 10KB)
|
|
360
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
361
|
+
|
|
362
|
+
# Environment name
|
|
363
|
+
NODE_ENV=development
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Optional
|
|
367
|
+
|
|
368
|
+
```env
|
|
369
|
+
# Authentication headers
|
|
370
|
+
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-key
|
|
371
|
+
|
|
372
|
+
# Disable UUID suffix on service name
|
|
373
|
+
SECURENOW_NO_UUID=1
|
|
374
|
+
|
|
375
|
+
# Enable debug logging
|
|
376
|
+
OTEL_LOG_LEVEL=debug
|
|
377
|
+
|
|
378
|
+
# Additional sensitive fields to redact
|
|
379
|
+
SECURENOW_SENSITIVE_FIELDS=internal_token,session_key
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Deployment
|
|
385
|
+
|
|
386
|
+
### Vercel
|
|
387
|
+
|
|
388
|
+
**Step 1: Ensure instrumentation is set up**
|
|
389
|
+
|
|
390
|
+
Your `instrumentation.ts` file will be automatically detected by Vercel.
|
|
391
|
+
|
|
392
|
+
**Step 2: Add environment variables in Vercel Dashboard**
|
|
393
|
+
|
|
394
|
+
Go to Project Settings → Environment Variables:
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
SECURENOW_APPID=my-nextjs-app-prod
|
|
398
|
+
SECURENOW_INSTANCE=http://your-collector:4318
|
|
399
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
400
|
+
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-key
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Step 3: Deploy**
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
vercel deploy
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Docker
|
|
410
|
+
|
|
411
|
+
**Dockerfile:**
|
|
412
|
+
|
|
413
|
+
```dockerfile
|
|
414
|
+
FROM node:20-alpine AS base
|
|
415
|
+
|
|
416
|
+
# Install dependencies
|
|
417
|
+
FROM base AS deps
|
|
418
|
+
WORKDIR /app
|
|
419
|
+
|
|
420
|
+
COPY package.json package-lock.json ./
|
|
421
|
+
RUN npm ci
|
|
422
|
+
|
|
423
|
+
# Build
|
|
424
|
+
FROM base AS builder
|
|
425
|
+
WORKDIR /app
|
|
426
|
+
|
|
427
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
428
|
+
COPY . .
|
|
429
|
+
|
|
430
|
+
RUN npm run build
|
|
431
|
+
|
|
432
|
+
# Production
|
|
433
|
+
FROM base AS runner
|
|
434
|
+
WORKDIR /app
|
|
435
|
+
|
|
436
|
+
ENV NODE_ENV=production
|
|
437
|
+
ENV SECURENOW_APPID=my-nextjs-app
|
|
438
|
+
ENV SECURENOW_INSTANCE=http://collector:4318
|
|
439
|
+
ENV SECURENOW_LOGGING_ENABLED=1
|
|
440
|
+
|
|
441
|
+
COPY --from=builder /app/public ./public
|
|
442
|
+
COPY --from=builder /app/.next/standalone ./
|
|
443
|
+
COPY --from=builder /app/.next/static ./.next/static
|
|
444
|
+
|
|
445
|
+
EXPOSE 3000
|
|
446
|
+
|
|
447
|
+
CMD ["node", "server.js"]
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**docker-compose.yml:**
|
|
451
|
+
|
|
452
|
+
```yaml
|
|
453
|
+
version: '3.8'
|
|
454
|
+
|
|
455
|
+
services:
|
|
456
|
+
nextjs:
|
|
457
|
+
build: .
|
|
458
|
+
ports:
|
|
459
|
+
- "3000:3000"
|
|
460
|
+
environment:
|
|
461
|
+
- SECURENOW_APPID=my-nextjs-app
|
|
462
|
+
- SECURENOW_INSTANCE=http://collector:4318
|
|
463
|
+
- SECURENOW_LOGGING_ENABLED=1
|
|
464
|
+
- SECURENOW_CAPTURE_BODY=1
|
|
465
|
+
- NODE_ENV=production
|
|
466
|
+
depends_on:
|
|
467
|
+
- collector
|
|
468
|
+
|
|
469
|
+
collector:
|
|
470
|
+
image: otel/opentelemetry-collector:latest
|
|
471
|
+
ports:
|
|
472
|
+
- "4318:4318"
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Run:
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
docker-compose up
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Advanced Features
|
|
484
|
+
|
|
485
|
+
### Request Body Capture
|
|
486
|
+
|
|
487
|
+
Enable to see request bodies in your traces:
|
|
488
|
+
|
|
489
|
+
```env
|
|
490
|
+
SECURENOW_CAPTURE_BODY=1
|
|
491
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
This captures:
|
|
495
|
+
- POST/PUT/PATCH request bodies
|
|
496
|
+
- JSON payloads
|
|
497
|
+
- Form data
|
|
498
|
+
- GraphQL queries
|
|
499
|
+
|
|
500
|
+
**Note:** File uploads (multipart) are not captured.
|
|
501
|
+
|
|
502
|
+
### Custom Logger
|
|
503
|
+
|
|
504
|
+
For more control:
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// app/api/custom/route.ts
|
|
508
|
+
import { getLogger } from 'securenow/tracing';
|
|
509
|
+
|
|
510
|
+
const logger = getLogger('api-handler', '1.0.0');
|
|
511
|
+
|
|
512
|
+
export async function POST(request: NextRequest) {
|
|
513
|
+
logger?.emit({
|
|
514
|
+
severityNumber: 9,
|
|
515
|
+
severityText: 'INFO',
|
|
516
|
+
body: 'Custom log message',
|
|
517
|
+
attributes: {
|
|
518
|
+
endpoint: '/api/custom',
|
|
519
|
+
timestamp: Date.now(),
|
|
520
|
+
},
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
return NextResponse.json({ success: true });
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Multiple Logger Instances
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
import { getLogger } from 'securenow/tracing';
|
|
531
|
+
|
|
532
|
+
const authLogger = getLogger('auth', '1.0.0');
|
|
533
|
+
const dbLogger = getLogger('database', '1.0.0');
|
|
534
|
+
const cacheLogger = getLogger('cache', '1.0.0');
|
|
535
|
+
|
|
536
|
+
// Use different loggers for different concerns
|
|
537
|
+
authLogger?.emit({ ... });
|
|
538
|
+
dbLogger?.emit({ ... });
|
|
539
|
+
cacheLogger?.emit({ ... });
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## Troubleshooting
|
|
545
|
+
|
|
546
|
+
### Instrumentation Not Working
|
|
547
|
+
|
|
548
|
+
**Check file location:**
|
|
549
|
+
|
|
550
|
+
`instrumentation.ts` must be in the project root (same level as `app/` or `pages/`), NOT inside `app/` or `src/`.
|
|
551
|
+
|
|
552
|
+
```
|
|
553
|
+
my-nextjs-app/
|
|
554
|
+
├── app/
|
|
555
|
+
├── instrumentation.ts ← Here
|
|
556
|
+
├── next.config.js
|
|
557
|
+
└── package.json
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Check next.config.js:**
|
|
561
|
+
|
|
562
|
+
```javascript
|
|
563
|
+
module.exports = {
|
|
564
|
+
experimental: {
|
|
565
|
+
instrumentationHook: true, // This is required!
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Restart dev server:**
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
# Kill the server completely
|
|
574
|
+
# Then start again
|
|
575
|
+
npm run dev
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Traces Not Appearing
|
|
579
|
+
|
|
580
|
+
**Enable debug logging:**
|
|
581
|
+
|
|
582
|
+
```env
|
|
583
|
+
OTEL_LOG_LEVEL=debug
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Look for:
|
|
587
|
+
```
|
|
588
|
+
[securenow] OTel SDK started → http://localhost:4318/v1/traces
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**Check collector endpoint:**
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
curl http://localhost:4318/v1/traces
|
|
595
|
+
# Should return 200 or 405
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Logs Not Appearing
|
|
599
|
+
|
|
600
|
+
**Check logging is enabled:**
|
|
601
|
+
|
|
602
|
+
```env
|
|
603
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
**Verify console instrumentation:**
|
|
607
|
+
|
|
608
|
+
Look for:
|
|
609
|
+
```
|
|
610
|
+
[securenow] Console instrumentation installed
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
**Check initialization order in instrumentation.ts:**
|
|
614
|
+
|
|
615
|
+
```typescript
|
|
616
|
+
// ✅ Correct order
|
|
617
|
+
await import('securenow/register');
|
|
618
|
+
await import('securenow/console-instrumentation');
|
|
619
|
+
|
|
620
|
+
// ❌ Wrong order
|
|
621
|
+
await import('securenow/console-instrumentation');
|
|
622
|
+
await import('securenow/register');
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### Duplicate Logs
|
|
626
|
+
|
|
627
|
+
If you see duplicate logs, check that you're not:
|
|
628
|
+
|
|
629
|
+
1. Logging both on client and server
|
|
630
|
+
2. Having multiple instances of console instrumentation
|
|
631
|
+
3. Using custom logger AND console instrumentation together
|
|
632
|
+
|
|
633
|
+
### Build Errors
|
|
634
|
+
|
|
635
|
+
**Error: Module not found**
|
|
636
|
+
|
|
637
|
+
Make sure SecureNow is in `dependencies` (not `devDependencies`):
|
|
638
|
+
|
|
639
|
+
```bash
|
|
640
|
+
npm install securenow
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**Webpack warnings:**
|
|
644
|
+
|
|
645
|
+
If you see webpack warnings about OpenTelemetry modules, ignore them. They're expected and don't affect functionality.
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## Best Practices
|
|
650
|
+
|
|
651
|
+
### 1. Use Structured Logging
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
// ❌ Bad
|
|
655
|
+
console.log('User 123 logged in');
|
|
656
|
+
|
|
657
|
+
// ✅ Good
|
|
658
|
+
console.log('User logged in', {
|
|
659
|
+
userId: 123,
|
|
660
|
+
email: 'user@example.com',
|
|
661
|
+
timestamp: Date.now(),
|
|
662
|
+
});
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### 2. Log in Server Components and API Routes
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
// app/page.tsx
|
|
669
|
+
export default async function Page() {
|
|
670
|
+
console.log('Page rendering'); // Logged on server
|
|
671
|
+
|
|
672
|
+
const data = await fetchData();
|
|
673
|
+
console.info('Data fetched', { count: data.length });
|
|
674
|
+
|
|
675
|
+
return <div>...</div>;
|
|
676
|
+
}
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### 3. Don't Log in Client Components
|
|
680
|
+
|
|
681
|
+
Client-side console logs won't be captured. Only server-side logs are sent.
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
// app/client-component.tsx
|
|
685
|
+
'use client';
|
|
686
|
+
|
|
687
|
+
export default function ClientComponent() {
|
|
688
|
+
// This will NOT be sent to your observability backend
|
|
689
|
+
console.log('Client-side log');
|
|
690
|
+
|
|
691
|
+
return <div>...</div>;
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### 4. Use Different Environments
|
|
696
|
+
|
|
697
|
+
```env
|
|
698
|
+
# .env.local (development)
|
|
699
|
+
SECURENOW_APPID=my-app-dev
|
|
700
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
701
|
+
SECURENOW_CAPTURE_BODY=1
|
|
702
|
+
OTEL_LOG_LEVEL=debug
|
|
703
|
+
|
|
704
|
+
# .env.production (production)
|
|
705
|
+
SECURENOW_APPID=my-app-prod
|
|
706
|
+
SECURENOW_INSTANCE=http://collector.prod:4318
|
|
707
|
+
SECURENOW_CAPTURE_BODY=0
|
|
708
|
+
OTEL_LOG_LEVEL=error
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### 5. Monitor Server Actions
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
// app/actions.ts
|
|
715
|
+
'use server';
|
|
716
|
+
|
|
717
|
+
export async function submitForm(data: FormData) {
|
|
718
|
+
console.info('Form submitted', {
|
|
719
|
+
fields: Array.from(data.keys()),
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
try {
|
|
723
|
+
await processForm(data);
|
|
724
|
+
console.log('Form processed successfully');
|
|
725
|
+
return { success: true };
|
|
726
|
+
} catch (error) {
|
|
727
|
+
console.error('Form processing failed', { error });
|
|
728
|
+
return { success: false };
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
## Complete Environment Variables Reference
|
|
736
|
+
|
|
737
|
+
```env
|
|
738
|
+
# === Required ===
|
|
739
|
+
SECURENOW_APPID=my-nextjs-app
|
|
740
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
741
|
+
|
|
742
|
+
# === Logging ===
|
|
743
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
744
|
+
|
|
745
|
+
# === Request Body Capture ===
|
|
746
|
+
SECURENOW_CAPTURE_BODY=1
|
|
747
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
748
|
+
SECURENOW_SENSITIVE_FIELDS=custom1,custom2
|
|
749
|
+
|
|
750
|
+
# === Service Naming ===
|
|
751
|
+
SECURENOW_NO_UUID=1
|
|
752
|
+
OTEL_SERVICE_NAME=my-nextjs-app
|
|
753
|
+
|
|
754
|
+
# === Connection ===
|
|
755
|
+
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-key
|
|
756
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
|
|
757
|
+
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://localhost:4318/v1/logs
|
|
758
|
+
|
|
759
|
+
# === Debugging ===
|
|
760
|
+
OTEL_LOG_LEVEL=debug
|
|
761
|
+
SECURENOW_TEST_SPAN=1
|
|
762
|
+
|
|
763
|
+
# === Environment ===
|
|
764
|
+
NODE_ENV=development
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Performance
|
|
770
|
+
|
|
771
|
+
- **Minimal overhead:** < 1% CPU impact
|
|
772
|
+
- **Async processing:** No blocking of requests
|
|
773
|
+
- **Server-side only:** Client-side performance unaffected
|
|
774
|
+
- **Production-ready:** Tested with high-traffic applications
|
|
775
|
+
|
|
776
|
+
---
|
|
777
|
+
|
|
778
|
+
## Next Steps
|
|
779
|
+
|
|
780
|
+
- Check your observability backend for traces and logs
|
|
781
|
+
- Set up dashboards for your API routes
|
|
782
|
+
- Create alerts for errors
|
|
783
|
+
- Monitor performance of Server Components
|
|
784
|
+
|
|
785
|
+
---
|
|
786
|
+
|
|
787
|
+
## Support
|
|
788
|
+
|
|
789
|
+
- **Documentation:** [Main Docs](../README.md)
|
|
790
|
+
- **Examples:** [Next.js Examples](../examples/)
|
|
791
|
+
- **Issues:** GitHub Issues
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
795
|
+
**Your Next.js app is now fully observable!** 🎉
|