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,720 @@
|
|
|
1
|
+
# Express.js Setup Guide - SecureNow Observability
|
|
2
|
+
|
|
3
|
+
Complete guide to add distributed tracing and logging to your Express.js application using SecureNow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 18 or higher
|
|
10
|
+
- An existing Express.js application
|
|
11
|
+
- An OTLP-compatible observability backend
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install securenow express
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Start (5 Minutes)
|
|
24
|
+
|
|
25
|
+
### Step 1: Install Package
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install securenow
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2: Create Environment Variables
|
|
32
|
+
|
|
33
|
+
Create a `.env` file in your project root:
|
|
34
|
+
|
|
35
|
+
```env
|
|
36
|
+
SECURENOW_APPID=my-express-app
|
|
37
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
38
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
39
|
+
SECURENOW_CAPTURE_BODY=1
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 3: Initialize SecureNow
|
|
43
|
+
|
|
44
|
+
Add these lines at the **very top** of your main file (before any other requires):
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
// app.js or server.js
|
|
48
|
+
require('securenow/register');
|
|
49
|
+
require('securenow/console-instrumentation');
|
|
50
|
+
|
|
51
|
+
// Now your Express app
|
|
52
|
+
const express = require('express');
|
|
53
|
+
const app = express();
|
|
54
|
+
|
|
55
|
+
app.use(express.json());
|
|
56
|
+
|
|
57
|
+
app.get('/', (req, res) => {
|
|
58
|
+
console.log('Home page accessed');
|
|
59
|
+
res.send('Hello World');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const PORT = process.env.PORT || 3000;
|
|
63
|
+
app.listen(PORT, () => {
|
|
64
|
+
console.log(`Server running on port ${PORT}`);
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Step 4: Run Your Application
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node app.js
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
You should see:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
[securenow] OTel SDK started → http://localhost:4318/v1/traces
|
|
78
|
+
[securenow] 📋 Logging: ENABLED → http://localhost:4318/v1/logs
|
|
79
|
+
[securenow] Console instrumentation installed
|
|
80
|
+
Server running on port 3000
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Done!** Your Express app is now sending traces and logs.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Complete Example
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
// app.js
|
|
91
|
+
require('securenow/register');
|
|
92
|
+
require('securenow/console-instrumentation');
|
|
93
|
+
|
|
94
|
+
const express = require('express');
|
|
95
|
+
const app = express();
|
|
96
|
+
|
|
97
|
+
// Middleware
|
|
98
|
+
app.use(express.json());
|
|
99
|
+
app.use(express.urlencoded({ extended: true }));
|
|
100
|
+
|
|
101
|
+
// Logging middleware
|
|
102
|
+
app.use((req, res, next) => {
|
|
103
|
+
console.info('Incoming request', {
|
|
104
|
+
method: req.method,
|
|
105
|
+
path: req.path,
|
|
106
|
+
query: req.query,
|
|
107
|
+
ip: req.ip,
|
|
108
|
+
userAgent: req.get('user-agent'),
|
|
109
|
+
});
|
|
110
|
+
next();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Routes
|
|
114
|
+
app.get('/', (req, res) => {
|
|
115
|
+
console.log('Home page accessed');
|
|
116
|
+
res.json({
|
|
117
|
+
message: 'Express with SecureNow',
|
|
118
|
+
timestamp: new Date().toISOString(),
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
app.get('/api/users', async (req, res) => {
|
|
123
|
+
console.log('Fetching users');
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Your database logic
|
|
127
|
+
const users = await getUsersFromDatabase();
|
|
128
|
+
|
|
129
|
+
console.info('Users fetched successfully', {
|
|
130
|
+
count: users.length,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
res.json(users);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error('Failed to fetch users', {
|
|
136
|
+
error: error.message,
|
|
137
|
+
stack: error.stack,
|
|
138
|
+
});
|
|
139
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
app.post('/api/users', async (req, res) => {
|
|
144
|
+
console.info('Creating new user', {
|
|
145
|
+
email: req.body.email,
|
|
146
|
+
name: req.body.name,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
// Validation
|
|
151
|
+
if (!req.body.email || !req.body.name) {
|
|
152
|
+
console.warn('Validation failed', {
|
|
153
|
+
body: req.body,
|
|
154
|
+
});
|
|
155
|
+
return res.status(400).json({ error: 'Email and name required' });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Your database logic
|
|
159
|
+
const user = await createUserInDatabase(req.body);
|
|
160
|
+
|
|
161
|
+
console.log('User created successfully', {
|
|
162
|
+
userId: user.id,
|
|
163
|
+
email: user.email,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
res.status(201).json(user);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error('Failed to create user', {
|
|
169
|
+
error: error.message,
|
|
170
|
+
stack: error.stack,
|
|
171
|
+
body: req.body,
|
|
172
|
+
});
|
|
173
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Error handling middleware
|
|
178
|
+
app.use((err, req, res, next) => {
|
|
179
|
+
console.error('Express error handler', {
|
|
180
|
+
error: err.message,
|
|
181
|
+
stack: err.stack,
|
|
182
|
+
path: req.path,
|
|
183
|
+
method: req.method,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
res.status(500).json({
|
|
187
|
+
error: 'Internal server error',
|
|
188
|
+
message: err.message,
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Start server
|
|
193
|
+
const PORT = process.env.PORT || 3000;
|
|
194
|
+
app.listen(PORT, () => {
|
|
195
|
+
console.log('Express server started', {
|
|
196
|
+
port: PORT,
|
|
197
|
+
nodeVersion: process.version,
|
|
198
|
+
env: process.env.NODE_ENV || 'development',
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Using NODE_OPTIONS (No Code Changes)
|
|
206
|
+
|
|
207
|
+
If you don't want to modify your code, use `NODE_OPTIONS`:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
NODE_OPTIONS="-r securenow/register -r securenow/console-instrumentation" \
|
|
211
|
+
SECURENOW_APPID=my-express-app \
|
|
212
|
+
SECURENOW_INSTANCE=http://localhost:4318 \
|
|
213
|
+
SECURENOW_LOGGING_ENABLED=1 \
|
|
214
|
+
node app.js
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
This works with npm scripts too:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"scripts": {
|
|
222
|
+
"start": "node app.js",
|
|
223
|
+
"start:instrumented": "NODE_OPTIONS='-r securenow/register -r securenow/console-instrumentation' node app.js"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Then run:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm run start:instrumented
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Environment Variables
|
|
237
|
+
|
|
238
|
+
### Required
|
|
239
|
+
|
|
240
|
+
```env
|
|
241
|
+
# Your application identifier
|
|
242
|
+
SECURENOW_APPID=my-express-app
|
|
243
|
+
|
|
244
|
+
# Your OTLP collector endpoint
|
|
245
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Recommended
|
|
249
|
+
|
|
250
|
+
```env
|
|
251
|
+
# Enable logging
|
|
252
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
253
|
+
|
|
254
|
+
# Enable request body capture (for debugging)
|
|
255
|
+
SECURENOW_CAPTURE_BODY=1
|
|
256
|
+
|
|
257
|
+
# Max body size (default: 10KB)
|
|
258
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
259
|
+
|
|
260
|
+
# Environment name
|
|
261
|
+
NODE_ENV=production
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Optional
|
|
265
|
+
|
|
266
|
+
```env
|
|
267
|
+
# Authentication headers for your observability backend
|
|
268
|
+
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-key
|
|
269
|
+
|
|
270
|
+
# Disable UUID suffix on service name
|
|
271
|
+
SECURENOW_NO_UUID=1
|
|
272
|
+
|
|
273
|
+
# Enable debug logging
|
|
274
|
+
OTEL_LOG_LEVEL=debug
|
|
275
|
+
|
|
276
|
+
# Additional sensitive fields to redact
|
|
277
|
+
SECURENOW_SENSITIVE_FIELDS=internal_token,session_key
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## PM2 Setup
|
|
283
|
+
|
|
284
|
+
### Basic PM2 Configuration
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
// ecosystem.config.js
|
|
288
|
+
module.exports = {
|
|
289
|
+
apps: [{
|
|
290
|
+
name: 'my-express-app',
|
|
291
|
+
script: './app.js',
|
|
292
|
+
instances: 4,
|
|
293
|
+
exec_mode: 'cluster',
|
|
294
|
+
node_args: '-r securenow/register -r securenow/console-instrumentation',
|
|
295
|
+
env: {
|
|
296
|
+
SECURENOW_APPID: 'my-express-app',
|
|
297
|
+
SECURENOW_INSTANCE: 'http://localhost:4318',
|
|
298
|
+
SECURENOW_LOGGING_ENABLED: '1',
|
|
299
|
+
SECURENOW_NO_UUID: '1', // Same service name for all instances
|
|
300
|
+
SECURENOW_CAPTURE_BODY: '1',
|
|
301
|
+
NODE_ENV: 'production',
|
|
302
|
+
}
|
|
303
|
+
}]
|
|
304
|
+
};
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Start with PM2:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
pm2 start ecosystem.config.js
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### PM2 with Environment-Specific Config
|
|
314
|
+
|
|
315
|
+
```javascript
|
|
316
|
+
// ecosystem.config.js
|
|
317
|
+
module.exports = {
|
|
318
|
+
apps: [{
|
|
319
|
+
name: 'my-app',
|
|
320
|
+
script: './app.js',
|
|
321
|
+
instances: 4,
|
|
322
|
+
exec_mode: 'cluster',
|
|
323
|
+
node_args: '-r securenow/register -r securenow/console-instrumentation',
|
|
324
|
+
env_development: {
|
|
325
|
+
SECURENOW_APPID: 'my-app-dev',
|
|
326
|
+
SECURENOW_INSTANCE: 'http://localhost:4318',
|
|
327
|
+
SECURENOW_LOGGING_ENABLED: '1',
|
|
328
|
+
SECURENOW_CAPTURE_BODY: '1',
|
|
329
|
+
OTEL_LOG_LEVEL: 'debug',
|
|
330
|
+
NODE_ENV: 'development',
|
|
331
|
+
},
|
|
332
|
+
env_production: {
|
|
333
|
+
SECURENOW_APPID: 'my-app-prod',
|
|
334
|
+
SECURENOW_INSTANCE: 'http://collector.prod:4318',
|
|
335
|
+
SECURENOW_LOGGING_ENABLED: '1',
|
|
336
|
+
SECURENOW_CAPTURE_BODY: '0', // Disable in production
|
|
337
|
+
SECURENOW_NO_UUID: '1',
|
|
338
|
+
NODE_ENV: 'production',
|
|
339
|
+
}
|
|
340
|
+
}]
|
|
341
|
+
};
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Run with specific environment:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Development
|
|
348
|
+
pm2 start ecosystem.config.js
|
|
349
|
+
|
|
350
|
+
# Production
|
|
351
|
+
pm2 start ecosystem.config.js --env production
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## TypeScript Setup
|
|
357
|
+
|
|
358
|
+
### Step 1: Install
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
npm install securenow typescript @types/node @types/express ts-node
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Step 2: Initialize SecureNow
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// app.ts
|
|
368
|
+
require('securenow/register');
|
|
369
|
+
require('securenow/console-instrumentation');
|
|
370
|
+
|
|
371
|
+
import express, { Request, Response, NextFunction } from 'express';
|
|
372
|
+
|
|
373
|
+
const app = express();
|
|
374
|
+
|
|
375
|
+
app.use(express.json());
|
|
376
|
+
|
|
377
|
+
app.get('/', (req: Request, res: Response) => {
|
|
378
|
+
console.log('Home page accessed');
|
|
379
|
+
res.json({ message: 'Hello World' });
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
app.post('/api/users', async (req: Request, res: Response) => {
|
|
383
|
+
console.info('Creating user', { body: req.body });
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
// Your logic
|
|
387
|
+
const user = await createUser(req.body);
|
|
388
|
+
console.log('User created', { userId: user.id });
|
|
389
|
+
res.status(201).json(user);
|
|
390
|
+
} catch (error) {
|
|
391
|
+
console.error('Failed to create user', { error });
|
|
392
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Error handler
|
|
397
|
+
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
398
|
+
console.error('Express error', {
|
|
399
|
+
error: err.message,
|
|
400
|
+
stack: err.stack,
|
|
401
|
+
path: req.path,
|
|
402
|
+
});
|
|
403
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
const PORT = process.env.PORT || 3000;
|
|
407
|
+
app.listen(PORT, () => {
|
|
408
|
+
console.log(`Server running on port ${PORT}`);
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Step 3: Run with ts-node
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
npx ts-node app.ts
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Or compile and run:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
npx tsc
|
|
422
|
+
node dist/app.js
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Advanced Features
|
|
428
|
+
|
|
429
|
+
### Request Body Capture
|
|
430
|
+
|
|
431
|
+
Enable to see request bodies in your traces:
|
|
432
|
+
|
|
433
|
+
```env
|
|
434
|
+
SECURENOW_CAPTURE_BODY=1
|
|
435
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Automatically redacted fields:** passwords, tokens, api_keys, card numbers, etc.
|
|
439
|
+
|
|
440
|
+
**Add custom redaction:**
|
|
441
|
+
|
|
442
|
+
```env
|
|
443
|
+
SECURENOW_SENSITIVE_FIELDS=internal_token,session_key
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Custom Logger
|
|
447
|
+
|
|
448
|
+
For more control, use the direct logger API:
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
const { getLogger } = require('securenow/tracing');
|
|
452
|
+
|
|
453
|
+
const logger = getLogger('express-app', '1.0.0');
|
|
454
|
+
|
|
455
|
+
app.post('/api/users', async (req, res) => {
|
|
456
|
+
logger.emit({
|
|
457
|
+
severityNumber: 9,
|
|
458
|
+
severityText: 'INFO',
|
|
459
|
+
body: 'User creation started',
|
|
460
|
+
attributes: {
|
|
461
|
+
email: req.body.email,
|
|
462
|
+
ip: req.ip,
|
|
463
|
+
timestamp: Date.now(),
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Your logic...
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Disable Specific Instrumentations
|
|
472
|
+
|
|
473
|
+
If you don't need certain instrumentations:
|
|
474
|
+
|
|
475
|
+
```env
|
|
476
|
+
SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns,net
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Docker Setup
|
|
482
|
+
|
|
483
|
+
### Dockerfile
|
|
484
|
+
|
|
485
|
+
```dockerfile
|
|
486
|
+
FROM node:20-alpine
|
|
487
|
+
|
|
488
|
+
WORKDIR /app
|
|
489
|
+
|
|
490
|
+
# Copy package files
|
|
491
|
+
COPY package*.json ./
|
|
492
|
+
|
|
493
|
+
# Install dependencies
|
|
494
|
+
RUN npm install
|
|
495
|
+
|
|
496
|
+
# Copy application code
|
|
497
|
+
COPY . .
|
|
498
|
+
|
|
499
|
+
# Set environment variables
|
|
500
|
+
ENV SECURENOW_APPID=my-express-app
|
|
501
|
+
ENV SECURENOW_INSTANCE=http://collector:4318
|
|
502
|
+
ENV SECURENOW_LOGGING_ENABLED=1
|
|
503
|
+
ENV NODE_ENV=production
|
|
504
|
+
|
|
505
|
+
# Expose port
|
|
506
|
+
EXPOSE 3000
|
|
507
|
+
|
|
508
|
+
# Start application
|
|
509
|
+
CMD ["node", "app.js"]
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### docker-compose.yml
|
|
513
|
+
|
|
514
|
+
```yaml
|
|
515
|
+
version: '3.8'
|
|
516
|
+
|
|
517
|
+
services:
|
|
518
|
+
app:
|
|
519
|
+
build: .
|
|
520
|
+
ports:
|
|
521
|
+
- "3000:3000"
|
|
522
|
+
environment:
|
|
523
|
+
- SECURENOW_APPID=my-express-app
|
|
524
|
+
- SECURENOW_INSTANCE=http://collector:4318
|
|
525
|
+
- SECURENOW_LOGGING_ENABLED=1
|
|
526
|
+
- SECURENOW_CAPTURE_BODY=1
|
|
527
|
+
- NODE_ENV=production
|
|
528
|
+
depends_on:
|
|
529
|
+
- collector
|
|
530
|
+
|
|
531
|
+
collector:
|
|
532
|
+
image: otel/opentelemetry-collector:latest
|
|
533
|
+
ports:
|
|
534
|
+
- "4318:4318"
|
|
535
|
+
volumes:
|
|
536
|
+
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
|
537
|
+
command: ["--config=/etc/otel-collector-config.yaml"]
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
Run:
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
docker-compose up
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Troubleshooting
|
|
549
|
+
|
|
550
|
+
### Traces Not Appearing
|
|
551
|
+
|
|
552
|
+
**Check initialization order:**
|
|
553
|
+
|
|
554
|
+
```javascript
|
|
555
|
+
// ✅ Correct
|
|
556
|
+
require('securenow/register');
|
|
557
|
+
require('securenow/console-instrumentation');
|
|
558
|
+
const express = require('express');
|
|
559
|
+
|
|
560
|
+
// ❌ Wrong
|
|
561
|
+
const express = require('express');
|
|
562
|
+
require('securenow/register');
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Enable debug logging:**
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
export OTEL_LOG_LEVEL=debug
|
|
569
|
+
node app.js
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Verify collector is running:**
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
curl http://localhost:4318/v1/traces
|
|
576
|
+
# Should return 200 or 405
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Logs Not Appearing
|
|
580
|
+
|
|
581
|
+
**Check logging is enabled:**
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
echo $SECURENOW_LOGGING_ENABLED
|
|
585
|
+
# Should output: 1
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Verify console instrumentation:**
|
|
589
|
+
|
|
590
|
+
Look for this in the output:
|
|
591
|
+
```
|
|
592
|
+
[securenow] Console instrumentation installed
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### PM2 Issues
|
|
596
|
+
|
|
597
|
+
**Different service names for each worker:**
|
|
598
|
+
|
|
599
|
+
```env
|
|
600
|
+
# Add this to use same service name
|
|
601
|
+
SECURENOW_NO_UUID=1
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Workers not instrumented:**
|
|
605
|
+
|
|
606
|
+
Use `node_args` in PM2 config:
|
|
607
|
+
|
|
608
|
+
```javascript
|
|
609
|
+
{
|
|
610
|
+
node_args: '-r securenow/register -r securenow/console-instrumentation'
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## Best Practices
|
|
617
|
+
|
|
618
|
+
### 1. Use Structured Logging
|
|
619
|
+
|
|
620
|
+
```javascript
|
|
621
|
+
// ❌ Bad
|
|
622
|
+
console.log('User 123 logged in');
|
|
623
|
+
|
|
624
|
+
// ✅ Good
|
|
625
|
+
console.log('User logged in', {
|
|
626
|
+
userId: 123,
|
|
627
|
+
email: 'user@example.com',
|
|
628
|
+
timestamp: Date.now(),
|
|
629
|
+
});
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### 2. Log at Appropriate Levels
|
|
633
|
+
|
|
634
|
+
```javascript
|
|
635
|
+
// Normal operations
|
|
636
|
+
console.info('Request processed', { userId: 123 });
|
|
637
|
+
|
|
638
|
+
// Warnings
|
|
639
|
+
console.warn('API rate limit approaching', { remaining: 10 });
|
|
640
|
+
|
|
641
|
+
// Errors
|
|
642
|
+
console.error('Database error', { error: err.message });
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### 3. Use Middleware for Request Logging
|
|
646
|
+
|
|
647
|
+
```javascript
|
|
648
|
+
app.use((req, res, next) => {
|
|
649
|
+
console.info('Request received', {
|
|
650
|
+
method: req.method,
|
|
651
|
+
path: req.path,
|
|
652
|
+
ip: req.ip,
|
|
653
|
+
});
|
|
654
|
+
next();
|
|
655
|
+
});
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### 4. Don't Enable Body Capture in Production
|
|
659
|
+
|
|
660
|
+
```env
|
|
661
|
+
# .env.development
|
|
662
|
+
SECURENOW_CAPTURE_BODY=1
|
|
663
|
+
|
|
664
|
+
# .env.production
|
|
665
|
+
SECURENOW_CAPTURE_BODY=0
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## Complete Environment Variables Reference
|
|
671
|
+
|
|
672
|
+
```env
|
|
673
|
+
# === Required ===
|
|
674
|
+
SECURENOW_APPID=my-express-app
|
|
675
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
676
|
+
|
|
677
|
+
# === Logging ===
|
|
678
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
679
|
+
|
|
680
|
+
# === Request Body Capture ===
|
|
681
|
+
SECURENOW_CAPTURE_BODY=1
|
|
682
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
683
|
+
SECURENOW_SENSITIVE_FIELDS=custom_field1,custom_field2
|
|
684
|
+
|
|
685
|
+
# === Service Naming ===
|
|
686
|
+
SECURENOW_NO_UUID=1
|
|
687
|
+
OTEL_SERVICE_NAME=my-express-app
|
|
688
|
+
|
|
689
|
+
# === Connection ===
|
|
690
|
+
OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-key
|
|
691
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
|
|
692
|
+
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://localhost:4318/v1/logs
|
|
693
|
+
|
|
694
|
+
# === Debugging ===
|
|
695
|
+
OTEL_LOG_LEVEL=debug
|
|
696
|
+
SECURENOW_TEST_SPAN=1
|
|
697
|
+
|
|
698
|
+
# === Environment ===
|
|
699
|
+
NODE_ENV=production
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## Next Steps
|
|
705
|
+
|
|
706
|
+
- Check your observability backend to see traces and logs
|
|
707
|
+
- Set up dashboards and alerts
|
|
708
|
+
- Explore the captured data to understand your application behavior
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## Support
|
|
713
|
+
|
|
714
|
+
- **Documentation:** [Main Docs](../README.md)
|
|
715
|
+
- **Examples:** [Express Examples](../examples/)
|
|
716
|
+
- **Issues:** GitHub Issues
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
**Your Express app is now fully observable!** 🎉
|