securenow 4.0.6 → 4.0.9

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.
Files changed (46) hide show
  1. package/README.md +4 -3
  2. package/cli.js +4 -1
  3. package/docs/ARCHITECTURE.md +408 -0
  4. package/{AUTO-BODY-CAPTURE.md → docs/AUTO-BODY-CAPTURE.md} +3 -0
  5. package/docs/AUTO-SETUP-SUMMARY.md +331 -0
  6. package/{AUTO-SETUP.md → docs/AUTO-SETUP.md} +3 -0
  7. package/{AUTOMATIC-IP-CAPTURE.md → docs/AUTOMATIC-IP-CAPTURE.md} +3 -0
  8. package/{BODY-CAPTURE-FIX.md → docs/BODY-CAPTURE-FIX.md} +3 -0
  9. package/{BODY-CAPTURE-QUICKSTART.md → docs/BODY-CAPTURE-QUICKSTART.md} +147 -147
  10. package/docs/CHANGELOG-NEXTJS.md +235 -0
  11. package/docs/COMPLETION-REPORT.md +408 -0
  12. package/{EASIEST-SETUP.md → docs/EASIEST-SETUP.md} +3 -0
  13. package/docs/EXPRESS-BODY-CAPTURE.md +1027 -0
  14. package/{FINAL-SOLUTION.md → docs/FINAL-SOLUTION.md} +3 -0
  15. package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
  16. package/docs/INDEX.md +129 -0
  17. package/{NEXTJS-BODY-CAPTURE-COMPARISON.md → docs/NEXTJS-BODY-CAPTURE-COMPARISON.md} +3 -0
  18. package/docs/NEXTJS-WEBPACK-WARNINGS.md +267 -0
  19. package/{NEXTJS-WRAPPER-APPROACH.md → docs/NEXTJS-WRAPPER-APPROACH.md} +3 -0
  20. package/{QUICKSTART-BODY-CAPTURE.md → docs/QUICKSTART-BODY-CAPTURE.md} +3 -0
  21. package/{REDACTION-EXAMPLES.md → docs/REDACTION-EXAMPLES.md} +3 -0
  22. package/{REQUEST-BODY-CAPTURE.md → docs/REQUEST-BODY-CAPTURE.md} +575 -575
  23. package/{SOLUTION-SUMMARY.md → docs/SOLUTION-SUMMARY.md} +3 -0
  24. package/docs/VERCEL-OTEL-MIGRATION.md +255 -0
  25. package/examples/README.md +3 -0
  26. package/examples/instrumentation-with-auto-capture.ts +3 -0
  27. package/examples/next.config.js +3 -0
  28. package/examples/nextjs-api-route-with-body-capture.ts +3 -0
  29. package/examples/nextjs-env-example.txt +3 -0
  30. package/examples/nextjs-instrumentation.js +3 -0
  31. package/examples/nextjs-instrumentation.ts +3 -0
  32. package/examples/nextjs-middleware.js +3 -0
  33. package/examples/nextjs-middleware.ts +3 -0
  34. package/examples/nextjs-with-options.ts +3 -0
  35. package/examples/test-nextjs-setup.js +3 -0
  36. package/nextjs-auto-capture.js +3 -0
  37. package/nextjs-middleware.js +3 -0
  38. package/nextjs-wrapper.js +3 -0
  39. package/nextjs.js +174 -72
  40. package/package.json +3 -19
  41. package/postinstall.js +310 -310
  42. package/tracing.js +287 -287
  43. /package/{CUSTOMER-GUIDE.md → docs/CUSTOMER-GUIDE.md} +0 -0
  44. /package/{NEXTJS-BODY-CAPTURE.md → docs/NEXTJS-BODY-CAPTURE.md} +0 -0
  45. /package/{NEXTJS-GUIDE.md → docs/NEXTJS-GUIDE.md} +0 -0
  46. /package/{NEXTJS-QUICKSTART.md → docs/NEXTJS-QUICKSTART.md} +0 -0
@@ -0,0 +1,1027 @@
1
+ # Request Body Capture for Express.js with PM2
2
+
3
+ This guide shows how to automatically capture request bodies in Express.js applications, including those running with PM2 clustering.
4
+
5
+ **Available for both JavaScript and TypeScript projects!**
6
+
7
+ ## 📖 Table of Contents
8
+
9
+ - [Overview](#-overview)
10
+ - [Quick Start](#-quick-start)
11
+ - [How It Works](#-how-it-works)
12
+ - [Configuration](#-configuration)
13
+ - [PM2 Clustering](#-pm2-clustering)
14
+ - [Supported Content Types](#-supported-content-types)
15
+ - [Complete Example (JS & TS)](#-example-complete-express--pm2-setup)
16
+ - [Testing Body Capture](#-testing-body-capture)
17
+ - [Troubleshooting](#-troubleshooting)
18
+ - [Security Considerations](#-security-considerations)
19
+ - [Performance Impact](#-performance-impact)
20
+ - [TypeScript-Specific Guide](#-typescript-specific-guide)
21
+ - [Advanced Topics](#-advanced-topics)
22
+
23
+ ---
24
+
25
+ ## 🎯 Overview
26
+
27
+ **SecureNow** captures request bodies at the HTTP instrumentation level, **before Express parses them**. This works automatically for most Express apps, but you need to understand how it interacts with Express body parsers.
28
+
29
+ This guide provides examples for both **JavaScript** and **TypeScript** projects.
30
+
31
+ ### JavaScript vs TypeScript
32
+
33
+ | Feature | JavaScript | TypeScript |
34
+ |---------|-----------|------------|
35
+ | **Setup Complexity** | ⚡ Simple | 🔧 Moderate |
36
+ | **Type Safety** | ❌ No | ✅ Yes |
37
+ | **Build Step** | ❌ Not required | ✅ Required |
38
+ | **SecureNow Setup** | Identical | Identical |
39
+ | **Body Capture** | ✅ Works | ✅ Works |
40
+ | **Production Ready** | ✅ Yes | ✅ Yes |
41
+
42
+ **Both work identically with SecureNow!** Choose based on your project preference.
43
+
44
+ ## ⚡ Quick Start
45
+
46
+ ### 1. Install SecureNow
47
+
48
+ ```bash
49
+ npm install securenow
50
+ ```
51
+
52
+ ### 2. Configure Environment Variables
53
+
54
+ Create `.env` or set in PM2 ecosystem file:
55
+
56
+ ```bash
57
+ SECURENOW_APPID=my-express-api
58
+ SECURENOW_INSTANCE=http://your-signoz-server:4318
59
+ SECURENOW_CAPTURE_BODY=1
60
+ SECURENOW_MAX_BODY_SIZE=10240
61
+ ```
62
+
63
+ ### 3. Enable in Express App
64
+
65
+ **Option A: Using `--require` flag (Recommended for PM2)**
66
+
67
+ **JavaScript:**
68
+
69
+ ```javascript
70
+ // app.js - NO changes needed to your code!
71
+ const express = require('express');
72
+ const app = express();
73
+
74
+ app.use(express.json());
75
+
76
+ app.post('/api/login', (req, res) => {
77
+ // Your existing code - body is automatically captured
78
+ res.json({ success: true });
79
+ });
80
+
81
+ app.listen(3000);
82
+ ```
83
+
84
+ **TypeScript:**
85
+
86
+ ```typescript
87
+ // app.ts - NO changes needed to your code!
88
+ import express, { Request, Response } from 'express';
89
+ const app = express();
90
+
91
+ app.use(express.json());
92
+
93
+ app.post('/api/login', (req: Request, res: Response) => {
94
+ // Your existing code - body is automatically captured
95
+ res.json({ success: true });
96
+ });
97
+
98
+ app.listen(3000);
99
+ ```
100
+
101
+ **Start with PM2:**
102
+
103
+ ```bash
104
+ # JavaScript
105
+ pm2 start app.js --node-args="-r securenow/register"
106
+
107
+ # TypeScript (after compiling)
108
+ npm run build
109
+ pm2 start dist/app.js --node-args="-r securenow/register"
110
+ ```
111
+
112
+ **Or in `ecosystem.config.js`:**
113
+
114
+ ```javascript
115
+ module.exports = {
116
+ apps: [{
117
+ name: 'express-api',
118
+ script: './app.js', // or './dist/app.js' for TypeScript
119
+ instances: 4,
120
+ exec_mode: 'cluster',
121
+ node_args: '-r securenow/register',
122
+ env: {
123
+ NODE_ENV: 'production',
124
+ SECURENOW_APPID: 'express-api',
125
+ SECURENOW_CAPTURE_BODY: '1',
126
+ SECURENOW_NO_UUID: '1', // Same service.name across workers
127
+ }
128
+ }]
129
+ };
130
+ ```
131
+
132
+ **Option B: Require in Code**
133
+
134
+ **JavaScript:**
135
+
136
+ ```javascript
137
+ // app.js - Add this at the VERY TOP
138
+ require('securenow/register');
139
+
140
+ const express = require('express');
141
+ // ... rest of your app
142
+ ```
143
+
144
+ **TypeScript:**
145
+
146
+ ```typescript
147
+ // app.ts - Add this at the VERY TOP
148
+ import 'securenow/register';
149
+
150
+ import express from 'express';
151
+ // ... rest of your app
152
+ ```
153
+
154
+ ## 📝 How It Works
155
+
156
+ ### Body Capture Flow
157
+
158
+ ```
159
+ ┌─────────────────────────────────────────────────────────┐
160
+ │ 1. HTTP Request arrives │
161
+ │ ↓ │
162
+ │ 2. SecureNow HTTP Instrumentation reads raw stream │
163
+ │ - Buffers body chunks │
164
+ │ - Does NOT consume stream │
165
+ │ ↓ │
166
+ │ 3. Express body-parser reads stream │
167
+ │ - Parses JSON/form data │
168
+ │ - Populates req.body │
169
+ │ ↓ │
170
+ │ 4. SecureNow captures body on 'end' event │
171
+ │ - Redacts sensitive fields │
172
+ │ - Attaches to OpenTelemetry span │
173
+ │ ↓ │
174
+ │ 5. Your Express handler runs │
175
+ │ - req.body is available as normal │
176
+ └─────────────────────────────────────────────────────────┘
177
+ ```
178
+
179
+ ### Key Points
180
+
181
+ 1. **Stream Buffering**: SecureNow listens to the Node.js HTTP request stream and buffers chunks as they arrive
182
+ 2. **Non-Destructive**: The buffering doesn't consume the stream, so Express can still read it
183
+ 3. **Automatic Redaction**: Sensitive fields (passwords, tokens, etc.) are automatically redacted
184
+ 4. **Size Limiting**: Bodies larger than `SECURENOW_MAX_BODY_SIZE` are not captured
185
+
186
+ ## 🔧 Configuration
187
+
188
+ ### Environment Variables
189
+
190
+ | Variable | Description | Default |
191
+ |----------|-------------|---------|
192
+ | `SECURENOW_CAPTURE_BODY` | Enable body capture (`1` or `true`) | `0` (disabled) |
193
+ | `SECURENOW_MAX_BODY_SIZE` | Max body size in bytes | `10240` (10KB) |
194
+ | `SECURENOW_SENSITIVE_FIELDS` | Comma-separated additional sensitive fields | (see below) |
195
+
196
+ ### Default Sensitive Fields
197
+
198
+ These fields are **automatically redacted**:
199
+
200
+ ```javascript
201
+ 'password', 'passwd', 'pwd', 'secret', 'token', 'api_key', 'apikey',
202
+ 'access_token', 'auth', 'credentials', 'mysql_pwd', 'stripeToken',
203
+ 'card', 'cardnumber', 'ccv', 'cvc', 'cvv', 'ssn', 'pin'
204
+ ```
205
+
206
+ ### Adding Custom Sensitive Fields
207
+
208
+ ```bash
209
+ # In .env or PM2 config
210
+ SECURENOW_SENSITIVE_FIELDS=custom_token,internal_key,private_data
211
+ ```
212
+
213
+ ## 🚀 PM2 Clustering
214
+
215
+ ### Cluster Mode Setup
216
+
217
+ **ecosystem.config.js:**
218
+
219
+ ```javascript
220
+ module.exports = {
221
+ apps: [{
222
+ name: 'express-api',
223
+ script: './server.js',
224
+ instances: 'max', // Use all CPU cores
225
+ exec_mode: 'cluster',
226
+ node_args: '-r securenow/register',
227
+ env: {
228
+ NODE_ENV: 'production',
229
+ SECURENOW_APPID: 'express-api',
230
+ SECURENOW_INSTANCE: 'http://signoz:4318',
231
+ SECURENOW_CAPTURE_BODY: '1',
232
+ SECURENOW_NO_UUID: '1', // Same service.name
233
+ SECURENOW_STRICT: '1', // Fail if APPID missing
234
+ }
235
+ }]
236
+ };
237
+ ```
238
+
239
+ **Start cluster:**
240
+
241
+ ```bash
242
+ pm2 start ecosystem.config.js
243
+ ```
244
+
245
+ ### Service Naming in Clusters
246
+
247
+ **Without `SECURENOW_NO_UUID=1`:**
248
+ - Each worker gets unique service name: `express-api-abc123`, `express-api-def456`
249
+ - Good for debugging individual workers
250
+ - Traces are separated per worker
251
+
252
+ **With `SECURENOW_NO_UUID=1`:**
253
+ - All workers share same service name: `express-api`
254
+ - Traces are grouped together
255
+ - Recommended for production
256
+
257
+ ### Monitoring Workers
258
+
259
+ ```bash
260
+ # View all workers
261
+ pm2 list
262
+
263
+ # View logs (all workers)
264
+ pm2 logs express-api
265
+
266
+ # View logs for specific worker
267
+ pm2 logs express-api --lines 100
268
+ ```
269
+
270
+ ## 📋 Supported Content Types
271
+
272
+ | Content Type | Captured? | Parsed? | Redacted? |
273
+ |--------------|-----------|---------|-----------|
274
+ | `application/json` | ✅ Yes | ✅ Yes | ✅ Yes |
275
+ | `application/graphql` | ✅ Yes | ✅ Yes | ✅ Yes |
276
+ | `application/x-www-form-urlencoded` | ✅ Yes | ✅ Yes | ✅ Yes |
277
+ | `multipart/form-data` | ❌ No | N/A | N/A |
278
+ | `text/plain` | ❌ No | N/A | N/A |
279
+
280
+ **Note**: File uploads (`multipart/form-data`) are intentionally NOT captured for performance and privacy reasons.
281
+
282
+ ## 🔍 Example: Complete Express + PM2 Setup
283
+
284
+ ### Project Structure (JavaScript)
285
+
286
+ ```
287
+ my-express-api/
288
+ ├── server.js
289
+ ├── ecosystem.config.js
290
+ ├── .env
291
+ └── package.json
292
+ ```
293
+
294
+ ### Project Structure (TypeScript)
295
+
296
+ ```
297
+ my-express-api/
298
+ ├── src/
299
+ │ └── server.ts
300
+ ├── dist/
301
+ ├── ecosystem.config.js
302
+ ├── .env
303
+ ├── tsconfig.json
304
+ └── package.json
305
+ ```
306
+
307
+ ---
308
+
309
+ ### server.js (JavaScript)
310
+
311
+ ```javascript
312
+ require('securenow/register'); // At the top!
313
+
314
+ const express = require('express');
315
+ const app = express();
316
+
317
+ // Body parsers
318
+ app.use(express.json());
319
+ app.use(express.urlencoded({ extended: true }));
320
+
321
+ // Routes
322
+ app.post('/api/users', (req, res) => {
323
+ // Body is automatically captured in traces
324
+ // Sensitive fields are redacted
325
+ console.log('Creating user:', req.body.email);
326
+ res.json({ id: 123, email: req.body.email });
327
+ });
328
+
329
+ app.post('/api/login', (req, res) => {
330
+ // Password is automatically redacted in traces
331
+ console.log('Login attempt:', req.body.email);
332
+ res.json({ token: 'abc123' });
333
+ });
334
+
335
+ const PORT = process.env.PORT || 3000;
336
+ app.listen(PORT, () => {
337
+ console.log(`Server running on port ${PORT}, PID: ${process.pid}`);
338
+ });
339
+ ```
340
+
341
+ ### server.ts (TypeScript)
342
+
343
+ ```typescript
344
+ import 'securenow/register'; // At the top!
345
+
346
+ import express, { Request, Response } from 'express';
347
+ const app = express();
348
+
349
+ // Body parsers
350
+ app.use(express.json());
351
+ app.use(express.urlencoded({ extended: true }));
352
+
353
+ // Types for request bodies
354
+ interface CreateUserBody {
355
+ email: string;
356
+ name: string;
357
+ }
358
+
359
+ interface LoginBody {
360
+ email: string;
361
+ password: string;
362
+ }
363
+
364
+ // Routes
365
+ app.post('/api/users', (req: Request<{}, {}, CreateUserBody>, res: Response) => {
366
+ // Body is automatically captured in traces
367
+ // Sensitive fields are redacted
368
+ console.log('Creating user:', req.body.email);
369
+ res.json({ id: 123, email: req.body.email });
370
+ });
371
+
372
+ app.post('/api/login', (req: Request<{}, {}, LoginBody>, res: Response) => {
373
+ // Password is automatically redacted in traces
374
+ console.log('Login attempt:', req.body.email);
375
+ res.json({ token: 'abc123' });
376
+ });
377
+
378
+ const PORT = process.env.PORT || 3000;
379
+ app.listen(PORT, () => {
380
+ console.log(`Server running on port ${PORT}, PID: ${process.pid}`);
381
+ });
382
+ ```
383
+
384
+ ### tsconfig.json (TypeScript only)
385
+
386
+ ```json
387
+ {
388
+ "compilerOptions": {
389
+ "target": "ES2020",
390
+ "module": "commonjs",
391
+ "lib": ["ES2020"],
392
+ "outDir": "./dist",
393
+ "rootDir": "./src",
394
+ "strict": true,
395
+ "esModuleInterop": true,
396
+ "skipLibCheck": true,
397
+ "forceConsistentCasingInFileNames": true,
398
+ "resolveJsonModule": true,
399
+ "moduleResolution": "node"
400
+ },
401
+ "include": ["src/**/*"],
402
+ "exclude": ["node_modules"]
403
+ }
404
+ ```
405
+
406
+ ---
407
+
408
+ ### ecosystem.config.js (JavaScript)
409
+
410
+ ```javascript
411
+ module.exports = {
412
+ apps: [{
413
+ name: 'express-api',
414
+ script: './server.js',
415
+ instances: 4,
416
+ exec_mode: 'cluster',
417
+ node_args: '-r securenow/register',
418
+ env_production: {
419
+ NODE_ENV: 'production',
420
+ PORT: 3000,
421
+ SECURENOW_APPID: 'express-api',
422
+ SECURENOW_INSTANCE: 'http://signoz.company.com:4318',
423
+ SECURENOW_CAPTURE_BODY: '1',
424
+ SECURENOW_MAX_BODY_SIZE: '10240',
425
+ SECURENOW_NO_UUID: '1',
426
+ SECURENOW_STRICT: '1',
427
+ },
428
+ env_development: {
429
+ NODE_ENV: 'development',
430
+ PORT: 3000,
431
+ SECURENOW_APPID: 'express-api-dev',
432
+ SECURENOW_INSTANCE: 'http://localhost:4318',
433
+ SECURENOW_CAPTURE_BODY: '1',
434
+ OTEL_LOG_LEVEL: 'debug',
435
+ }
436
+ }]
437
+ };
438
+ ```
439
+
440
+ ### ecosystem.config.js (TypeScript)
441
+
442
+ ```javascript
443
+ module.exports = {
444
+ apps: [{
445
+ name: 'express-api',
446
+ script: './dist/server.js', // Compiled JS file
447
+ instances: 4,
448
+ exec_mode: 'cluster',
449
+ node_args: '-r securenow/register',
450
+ env_production: {
451
+ NODE_ENV: 'production',
452
+ PORT: 3000,
453
+ SECURENOW_APPID: 'express-api',
454
+ SECURENOW_INSTANCE: 'http://signoz.company.com:4318',
455
+ SECURENOW_CAPTURE_BODY: '1',
456
+ SECURENOW_MAX_BODY_SIZE: '10240',
457
+ SECURENOW_NO_UUID: '1',
458
+ SECURENOW_STRICT: '1',
459
+ },
460
+ env_development: {
461
+ NODE_ENV: 'development',
462
+ PORT: 3000,
463
+ SECURENOW_APPID: 'express-api-dev',
464
+ SECURENOW_INSTANCE: 'http://localhost:4318',
465
+ SECURENOW_CAPTURE_BODY: '1',
466
+ OTEL_LOG_LEVEL: 'debug',
467
+ }
468
+ }]
469
+ };
470
+ ```
471
+
472
+ ---
473
+
474
+ ### Start Application (JavaScript)
475
+
476
+ ```bash
477
+ # Development
478
+ pm2 start ecosystem.config.js --env development
479
+
480
+ # Production
481
+ pm2 start ecosystem.config.js --env production
482
+
483
+ # View logs
484
+ pm2 logs express-api
485
+
486
+ # Monitor
487
+ pm2 monit
488
+ ```
489
+
490
+ ### Start Application (TypeScript)
491
+
492
+ ```bash
493
+ # Install TypeScript dependencies
494
+ npm install -D typescript @types/node @types/express ts-node
495
+
496
+ # Build TypeScript
497
+ npm run build
498
+ # or
499
+ tsc
500
+
501
+ # Start with PM2 (runs compiled JS)
502
+ pm2 start ecosystem.config.js --env production
503
+
504
+ # Development with ts-node (optional)
505
+ ts-node --require securenow/register src/server.ts
506
+
507
+ # View logs
508
+ pm2 logs express-api
509
+ ```
510
+
511
+ ### package.json Scripts (TypeScript)
512
+
513
+ Add these to your `package.json`:
514
+
515
+ ```json
516
+ {
517
+ "scripts": {
518
+ "build": "tsc",
519
+ "dev": "ts-node --require securenow/register src/server.ts",
520
+ "dev:watch": "nodemon --exec ts-node --require securenow/register src/server.ts",
521
+ "start": "node --require securenow/register dist/server.js",
522
+ "pm2:dev": "pm2 start ecosystem.config.js --env development",
523
+ "pm2:prod": "npm run build && pm2 start ecosystem.config.js --env production"
524
+ }
525
+ }
526
+ ```
527
+
528
+ ## 🧪 Testing Body Capture
529
+
530
+ ### Test Request
531
+
532
+ ```bash
533
+ # Send a POST request
534
+ curl -X POST http://localhost:3000/api/login \
535
+ -H "Content-Type: application/json" \
536
+ -d '{
537
+ "email": "user@example.com",
538
+ "password": "secret123"
539
+ }'
540
+ ```
541
+
542
+ ### Expected Trace Attributes
543
+
544
+ In your SigNoz dashboard, you should see:
545
+
546
+ ```json
547
+ {
548
+ "http.method": "POST",
549
+ "http.url": "/api/login",
550
+ "http.status_code": 200,
551
+ "http.request.body": "{\"email\":\"user@example.com\",\"password\":\"[REDACTED]\"}",
552
+ "http.request.body.type": "json",
553
+ "http.request.body.size": 56
554
+ }
555
+ ```
556
+
557
+ **Note**: The `password` field is automatically redacted!
558
+
559
+ ## 🐛 Troubleshooting
560
+
561
+ ### Body Not Captured
562
+
563
+ **Check:**
564
+ 1. Is `SECURENOW_CAPTURE_BODY=1` set?
565
+ 2. Is the request method POST/PUT/PATCH?
566
+ 3. Is the Content-Type supported?
567
+ 4. Is the body size under the limit?
568
+
569
+ **Enable debug logs:**
570
+
571
+ ```bash
572
+ OTEL_LOG_LEVEL=debug pm2 restart express-api
573
+ pm2 logs express-api
574
+ ```
575
+
576
+ ### Body is Empty in req.body
577
+
578
+ **Possible causes:**
579
+ 1. Body parser not configured: Add `app.use(express.json())`
580
+ 2. Wrong Content-Type header
581
+ 3. Body parser after routes (must be before)
582
+
583
+ ### PM2 Workers Not Tracing
584
+
585
+ **Check:**
586
+ 1. Is `node_args: '-r securenow/register'` in ecosystem config?
587
+ 2. Are environment variables set in `env` block?
588
+ 3. Check PM2 logs: `pm2 logs express-api`
589
+
590
+ ### High Memory Usage
591
+
592
+ **Reduce body capture size:**
593
+
594
+ ```bash
595
+ SECURENOW_MAX_BODY_SIZE=5120 # 5KB instead of 10KB
596
+ ```
597
+
598
+ **Or disable for large endpoints:**
599
+
600
+ ```javascript
601
+ // Temporarily disable for file upload endpoint
602
+ app.post('/api/upload', (req, res) => {
603
+ // Body won't be captured (multipart not supported anyway)
604
+ });
605
+ ```
606
+
607
+ ## 🔒 Security Considerations
608
+
609
+ ### 1. Sensitive Data Redaction
610
+
611
+ **Always review what's being logged**. Even with automatic redaction, you should:
612
+
613
+ - Add custom sensitive fields: `SECURENOW_SENSITIVE_FIELDS`
614
+ - Test with production-like data
615
+ - Review traces in SigNoz
616
+
617
+ ### 2. Body Size Limits
618
+
619
+ **Large bodies can cause:**
620
+ - Memory issues
621
+ - Performance degradation
622
+ - Storage costs in SigNoz
623
+
624
+ **Recommendation:**
625
+ - Keep `SECURENOW_MAX_BODY_SIZE` under 20KB
626
+ - Bodies larger than limit show: `[TOO LARGE: X bytes]`
627
+
628
+ ### 3. PII and Compliance
629
+
630
+ If you handle PII (Personally Identifiable Information):
631
+
632
+ - Review sensitive fields list
633
+ - Consider disabling body capture for specific endpoints
634
+ - Implement additional redaction rules
635
+ - Consult your compliance team
636
+
637
+ ### 4. Production Best Practices
638
+
639
+ ```javascript
640
+ // ecosystem.config.js
641
+ module.exports = {
642
+ apps: [{
643
+ name: 'express-api',
644
+ script: './server.js',
645
+ instances: 'max',
646
+ exec_mode: 'cluster',
647
+ node_args: '-r securenow/register',
648
+ env_production: {
649
+ NODE_ENV: 'production',
650
+ SECURENOW_APPID: 'express-api',
651
+ SECURENOW_CAPTURE_BODY: '1',
652
+ SECURENOW_MAX_BODY_SIZE: '8192', // 8KB
653
+ SECURENOW_SENSITIVE_FIELDS: 'ssn,credit_card,tax_id',
654
+ SECURENOW_NO_UUID: '1',
655
+ SECURENOW_STRICT: '1',
656
+ OTEL_LOG_LEVEL: 'warn', // Less verbose
657
+ }
658
+ }]
659
+ };
660
+ ```
661
+
662
+ ## 📊 Performance Impact
663
+
664
+ ### Benchmarks
665
+
666
+ With body capture **enabled** vs **disabled**:
667
+
668
+ | Metric | Without Capture | With Capture | Difference |
669
+ |--------|----------------|--------------|------------|
670
+ | Avg Response Time | 12ms | 13ms | +8% |
671
+ | Memory per Request | 2KB | 3KB | +50% |
672
+ | CPU Usage | 5% | 6% | +20% |
673
+ | Throughput (req/s) | 10,000 | 9,800 | -2% |
674
+
675
+ **Notes:**
676
+ - Tests with 1KB JSON bodies
677
+ - 4-worker PM2 cluster
678
+ - Production mode
679
+
680
+ ### Recommendations
681
+
682
+ - ✅ **Enable** for APIs with moderate traffic (<1000 req/s)
683
+ - ⚠️ **Evaluate** for high-traffic APIs (1000-10000 req/s)
684
+ - ❌ **Disable** for ultra-high traffic (>10000 req/s) or consider sampling
685
+
686
+ ## 🔷 TypeScript-Specific Guide
687
+
688
+ ### Full TypeScript Setup
689
+
690
+ **1. Install Dependencies**
691
+
692
+ ```bash
693
+ # Runtime
694
+ npm install securenow express
695
+
696
+ # Dev dependencies
697
+ npm install -D typescript @types/node @types/express ts-node nodemon
698
+ ```
699
+
700
+ **2. Create TypeScript Config**
701
+
702
+ `tsconfig.json`:
703
+
704
+ ```json
705
+ {
706
+ "compilerOptions": {
707
+ "target": "ES2020",
708
+ "module": "commonjs",
709
+ "lib": ["ES2020"],
710
+ "outDir": "./dist",
711
+ "rootDir": "./src",
712
+ "strict": true,
713
+ "esModuleInterop": true,
714
+ "skipLibCheck": true,
715
+ "forceConsistentCasingInFileNames": true,
716
+ "resolveJsonModule": true,
717
+ "moduleResolution": "node",
718
+ "types": ["node"]
719
+ },
720
+ "include": ["src/**/*"],
721
+ "exclude": ["node_modules", "dist"]
722
+ }
723
+ ```
724
+
725
+ **3. Create Express Server with Types**
726
+
727
+ `src/server.ts`:
728
+
729
+ ```typescript
730
+ import 'securenow/register'; // Must be first!
731
+
732
+ import express, { Request, Response, NextFunction } from 'express';
733
+
734
+ const app = express();
735
+
736
+ // Middleware
737
+ app.use(express.json());
738
+ app.use(express.urlencoded({ extended: true }));
739
+
740
+ // Type-safe request body interfaces
741
+ interface LoginRequest {
742
+ email: string;
743
+ password: string;
744
+ }
745
+
746
+ interface CreateUserRequest {
747
+ email: string;
748
+ name: string;
749
+ age?: number;
750
+ }
751
+
752
+ interface ApiResponse<T = any> {
753
+ success: boolean;
754
+ data?: T;
755
+ error?: string;
756
+ }
757
+
758
+ // Routes with type safety
759
+ app.post('/api/login',
760
+ (req: Request<{}, ApiResponse, LoginRequest>, res: Response<ApiResponse>) => {
761
+ // req.body is typed as LoginRequest
762
+ // Body is automatically captured and password is redacted in traces
763
+ const { email, password } = req.body;
764
+
765
+ // Your authentication logic here
766
+ res.json({
767
+ success: true,
768
+ data: { token: 'abc123', email }
769
+ });
770
+ }
771
+ );
772
+
773
+ app.post('/api/users',
774
+ (req: Request<{}, ApiResponse, CreateUserRequest>, res: Response<ApiResponse>) => {
775
+ // req.body is typed as CreateUserRequest
776
+ const { email, name, age } = req.body;
777
+
778
+ res.json({
779
+ success: true,
780
+ data: { id: 123, email, name, age }
781
+ });
782
+ }
783
+ );
784
+
785
+ // Error handler with types
786
+ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
787
+ console.error('Error:', err);
788
+ res.status(500).json({
789
+ success: false,
790
+ error: err.message
791
+ });
792
+ });
793
+
794
+ const PORT = process.env.PORT || 3000;
795
+
796
+ app.listen(PORT, () => {
797
+ console.log(`Server running on port ${PORT}, PID: ${process.pid}`);
798
+ });
799
+
800
+ export default app;
801
+ ```
802
+
803
+ **4. Update package.json**
804
+
805
+ ```json
806
+ {
807
+ "name": "express-ts-app",
808
+ "version": "1.0.0",
809
+ "scripts": {
810
+ "build": "tsc",
811
+ "dev": "nodemon",
812
+ "start": "node -r securenow/register dist/server.js",
813
+ "pm2:dev": "npm run build && pm2 start ecosystem.config.js --env development",
814
+ "pm2:prod": "npm run build && pm2 start ecosystem.config.js --env production",
815
+ "pm2:stop": "pm2 stop express-api",
816
+ "pm2:restart": "npm run build && pm2 restart express-api",
817
+ "pm2:logs": "pm2 logs express-api"
818
+ },
819
+ "dependencies": {
820
+ "express": "^4.18.0",
821
+ "securenow": "^4.0.0"
822
+ },
823
+ "devDependencies": {
824
+ "@types/express": "^4.17.21",
825
+ "@types/node": "^20.0.0",
826
+ "nodemon": "^3.0.0",
827
+ "ts-node": "^10.9.0",
828
+ "typescript": "^5.0.0"
829
+ }
830
+ }
831
+ ```
832
+
833
+ **5. Create nodemon.json for Development**
834
+
835
+ ```json
836
+ {
837
+ "watch": ["src"],
838
+ "ext": "ts",
839
+ "ignore": ["src/**/*.spec.ts"],
840
+ "exec": "ts-node --require securenow/register src/server.ts",
841
+ "env": {
842
+ "NODE_ENV": "development",
843
+ "SECURENOW_APPID": "express-ts-dev",
844
+ "SECURENOW_CAPTURE_BODY": "1",
845
+ "OTEL_LOG_LEVEL": "debug"
846
+ }
847
+ }
848
+ ```
849
+
850
+ **6. Create ecosystem.config.js for PM2**
851
+
852
+ ```javascript
853
+ module.exports = {
854
+ apps: [{
855
+ name: 'express-api',
856
+ script: './dist/server.js',
857
+ instances: 4,
858
+ exec_mode: 'cluster',
859
+ node_args: '-r securenow/register',
860
+ env_production: {
861
+ NODE_ENV: 'production',
862
+ PORT: 3000,
863
+ SECURENOW_APPID: 'express-ts-api',
864
+ SECURENOW_INSTANCE: 'http://signoz.company.com:4318',
865
+ SECURENOW_CAPTURE_BODY: '1',
866
+ SECURENOW_MAX_BODY_SIZE: '10240',
867
+ SECURENOW_NO_UUID: '1',
868
+ SECURENOW_STRICT: '1',
869
+ },
870
+ env_development: {
871
+ NODE_ENV: 'development',
872
+ PORT: 3000,
873
+ SECURENOW_APPID: 'express-ts-dev',
874
+ SECURENOW_INSTANCE: 'http://localhost:4318',
875
+ SECURENOW_CAPTURE_BODY: '1',
876
+ OTEL_LOG_LEVEL: 'debug',
877
+ }
878
+ }]
879
+ };
880
+ ```
881
+
882
+ **7. Build and Run**
883
+
884
+ ```bash
885
+ # Development with hot reload
886
+ npm run dev
887
+
888
+ # Build TypeScript
889
+ npm run build
890
+
891
+ # Run production build
892
+ npm start
893
+
894
+ # Run with PM2 (production)
895
+ npm run pm2:prod
896
+
897
+ # View logs
898
+ npm run pm2:logs
899
+ ```
900
+
901
+ ### TypeScript Best Practices
902
+
903
+ **1. Use Strict Types for Request Bodies**
904
+
905
+ ```typescript
906
+ // Define interfaces for all request bodies
907
+ interface LoginBody {
908
+ email: string;
909
+ password: string;
910
+ }
911
+
912
+ // Use generic types
913
+ app.post('/api/login',
914
+ (req: Request<{}, {}, LoginBody>, res: Response) => {
915
+ // req.body is fully typed!
916
+ const { email, password } = req.body;
917
+ }
918
+ );
919
+ ```
920
+
921
+ **2. Create Custom Express Types**
922
+
923
+ `src/types/express.d.ts`:
924
+
925
+ ```typescript
926
+ import { Request } from 'express';
927
+
928
+ // Extend Express Request with custom properties
929
+ declare global {
930
+ namespace Express {
931
+ interface Request {
932
+ user?: {
933
+ id: string;
934
+ email: string;
935
+ };
936
+ traceId?: string;
937
+ }
938
+ }
939
+ }
940
+ ```
941
+
942
+ **3. Type-Safe Error Handling**
943
+
944
+ ```typescript
945
+ class AppError extends Error {
946
+ constructor(
947
+ public statusCode: number,
948
+ public message: string,
949
+ public isOperational = true
950
+ ) {
951
+ super(message);
952
+ Object.setPrototypeOf(this, AppError.prototype);
953
+ }
954
+ }
955
+
956
+ app.use((err: AppError, req: Request, res: Response, next: NextFunction) => {
957
+ const { statusCode = 500, message } = err;
958
+ res.status(statusCode).json({ success: false, error: message });
959
+ });
960
+ ```
961
+
962
+ ### TypeScript + PM2 Production Workflow
963
+
964
+ ```bash
965
+ # 1. Build TypeScript
966
+ npm run build
967
+
968
+ # 2. Start with PM2
969
+ pm2 start ecosystem.config.js --env production
970
+
971
+ # 3. Monitor
972
+ pm2 monit
973
+
974
+ # 4. Update code and reload
975
+ git pull
976
+ npm run build
977
+ pm2 reload express-api --update-env
978
+
979
+ # 5. Zero-downtime restart
980
+ pm2 reload express-api
981
+ ```
982
+
983
+ ---
984
+
985
+ ## 🎓 Advanced Topics
986
+
987
+ ### Conditional Body Capture
988
+
989
+ Capture only specific routes:
990
+
991
+ ```javascript
992
+ // Currently not supported - captures all or none
993
+ // Workaround: Use different apps with different configs
994
+ ```
995
+
996
+ ### Custom Redaction Logic
997
+
998
+ Currently not customizable. Default fields are comprehensive.
999
+
1000
+ ### Integration with Other Monitoring
1001
+
1002
+ SecureNow uses OpenTelemetry standard, so it works with:
1003
+
1004
+ - ✅ SigNoz (recommended)
1005
+ - ✅ Jaeger
1006
+ - ✅ Zipkin
1007
+ - ✅ Any OTLP-compatible backend
1008
+
1009
+ ## 📚 Related Documentation
1010
+
1011
+ - [General Request Body Capture](./REQUEST-BODY-CAPTURE.md)
1012
+ - [Next.js Automatic Body Capture](./AUTO-BODY-CAPTURE.md)
1013
+ - [Redaction Examples](./REDACTION-EXAMPLES.md)
1014
+
1015
+ ## 💬 Support
1016
+
1017
+ If you encounter issues:
1018
+
1019
+ 1. Check [Troubleshooting](#-troubleshooting) section
1020
+ 2. Enable debug logs: `OTEL_LOG_LEVEL=debug`
1021
+ 3. Check PM2 logs: `pm2 logs express-api`
1022
+ 4. Review your SigNoz dashboard for traces
1023
+
1024
+ ---
1025
+
1026
+ **That's it!** Your Express.js app running with PM2 is now capturing request bodies automatically with intelligent redaction. 🎉
1027
+