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.
@@ -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!** 🎉