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
package/NPM_README.md
ADDED
|
@@ -0,0 +1,1328 @@
|
|
|
1
|
+
# SecureNow - Complete OpenTelemetry Observability for Node.js
|
|
2
|
+
|
|
3
|
+
OpenTelemetry instrumentation library for Node.js applications. Send distributed traces and logs to any OTLP-compatible observability backend.
|
|
4
|
+
|
|
5
|
+
**Features:**
|
|
6
|
+
- 🚀 Zero-config automatic instrumentation
|
|
7
|
+
- 📊 Distributed tracing for all popular frameworks
|
|
8
|
+
- 📋 Automatic logging with console instrumentation
|
|
9
|
+
- 🔐 Built-in sensitive data redaction
|
|
10
|
+
- 🎯 Request body capture for debugging
|
|
11
|
+
- 🔧 Fully configurable via environment variables
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Quick Start](#quick-start)
|
|
19
|
+
- [Framework-Specific Setup](#framework-specific-setup)
|
|
20
|
+
- [Express.js](#expressjs)
|
|
21
|
+
- [Next.js](#nextjs)
|
|
22
|
+
- [Fastify](#fastify)
|
|
23
|
+
- [NestJS](#nestjs)
|
|
24
|
+
- [Koa](#koa)
|
|
25
|
+
- [Hapi](#hapi)
|
|
26
|
+
- [Environment Variables Reference](#environment-variables-reference)
|
|
27
|
+
- [Logging Setup](#logging-setup)
|
|
28
|
+
- [Request Body Capture](#request-body-capture)
|
|
29
|
+
- [Advanced Configuration](#advanced-configuration)
|
|
30
|
+
- [TypeScript Support](#typescript-support)
|
|
31
|
+
- [Troubleshooting](#troubleshooting)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install securenow
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or with yarn:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yarn add securenow
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### 1. Set Environment Variables
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Required: Your application identifier
|
|
55
|
+
export SECURENOW_APPID=my-app
|
|
56
|
+
|
|
57
|
+
# Required: Your OTLP collector endpoint
|
|
58
|
+
export SECURENOW_INSTANCE=http://your-otlp-collector:4318
|
|
59
|
+
|
|
60
|
+
# Optional: Enable logging
|
|
61
|
+
export SECURENOW_LOGGING_ENABLED=1
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Initialize in Your Application
|
|
65
|
+
|
|
66
|
+
**Option A: Using NODE_OPTIONS (Recommended)**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
NODE_OPTIONS="-r securenow/register" node app.js
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Option B: Code-based initialization**
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// At the very top of your main file
|
|
76
|
+
require('securenow/register');
|
|
77
|
+
|
|
78
|
+
// Your application code
|
|
79
|
+
const express = require('express');
|
|
80
|
+
const app = express();
|
|
81
|
+
// ...
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Run Your Application
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
node app.js
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
You'll see confirmation in the console:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[securenow] OTel SDK started → http://your-otlp-collector:4318/v1/traces
|
|
94
|
+
[securenow] 📝 Request body capture: ENABLED
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Framework-Specific Setup
|
|
100
|
+
|
|
101
|
+
### Express.js
|
|
102
|
+
|
|
103
|
+
#### Basic Tracing Setup
|
|
104
|
+
|
|
105
|
+
**Step 1: Install**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npm install securenow express
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Step 2: Create `.env` file**
|
|
112
|
+
|
|
113
|
+
```env
|
|
114
|
+
SECURENOW_APPID=my-express-app
|
|
115
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
116
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Step 3: Initialize at the top of your main file**
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
// app.js or server.js
|
|
123
|
+
require('securenow/register');
|
|
124
|
+
require('securenow/console-instrumentation'); // Optional: for automatic logging
|
|
125
|
+
|
|
126
|
+
const express = require('express');
|
|
127
|
+
const app = express();
|
|
128
|
+
|
|
129
|
+
app.use(express.json());
|
|
130
|
+
|
|
131
|
+
app.get('/', (req, res) => {
|
|
132
|
+
console.log('Home page accessed'); // Automatically logged if console-instrumentation is enabled
|
|
133
|
+
res.send('Hello World');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
app.post('/api/users', (req, res) => {
|
|
137
|
+
console.info('User created', { userId: 123 });
|
|
138
|
+
res.json({ success: true });
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const PORT = process.env.PORT || 3000;
|
|
142
|
+
app.listen(PORT, () => {
|
|
143
|
+
console.log(`Server running on port ${PORT}`);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Step 4: Run**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# With NODE_OPTIONS
|
|
151
|
+
NODE_OPTIONS="-r securenow/register -r securenow/console-instrumentation" node app.js
|
|
152
|
+
|
|
153
|
+
# Or directly (if you added require statements)
|
|
154
|
+
node app.js
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### With PM2
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
// ecosystem.config.js
|
|
161
|
+
module.exports = {
|
|
162
|
+
apps: [{
|
|
163
|
+
name: 'my-app',
|
|
164
|
+
script: './app.js',
|
|
165
|
+
instances: 4,
|
|
166
|
+
exec_mode: 'cluster',
|
|
167
|
+
node_args: '-r securenow/register -r securenow/console-instrumentation',
|
|
168
|
+
env: {
|
|
169
|
+
SECURENOW_APPID: 'my-express-app',
|
|
170
|
+
SECURENOW_INSTANCE: 'http://localhost:4318',
|
|
171
|
+
SECURENOW_LOGGING_ENABLED: '1',
|
|
172
|
+
SECURENOW_NO_UUID: '1', // Use same service name across all instances
|
|
173
|
+
SECURENOW_CAPTURE_BODY: '1' // Enable request body capture
|
|
174
|
+
}
|
|
175
|
+
}]
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
pm2 start ecosystem.config.js
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### Next.js
|
|
186
|
+
|
|
187
|
+
#### App Router (Next.js 13+)
|
|
188
|
+
|
|
189
|
+
**Step 1: Install**
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm install securenow
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Step 2: Create `instrumentation.ts` (or `.js`) in your project root**
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// instrumentation.ts
|
|
199
|
+
export async function register() {
|
|
200
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
201
|
+
// Enable logging
|
|
202
|
+
process.env.SECURENOW_LOGGING_ENABLED = '1';
|
|
203
|
+
|
|
204
|
+
// Initialize tracing and logging
|
|
205
|
+
await import('securenow/register');
|
|
206
|
+
await import('securenow/console-instrumentation');
|
|
207
|
+
|
|
208
|
+
console.log('SecureNow observability initialized');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Step 3: Enable instrumentation hook in `next.config.js`**
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
// next.config.js
|
|
217
|
+
/** @type {import('next').NextConfig} */
|
|
218
|
+
const nextConfig = {
|
|
219
|
+
experimental: {
|
|
220
|
+
instrumentationHook: true,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
module.exports = nextConfig;
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Step 4: Create `.env.local`**
|
|
228
|
+
|
|
229
|
+
```env
|
|
230
|
+
SECURENOW_APPID=my-nextjs-app
|
|
231
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
232
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
233
|
+
SECURENOW_CAPTURE_BODY=1
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Step 5: Use in your application**
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// app/api/users/route.ts
|
|
240
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
241
|
+
|
|
242
|
+
export async function GET(request: NextRequest) {
|
|
243
|
+
console.log('GET /api/users called');
|
|
244
|
+
|
|
245
|
+
// Your logic here
|
|
246
|
+
const users = await fetchUsers();
|
|
247
|
+
|
|
248
|
+
console.info('Users fetched', { count: users.length });
|
|
249
|
+
return NextResponse.json(users);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export async function POST(request: NextRequest) {
|
|
253
|
+
const body = await request.json();
|
|
254
|
+
console.info('Creating user', { email: body.email });
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const user = await createUser(body);
|
|
258
|
+
console.log('User created successfully', { userId: user.id });
|
|
259
|
+
return NextResponse.json(user, { status: 201 });
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error('Failed to create user', { error: error.message });
|
|
262
|
+
return NextResponse.json({ error: 'Failed' }, { status: 500 });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Step 6: Run**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
npm run dev
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Pages Router (Next.js 12 and below)
|
|
274
|
+
|
|
275
|
+
**Step 1: Create `_app.js` or `_app.tsx`**
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
// pages/_app.js
|
|
279
|
+
if (typeof window === 'undefined') {
|
|
280
|
+
require('securenow/register');
|
|
281
|
+
require('securenow/console-instrumentation');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function MyApp({ Component, pageProps }) {
|
|
285
|
+
return <Component {...pageProps} />;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export default MyApp;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Step 2: Same `.env.local` as above**
|
|
292
|
+
|
|
293
|
+
**Step 3: Run**
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
npm run dev
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### Fastify
|
|
302
|
+
|
|
303
|
+
**Step 1: Install**
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
npm install securenow fastify
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Step 2: Create `.env`**
|
|
310
|
+
|
|
311
|
+
```env
|
|
312
|
+
SECURENOW_APPID=my-fastify-app
|
|
313
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
314
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Step 3: Initialize at the top**
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
// server.js
|
|
321
|
+
require('securenow/register');
|
|
322
|
+
require('securenow/console-instrumentation');
|
|
323
|
+
|
|
324
|
+
const fastify = require('fastify')({ logger: false });
|
|
325
|
+
|
|
326
|
+
// Logging hook
|
|
327
|
+
fastify.addHook('onRequest', async (request, reply) => {
|
|
328
|
+
console.info('Request received', {
|
|
329
|
+
method: request.method,
|
|
330
|
+
url: request.url,
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
fastify.get('/', async (request, reply) => {
|
|
335
|
+
console.log('Root endpoint called');
|
|
336
|
+
return { hello: 'world' };
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
fastify.post('/users', async (request, reply) => {
|
|
340
|
+
console.info('Creating user', { body: request.body });
|
|
341
|
+
// Your logic
|
|
342
|
+
return { success: true };
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Error handler
|
|
346
|
+
fastify.setErrorHandler((error, request, reply) => {
|
|
347
|
+
console.error('Fastify error', {
|
|
348
|
+
error: error.message,
|
|
349
|
+
stack: error.stack,
|
|
350
|
+
url: request.url,
|
|
351
|
+
});
|
|
352
|
+
reply.status(500).send({ error: 'Internal server error' });
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const start = async () => {
|
|
356
|
+
try {
|
|
357
|
+
await fastify.listen({ port: 3000 });
|
|
358
|
+
console.log('Fastify server running on port 3000');
|
|
359
|
+
} catch (err) {
|
|
360
|
+
console.error('Server start failed', { error: err });
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
start();
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Step 4: Run**
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
node server.js
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### NestJS
|
|
377
|
+
|
|
378
|
+
**Step 1: Install**
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
npm install securenow
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Step 2: Create `.env`**
|
|
385
|
+
|
|
386
|
+
```env
|
|
387
|
+
SECURENOW_APPID=my-nestjs-app
|
|
388
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
389
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Step 3: Initialize in `main.ts`**
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
// src/main.ts
|
|
396
|
+
require('securenow/register');
|
|
397
|
+
require('securenow/console-instrumentation');
|
|
398
|
+
|
|
399
|
+
import { NestFactory } from '@nestjs/core';
|
|
400
|
+
import { AppModule } from './app.module';
|
|
401
|
+
|
|
402
|
+
async function bootstrap() {
|
|
403
|
+
const app = await NestFactory.create(AppModule);
|
|
404
|
+
|
|
405
|
+
console.log('NestJS application starting');
|
|
406
|
+
|
|
407
|
+
await app.listen(3000);
|
|
408
|
+
console.log('Application is running on: http://localhost:3000');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
bootstrap();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Step 4: Use in services**
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
// src/users/users.service.ts
|
|
418
|
+
import { Injectable } from '@nestjs/common';
|
|
419
|
+
|
|
420
|
+
@Injectable()
|
|
421
|
+
export class UsersService {
|
|
422
|
+
async findAll() {
|
|
423
|
+
console.log('Fetching all users');
|
|
424
|
+
const users = await this.fetchFromDatabase();
|
|
425
|
+
console.info('Users retrieved', { count: users.length });
|
|
426
|
+
return users;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async create(userData: any) {
|
|
430
|
+
console.info('Creating user', { email: userData.email });
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
const user = await this.saveToDatabase(userData);
|
|
434
|
+
console.log('User created', { userId: user.id });
|
|
435
|
+
return user;
|
|
436
|
+
} catch (error) {
|
|
437
|
+
console.error('Failed to create user', {
|
|
438
|
+
error: error.message,
|
|
439
|
+
email: userData.email,
|
|
440
|
+
});
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Step 5: Run**
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
npm run start
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
### Koa
|
|
456
|
+
|
|
457
|
+
**Step 1: Install**
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
npm install securenow koa
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Step 2: Create `.env`**
|
|
464
|
+
|
|
465
|
+
```env
|
|
466
|
+
SECURENOW_APPID=my-koa-app
|
|
467
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
468
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Step 3: Initialize**
|
|
472
|
+
|
|
473
|
+
```javascript
|
|
474
|
+
// app.js
|
|
475
|
+
require('securenow/register');
|
|
476
|
+
require('securenow/console-instrumentation');
|
|
477
|
+
|
|
478
|
+
const Koa = require('koa');
|
|
479
|
+
const Router = require('@koa/router');
|
|
480
|
+
|
|
481
|
+
const app = new Koa();
|
|
482
|
+
const router = new Router();
|
|
483
|
+
|
|
484
|
+
// Logging middleware
|
|
485
|
+
app.use(async (ctx, next) => {
|
|
486
|
+
console.info('Request received', {
|
|
487
|
+
method: ctx.method,
|
|
488
|
+
path: ctx.path,
|
|
489
|
+
});
|
|
490
|
+
await next();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
router.get('/', (ctx) => {
|
|
494
|
+
console.log('Home page accessed');
|
|
495
|
+
ctx.body = { message: 'Hello World' };
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
router.post('/users', (ctx) => {
|
|
499
|
+
console.info('Creating user', { body: ctx.request.body });
|
|
500
|
+
ctx.body = { success: true };
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
app.use(router.routes());
|
|
504
|
+
|
|
505
|
+
const PORT = 3000;
|
|
506
|
+
app.listen(PORT, () => {
|
|
507
|
+
console.log(`Koa server running on port ${PORT}`);
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Step 4: Run**
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
node app.js
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
### Hapi
|
|
520
|
+
|
|
521
|
+
**Step 1: Install**
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
npm install securenow @hapi/hapi
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Step 2: Create `.env`**
|
|
528
|
+
|
|
529
|
+
```env
|
|
530
|
+
SECURENOW_APPID=my-hapi-app
|
|
531
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
532
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Step 3: Initialize**
|
|
536
|
+
|
|
537
|
+
```javascript
|
|
538
|
+
// server.js
|
|
539
|
+
require('securenow/register');
|
|
540
|
+
require('securenow/console-instrumentation');
|
|
541
|
+
|
|
542
|
+
const Hapi = require('@hapi/hapi');
|
|
543
|
+
|
|
544
|
+
const init = async () => {
|
|
545
|
+
const server = Hapi.server({
|
|
546
|
+
port: 3000,
|
|
547
|
+
host: 'localhost'
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// Logging extension
|
|
551
|
+
server.ext('onRequest', (request, h) => {
|
|
552
|
+
console.info('Request received', {
|
|
553
|
+
method: request.method,
|
|
554
|
+
path: request.path,
|
|
555
|
+
});
|
|
556
|
+
return h.continue;
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
server.route({
|
|
560
|
+
method: 'GET',
|
|
561
|
+
path: '/',
|
|
562
|
+
handler: (request, h) => {
|
|
563
|
+
console.log('Home page accessed');
|
|
564
|
+
return { message: 'Hello World' };
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
server.route({
|
|
569
|
+
method: 'POST',
|
|
570
|
+
path: '/users',
|
|
571
|
+
handler: (request, h) => {
|
|
572
|
+
console.info('Creating user', { payload: request.payload });
|
|
573
|
+
return { success: true };
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
await server.start();
|
|
578
|
+
console.log('Hapi server running on:', server.info.uri);
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
init();
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Step 4: Run**
|
|
585
|
+
|
|
586
|
+
```bash
|
|
587
|
+
node server.js
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Environment Variables Reference
|
|
593
|
+
|
|
594
|
+
### Required Variables
|
|
595
|
+
|
|
596
|
+
| Variable | Description | Example |
|
|
597
|
+
|----------|-------------|---------|
|
|
598
|
+
| `SECURENOW_APPID` | Your application identifier. Used as the service name in traces. | `my-app` |
|
|
599
|
+
| `SECURENOW_INSTANCE` | Base URL of your OTLP collector endpoint. | `http://localhost:4318` |
|
|
600
|
+
|
|
601
|
+
### Optional Configuration
|
|
602
|
+
|
|
603
|
+
#### Service Naming
|
|
604
|
+
|
|
605
|
+
| Variable | Description | Default |
|
|
606
|
+
|----------|-------------|---------|
|
|
607
|
+
| `OTEL_SERVICE_NAME` | Alternative to SECURENOW_APPID. Standard OpenTelemetry variable. | - |
|
|
608
|
+
| `SECURENOW_NO_UUID` | Set to `1` to disable UUID suffix on service name. Useful for clustered apps. | `0` |
|
|
609
|
+
| `SECURENOW_STRICT` | Set to `1` to exit process if SECURENOW_APPID is not set in cluster mode. | `0` |
|
|
610
|
+
|
|
611
|
+
#### Connection Settings
|
|
612
|
+
|
|
613
|
+
| Variable | Description | Default |
|
|
614
|
+
|----------|-------------|---------|
|
|
615
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Alternative to SECURENOW_INSTANCE. Standard OpenTelemetry variable. | - |
|
|
616
|
+
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Override traces endpoint specifically. | `{SECURENOW_INSTANCE}/v1/traces` |
|
|
617
|
+
| `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Override logs endpoint specifically. | `{SECURENOW_INSTANCE}/v1/logs` |
|
|
618
|
+
| `OTEL_EXPORTER_OTLP_HEADERS` | Headers to send with OTLP exports. Format: `key1=value1,key2=value2` | - |
|
|
619
|
+
|
|
620
|
+
#### Logging
|
|
621
|
+
|
|
622
|
+
| Variable | Description | Default |
|
|
623
|
+
|----------|-------------|---------|
|
|
624
|
+
| `SECURENOW_LOGGING_ENABLED` | Enable automatic logging to OTLP backend. Set to `1` to enable, `0` to disable. | `1` |
|
|
625
|
+
|
|
626
|
+
#### Request Body Capture
|
|
627
|
+
|
|
628
|
+
| Variable | Description | Default |
|
|
629
|
+
|----------|-------------|---------|
|
|
630
|
+
| `SECURENOW_CAPTURE_BODY` | Enable request body capture in traces. Set to `1` to enable. | `0` |
|
|
631
|
+
| `SECURENOW_MAX_BODY_SIZE` | Maximum body size to capture in bytes. Bodies larger than this are truncated. | `10240` (10KB) |
|
|
632
|
+
| `SECURENOW_SENSITIVE_FIELDS` | Comma-separated list of additional field names to redact. | - |
|
|
633
|
+
|
|
634
|
+
**Default sensitive fields (auto-redacted):** `password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `apikey`, `access_token`, `auth`, `credentials`, `mysql_pwd`, `stripeToken`, `card`, `cardnumber`, `ccv`, `cvc`, `cvv`, `ssn`, `pin`
|
|
635
|
+
|
|
636
|
+
#### Instrumentation Control
|
|
637
|
+
|
|
638
|
+
| Variable | Description | Default |
|
|
639
|
+
|----------|-------------|---------|
|
|
640
|
+
| `SECURENOW_DISABLE_INSTRUMENTATIONS` | Comma-separated list of instrumentation packages to disable. | - |
|
|
641
|
+
|
|
642
|
+
**Example:** `SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns` disables filesystem and DNS instrumentations.
|
|
643
|
+
|
|
644
|
+
#### Debugging
|
|
645
|
+
|
|
646
|
+
| Variable | Description | Default |
|
|
647
|
+
|----------|-------------|---------|
|
|
648
|
+
| `OTEL_LOG_LEVEL` | OpenTelemetry SDK log level. Options: `debug`, `info`, `warn`, `error` | `none` |
|
|
649
|
+
| `SECURENOW_TEST_SPAN` | Set to `1` to emit a test span on startup. | `0` |
|
|
650
|
+
|
|
651
|
+
#### Environment
|
|
652
|
+
|
|
653
|
+
| Variable | Description | Default |
|
|
654
|
+
|----------|-------------|---------|
|
|
655
|
+
| `NODE_ENV` | Deployment environment name. Sent as `deployment.environment` attribute. | `production` |
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## Logging Setup
|
|
660
|
+
|
|
661
|
+
### Automatic Console Logging
|
|
662
|
+
|
|
663
|
+
The easiest way to send logs is to use the console instrumentation wrapper:
|
|
664
|
+
|
|
665
|
+
```javascript
|
|
666
|
+
// At the top of your main file
|
|
667
|
+
require('securenow/register');
|
|
668
|
+
require('securenow/console-instrumentation');
|
|
669
|
+
|
|
670
|
+
// Now all console logs are automatically sent
|
|
671
|
+
console.log('Application started');
|
|
672
|
+
console.info('User action', { userId: 123, action: 'login' });
|
|
673
|
+
console.warn('Deprecation warning');
|
|
674
|
+
console.error('Error occurred', { error: 'Something failed' });
|
|
675
|
+
console.debug('Debug info');
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
**Severity mapping:**
|
|
679
|
+
- `console.log()` → INFO
|
|
680
|
+
- `console.info()` → INFO
|
|
681
|
+
- `console.warn()` → WARN
|
|
682
|
+
- `console.error()` → ERROR
|
|
683
|
+
- `console.debug()` → DEBUG
|
|
684
|
+
|
|
685
|
+
**Environment variable:**
|
|
686
|
+
```bash
|
|
687
|
+
SECURENOW_LOGGING_ENABLED=1
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Direct Logger API
|
|
691
|
+
|
|
692
|
+
For more control, use the OpenTelemetry logger API:
|
|
693
|
+
|
|
694
|
+
```javascript
|
|
695
|
+
require('securenow/register');
|
|
696
|
+
const { getLogger } = require('securenow/tracing');
|
|
697
|
+
|
|
698
|
+
// Get a logger instance
|
|
699
|
+
const logger = getLogger('my-module', '1.0.0');
|
|
700
|
+
|
|
701
|
+
// Emit structured logs
|
|
702
|
+
logger.emit({
|
|
703
|
+
severityNumber: 9, // INFO
|
|
704
|
+
severityText: 'INFO',
|
|
705
|
+
body: 'User logged in',
|
|
706
|
+
attributes: {
|
|
707
|
+
userId: 123,
|
|
708
|
+
username: 'john',
|
|
709
|
+
sessionId: 'abc123',
|
|
710
|
+
},
|
|
711
|
+
});
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
**Severity numbers:**
|
|
715
|
+
- `5` - DEBUG
|
|
716
|
+
- `9` - INFO
|
|
717
|
+
- `13` - WARN
|
|
718
|
+
- `17` - ERROR
|
|
719
|
+
|
|
720
|
+
### Using with NODE_OPTIONS
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
# Enable both tracing and logging
|
|
724
|
+
NODE_OPTIONS="-r securenow/register -r securenow/console-instrumentation" \
|
|
725
|
+
SECURENOW_APPID=my-app \
|
|
726
|
+
SECURENOW_INSTANCE=http://localhost:4318 \
|
|
727
|
+
SECURENOW_LOGGING_ENABLED=1 \
|
|
728
|
+
node app.js
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
## Request Body Capture
|
|
734
|
+
|
|
735
|
+
SecureNow can capture HTTP request bodies in traces for debugging purposes. This is disabled by default.
|
|
736
|
+
|
|
737
|
+
### Enable Body Capture
|
|
738
|
+
|
|
739
|
+
```bash
|
|
740
|
+
export SECURENOW_CAPTURE_BODY=1
|
|
741
|
+
export SECURENOW_MAX_BODY_SIZE=10240 # 10KB (optional)
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Supported Content Types
|
|
745
|
+
|
|
746
|
+
- `application/json`
|
|
747
|
+
- `application/x-www-form-urlencoded`
|
|
748
|
+
- `application/graphql`
|
|
749
|
+
|
|
750
|
+
**Note:** Multipart form data (file uploads) are NOT captured by design.
|
|
751
|
+
|
|
752
|
+
### Sensitive Data Redaction
|
|
753
|
+
|
|
754
|
+
All request bodies are automatically scanned and sensitive fields are redacted:
|
|
755
|
+
|
|
756
|
+
**Automatically redacted fields:** `password`, `secret`, `token`, `api_key`, `card`, `cvv`, `ssn`, and more.
|
|
757
|
+
|
|
758
|
+
**Add custom fields to redact:**
|
|
759
|
+
|
|
760
|
+
```bash
|
|
761
|
+
export SECURENOW_SENSITIVE_FIELDS="custom_secret,internal_token"
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Example
|
|
765
|
+
|
|
766
|
+
```javascript
|
|
767
|
+
// POST /api/users with body:
|
|
768
|
+
{
|
|
769
|
+
"email": "user@example.com",
|
|
770
|
+
"password": "secret123",
|
|
771
|
+
"name": "John Doe"
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Captured in trace as:
|
|
775
|
+
{
|
|
776
|
+
"email": "user@example.com",
|
|
777
|
+
"password": "[REDACTED]",
|
|
778
|
+
"name": "John Doe"
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
## Advanced Configuration
|
|
785
|
+
|
|
786
|
+
### Complete Example with All Options
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
# Service identification
|
|
790
|
+
export SECURENOW_APPID=my-production-app
|
|
791
|
+
export SECURENOW_NO_UUID=1
|
|
792
|
+
export SECURENOW_STRICT=1
|
|
793
|
+
|
|
794
|
+
# OTLP backend
|
|
795
|
+
export SECURENOW_INSTANCE=http://collector.example.com:4318
|
|
796
|
+
export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key"
|
|
797
|
+
|
|
798
|
+
# Logging
|
|
799
|
+
export SECURENOW_LOGGING_ENABLED=1
|
|
800
|
+
|
|
801
|
+
# Request body capture
|
|
802
|
+
export SECURENOW_CAPTURE_BODY=1
|
|
803
|
+
export SECURENOW_MAX_BODY_SIZE=20480
|
|
804
|
+
export SECURENOW_SENSITIVE_FIELDS="internal_id,session_key"
|
|
805
|
+
|
|
806
|
+
# Environment
|
|
807
|
+
export NODE_ENV=production
|
|
808
|
+
|
|
809
|
+
# Debugging
|
|
810
|
+
export OTEL_LOG_LEVEL=info
|
|
811
|
+
|
|
812
|
+
# Disable specific instrumentations
|
|
813
|
+
export SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns
|
|
814
|
+
|
|
815
|
+
# Run application
|
|
816
|
+
NODE_OPTIONS="-r securenow/register -r securenow/console-instrumentation" node app.js
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### Using Multiple Logger Instances
|
|
820
|
+
|
|
821
|
+
```javascript
|
|
822
|
+
const { getLogger } = require('securenow/tracing');
|
|
823
|
+
|
|
824
|
+
const authLogger = getLogger('auth-service', '1.0.0');
|
|
825
|
+
const dbLogger = getLogger('database', '1.0.0');
|
|
826
|
+
const apiLogger = getLogger('api-handler', '1.0.0');
|
|
827
|
+
|
|
828
|
+
authLogger.emit({
|
|
829
|
+
severityNumber: 9,
|
|
830
|
+
severityText: 'INFO',
|
|
831
|
+
body: 'User authenticated',
|
|
832
|
+
attributes: { userId: 123 },
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
dbLogger.emit({
|
|
836
|
+
severityNumber: 13,
|
|
837
|
+
severityText: 'WARN',
|
|
838
|
+
body: 'Slow query detected',
|
|
839
|
+
attributes: { queryTime: 5000 },
|
|
840
|
+
});
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### Check if Logging is Enabled
|
|
844
|
+
|
|
845
|
+
```javascript
|
|
846
|
+
const { isLoggingEnabled } = require('securenow/tracing');
|
|
847
|
+
|
|
848
|
+
if (isLoggingEnabled()) {
|
|
849
|
+
console.log('Logging is enabled');
|
|
850
|
+
} else {
|
|
851
|
+
console.log('Logging is disabled');
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
### Programmatic Configuration
|
|
856
|
+
|
|
857
|
+
While environment variables are recommended, you can also configure programmatically:
|
|
858
|
+
|
|
859
|
+
```javascript
|
|
860
|
+
// Set environment variables before requiring securenow
|
|
861
|
+
process.env.SECURENOW_APPID = 'my-app';
|
|
862
|
+
process.env.SECURENOW_INSTANCE = 'http://localhost:4318';
|
|
863
|
+
process.env.SECURENOW_LOGGING_ENABLED = '1';
|
|
864
|
+
|
|
865
|
+
// Then initialize
|
|
866
|
+
require('securenow/register');
|
|
867
|
+
require('securenow/console-instrumentation');
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
---
|
|
871
|
+
|
|
872
|
+
## TypeScript Support
|
|
873
|
+
|
|
874
|
+
SecureNow includes full TypeScript definitions.
|
|
875
|
+
|
|
876
|
+
### Type Definitions
|
|
877
|
+
|
|
878
|
+
```typescript
|
|
879
|
+
import { getLogger, isLoggingEnabled, Logger, LogRecord } from 'securenow/tracing';
|
|
880
|
+
|
|
881
|
+
// Get a typed logger
|
|
882
|
+
const logger: Logger | null = getLogger('my-service', '1.0.0');
|
|
883
|
+
|
|
884
|
+
// Emit a log with type checking
|
|
885
|
+
if (logger) {
|
|
886
|
+
const logRecord: LogRecord = {
|
|
887
|
+
severityNumber: 9,
|
|
888
|
+
severityText: 'INFO',
|
|
889
|
+
body: 'User action',
|
|
890
|
+
attributes: {
|
|
891
|
+
userId: 123,
|
|
892
|
+
action: 'login',
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
logger.emit(logRecord);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Check if enabled
|
|
900
|
+
const enabled: boolean = isLoggingEnabled();
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### Next.js with TypeScript
|
|
904
|
+
|
|
905
|
+
```typescript
|
|
906
|
+
// instrumentation.ts
|
|
907
|
+
export async function register() {
|
|
908
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
909
|
+
process.env.SECURENOW_LOGGING_ENABLED = '1';
|
|
910
|
+
|
|
911
|
+
await import('securenow/register');
|
|
912
|
+
await import('securenow/console-instrumentation');
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
### NestJS with TypeScript
|
|
918
|
+
|
|
919
|
+
```typescript
|
|
920
|
+
// main.ts
|
|
921
|
+
require('securenow/register');
|
|
922
|
+
require('securenow/console-instrumentation');
|
|
923
|
+
|
|
924
|
+
import { NestFactory } from '@nestjs/core';
|
|
925
|
+
import { AppModule } from './app.module';
|
|
926
|
+
|
|
927
|
+
async function bootstrap() {
|
|
928
|
+
const app = await NestFactory.create(AppModule);
|
|
929
|
+
await app.listen(3000);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
bootstrap();
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
## Troubleshooting
|
|
938
|
+
|
|
939
|
+
### Traces Not Appearing
|
|
940
|
+
|
|
941
|
+
**Check 1: Verify environment variables**
|
|
942
|
+
|
|
943
|
+
```bash
|
|
944
|
+
echo $SECURENOW_APPID
|
|
945
|
+
echo $SECURENOW_INSTANCE
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
Both should output values.
|
|
949
|
+
|
|
950
|
+
**Check 2: Verify OTLP collector is running**
|
|
951
|
+
|
|
952
|
+
```bash
|
|
953
|
+
curl http://localhost:4318/v1/traces
|
|
954
|
+
# Should return 200 or 405 (method not allowed)
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
**Check 3: Enable debug logging**
|
|
958
|
+
|
|
959
|
+
```bash
|
|
960
|
+
export OTEL_LOG_LEVEL=debug
|
|
961
|
+
node app.js
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Look for lines like:
|
|
965
|
+
```
|
|
966
|
+
[securenow] OTel SDK started → http://localhost:4318/v1/traces
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
**Check 4: Verify initialization order**
|
|
970
|
+
|
|
971
|
+
SecureNow must be required BEFORE any other modules:
|
|
972
|
+
|
|
973
|
+
```javascript
|
|
974
|
+
// ✅ Correct
|
|
975
|
+
require('securenow/register');
|
|
976
|
+
const express = require('express');
|
|
977
|
+
|
|
978
|
+
// ❌ Wrong - too late!
|
|
979
|
+
const express = require('express');
|
|
980
|
+
require('securenow/register');
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### Logs Not Appearing
|
|
984
|
+
|
|
985
|
+
**Check 1: Is logging enabled?**
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
echo $SECURENOW_LOGGING_ENABLED
|
|
989
|
+
# Should output: 1
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
**Check 2: Verify console instrumentation is loaded**
|
|
993
|
+
|
|
994
|
+
```javascript
|
|
995
|
+
// Must load after register
|
|
996
|
+
require('securenow/register');
|
|
997
|
+
require('securenow/console-instrumentation');
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
**Check 3: Check console output**
|
|
1001
|
+
|
|
1002
|
+
You should see:
|
|
1003
|
+
```
|
|
1004
|
+
[securenow] 📋 Logging: ENABLED → http://localhost:4318/v1/logs
|
|
1005
|
+
[securenow] Console instrumentation installed
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
**Check 4: Verify OTLP logs endpoint**
|
|
1009
|
+
|
|
1010
|
+
```bash
|
|
1011
|
+
curl http://localhost:4318/v1/logs
|
|
1012
|
+
# Should return 200 or 405
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
### Request Body Not Captured
|
|
1016
|
+
|
|
1017
|
+
**Check 1: Is body capture enabled?**
|
|
1018
|
+
|
|
1019
|
+
```bash
|
|
1020
|
+
export SECURENOW_CAPTURE_BODY=1
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
**Check 2: Verify content type**
|
|
1024
|
+
|
|
1025
|
+
Body capture only works for:
|
|
1026
|
+
- `application/json`
|
|
1027
|
+
- `application/x-www-form-urlencoded`
|
|
1028
|
+
- `application/graphql`
|
|
1029
|
+
|
|
1030
|
+
**Check 3: Check body size**
|
|
1031
|
+
|
|
1032
|
+
Bodies larger than `SECURENOW_MAX_BODY_SIZE` are truncated:
|
|
1033
|
+
|
|
1034
|
+
```bash
|
|
1035
|
+
export SECURENOW_MAX_BODY_SIZE=20480 # Increase to 20KB
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
### High Memory Usage
|
|
1039
|
+
|
|
1040
|
+
**Option 1: Disable body capture**
|
|
1041
|
+
|
|
1042
|
+
```bash
|
|
1043
|
+
export SECURENOW_CAPTURE_BODY=0
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
**Option 2: Reduce body size limit**
|
|
1047
|
+
|
|
1048
|
+
```bash
|
|
1049
|
+
export SECURENOW_MAX_BODY_SIZE=5120 # 5KB
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
**Option 3: Disable specific instrumentations**
|
|
1053
|
+
|
|
1054
|
+
```bash
|
|
1055
|
+
export SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns,net
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
### Next.js Instrumentation Not Working
|
|
1059
|
+
|
|
1060
|
+
**Check 1: Verify instrumentation file location**
|
|
1061
|
+
|
|
1062
|
+
`instrumentation.ts` or `instrumentation.js` must be in the project root (same level as `app/` or `pages/`).
|
|
1063
|
+
|
|
1064
|
+
**Check 2: Enable instrumentation hook**
|
|
1065
|
+
|
|
1066
|
+
```javascript
|
|
1067
|
+
// next.config.js
|
|
1068
|
+
module.exports = {
|
|
1069
|
+
experimental: {
|
|
1070
|
+
instrumentationHook: true,
|
|
1071
|
+
},
|
|
1072
|
+
};
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
**Check 3: Restart dev server**
|
|
1076
|
+
|
|
1077
|
+
```bash
|
|
1078
|
+
# Kill the server and restart
|
|
1079
|
+
npm run dev
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### PM2 Cluster Issues
|
|
1083
|
+
|
|
1084
|
+
**Problem: Different service names for each worker**
|
|
1085
|
+
|
|
1086
|
+
**Solution: Use SECURENOW_NO_UUID**
|
|
1087
|
+
|
|
1088
|
+
```bash
|
|
1089
|
+
export SECURENOW_NO_UUID=1
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
This uses the same service name for all workers.
|
|
1093
|
+
|
|
1094
|
+
**Problem: Workers not instrumented**
|
|
1095
|
+
|
|
1096
|
+
**Solution: Use node_args in PM2 config**
|
|
1097
|
+
|
|
1098
|
+
```javascript
|
|
1099
|
+
// ecosystem.config.js
|
|
1100
|
+
module.exports = {
|
|
1101
|
+
apps: [{
|
|
1102
|
+
name: 'my-app',
|
|
1103
|
+
script: './app.js',
|
|
1104
|
+
instances: 4,
|
|
1105
|
+
node_args: '-r securenow/register',
|
|
1106
|
+
env: {
|
|
1107
|
+
SECURENOW_APPID: 'my-app',
|
|
1108
|
+
SECURENOW_INSTANCE: 'http://localhost:4318',
|
|
1109
|
+
}
|
|
1110
|
+
}]
|
|
1111
|
+
};
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
---
|
|
1115
|
+
|
|
1116
|
+
## Best Practices
|
|
1117
|
+
|
|
1118
|
+
### 1. Use Environment Variables
|
|
1119
|
+
|
|
1120
|
+
Don't hardcode configuration. Use environment variables:
|
|
1121
|
+
|
|
1122
|
+
```javascript
|
|
1123
|
+
// ❌ Bad
|
|
1124
|
+
process.env.SECURENOW_APPID = 'hardcoded-value';
|
|
1125
|
+
|
|
1126
|
+
// ✅ Good - use .env file or export
|
|
1127
|
+
// .env
|
|
1128
|
+
SECURENOW_APPID=my-app
|
|
1129
|
+
SECURENOW_INSTANCE=http://localhost:4318
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
### 2. Use Structured Logging
|
|
1133
|
+
|
|
1134
|
+
Pass objects to console methods for better filtering:
|
|
1135
|
+
|
|
1136
|
+
```javascript
|
|
1137
|
+
// ❌ Less useful
|
|
1138
|
+
console.log('User 123 logged in');
|
|
1139
|
+
|
|
1140
|
+
// ✅ Better - structured attributes
|
|
1141
|
+
console.log('User logged in', {
|
|
1142
|
+
userId: 123,
|
|
1143
|
+
email: 'user@example.com',
|
|
1144
|
+
timestamp: new Date().toISOString(),
|
|
1145
|
+
});
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
### 3. Choose Appropriate Severity Levels
|
|
1149
|
+
|
|
1150
|
+
```javascript
|
|
1151
|
+
// Normal operations
|
|
1152
|
+
console.log('Request processed');
|
|
1153
|
+
console.info('User created', { userId: 123 });
|
|
1154
|
+
|
|
1155
|
+
// Warnings
|
|
1156
|
+
console.warn('API rate limit approaching', { remaining: 10 });
|
|
1157
|
+
|
|
1158
|
+
// Errors
|
|
1159
|
+
console.error('Database connection failed', { error: err.message });
|
|
1160
|
+
|
|
1161
|
+
// Debug (only in development)
|
|
1162
|
+
console.debug('Cache hit', { key: 'user:123' });
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
### 4. Don't Log Sensitive Data
|
|
1166
|
+
|
|
1167
|
+
Even though SecureNow automatically redacts common sensitive fields, avoid logging:
|
|
1168
|
+
|
|
1169
|
+
```javascript
|
|
1170
|
+
// ❌ Bad
|
|
1171
|
+
console.log('Login attempt', {
|
|
1172
|
+
email: 'user@example.com',
|
|
1173
|
+
password: 'secret123', // Will be redacted, but don't log it!
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
// ✅ Good
|
|
1177
|
+
console.log('Login attempt', {
|
|
1178
|
+
email: 'user@example.com',
|
|
1179
|
+
timestamp: Date.now(),
|
|
1180
|
+
});
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
### 5. Use Different Logger Instances for Different Modules
|
|
1184
|
+
|
|
1185
|
+
```javascript
|
|
1186
|
+
// auth-service.js
|
|
1187
|
+
const authLogger = getLogger('auth-service', '1.0.0');
|
|
1188
|
+
|
|
1189
|
+
// database.js
|
|
1190
|
+
const dbLogger = getLogger('database', '1.0.0');
|
|
1191
|
+
|
|
1192
|
+
// api.js
|
|
1193
|
+
const apiLogger = getLogger('api', '1.0.0');
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
### 6. Enable Body Capture Only in Development
|
|
1197
|
+
|
|
1198
|
+
```bash
|
|
1199
|
+
# .env.development
|
|
1200
|
+
SECURENOW_CAPTURE_BODY=1
|
|
1201
|
+
|
|
1202
|
+
# .env.production
|
|
1203
|
+
SECURENOW_CAPTURE_BODY=0
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
---
|
|
1207
|
+
|
|
1208
|
+
## Supported Runtimes
|
|
1209
|
+
|
|
1210
|
+
- **Node.js:** 18+
|
|
1211
|
+
- **Frameworks:** Express, Next.js, Fastify, NestJS, Koa, Hapi, and more
|
|
1212
|
+
- **Databases:** PostgreSQL, MySQL, MongoDB, Redis
|
|
1213
|
+
- **HTTP Clients:** axios, fetch, node-fetch, got, request
|
|
1214
|
+
- **GraphQL:** Apollo Server, GraphQL.js
|
|
1215
|
+
- **Message Queues:** Redis, BullMQ
|
|
1216
|
+
- **And many more via OpenTelemetry auto-instrumentation**
|
|
1217
|
+
|
|
1218
|
+
---
|
|
1219
|
+
|
|
1220
|
+
## Automatic Instrumentations
|
|
1221
|
+
|
|
1222
|
+
SecureNow automatically instruments:
|
|
1223
|
+
|
|
1224
|
+
- HTTP/HTTPS (incoming and outgoing)
|
|
1225
|
+
- Express.js
|
|
1226
|
+
- Fastify
|
|
1227
|
+
- Koa
|
|
1228
|
+
- Hapi
|
|
1229
|
+
- Next.js
|
|
1230
|
+
- PostgreSQL
|
|
1231
|
+
- MySQL/MySQL2
|
|
1232
|
+
- MongoDB
|
|
1233
|
+
- Redis
|
|
1234
|
+
- GraphQL
|
|
1235
|
+
- gRPC
|
|
1236
|
+
- DNS
|
|
1237
|
+
- File System
|
|
1238
|
+
- And 50+ more libraries
|
|
1239
|
+
|
|
1240
|
+
No code changes needed!
|
|
1241
|
+
|
|
1242
|
+
---
|
|
1243
|
+
|
|
1244
|
+
## Architecture
|
|
1245
|
+
|
|
1246
|
+
```
|
|
1247
|
+
┌─────────────────────────────────┐
|
|
1248
|
+
│ Your Application │
|
|
1249
|
+
│ (Express/Next.js/etc) │
|
|
1250
|
+
└───────────────┬─────────────────┘
|
|
1251
|
+
│
|
|
1252
|
+
▼
|
|
1253
|
+
┌─────────────────────────────────┐
|
|
1254
|
+
│ SecureNow Library │
|
|
1255
|
+
│ - Auto-instrumentation │
|
|
1256
|
+
│ - Console wrapper (optional) │
|
|
1257
|
+
│ - Body capture (optional) │
|
|
1258
|
+
└───────────────┬─────────────────┘
|
|
1259
|
+
│
|
|
1260
|
+
▼
|
|
1261
|
+
┌─────────────────────────────────┐
|
|
1262
|
+
│ OpenTelemetry SDK │
|
|
1263
|
+
│ - Trace/Log processors │
|
|
1264
|
+
│ - OTLP exporters │
|
|
1265
|
+
└───────────────┬─────────────────┘
|
|
1266
|
+
│
|
|
1267
|
+
▼
|
|
1268
|
+
┌─────────────────────────────────┐
|
|
1269
|
+
│ OTLP Collector/Backend │
|
|
1270
|
+
│ (Your observability platform) │
|
|
1271
|
+
└─────────────────────────────────┘
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
---
|
|
1275
|
+
|
|
1276
|
+
## Performance
|
|
1277
|
+
|
|
1278
|
+
- **Minimal overhead:** < 1% CPU and memory impact
|
|
1279
|
+
- **Batch export:** Traces and logs are batched before sending
|
|
1280
|
+
- **Async processing:** No blocking of application threads
|
|
1281
|
+
- **Configurable:** Disable instrumentations you don't need
|
|
1282
|
+
|
|
1283
|
+
---
|
|
1284
|
+
|
|
1285
|
+
## Security
|
|
1286
|
+
|
|
1287
|
+
- **Automatic redaction** of sensitive fields (passwords, tokens, keys)
|
|
1288
|
+
- **Configurable** sensitive field patterns
|
|
1289
|
+
- **No data stored** locally - everything sent to your OTLP backend
|
|
1290
|
+
- **Open source** - audit the code yourself
|
|
1291
|
+
|
|
1292
|
+
---
|
|
1293
|
+
|
|
1294
|
+
## License
|
|
1295
|
+
|
|
1296
|
+
ISC
|
|
1297
|
+
|
|
1298
|
+
---
|
|
1299
|
+
|
|
1300
|
+
## Support
|
|
1301
|
+
|
|
1302
|
+
- **Documentation:** [GitHub Docs](https://github.com/your-repo/securenow-npm/tree/main/docs)
|
|
1303
|
+
- **Issues:** [GitHub Issues](https://github.com/your-repo/securenow-npm/issues)
|
|
1304
|
+
- **Examples:** [GitHub Examples](https://github.com/your-repo/securenow-npm/tree/main/examples)
|
|
1305
|
+
|
|
1306
|
+
---
|
|
1307
|
+
|
|
1308
|
+
## Changelog
|
|
1309
|
+
|
|
1310
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
1311
|
+
|
|
1312
|
+
---
|
|
1313
|
+
|
|
1314
|
+
## Contributing
|
|
1315
|
+
|
|
1316
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
1317
|
+
|
|
1318
|
+
---
|
|
1319
|
+
|
|
1320
|
+
## Related Packages
|
|
1321
|
+
|
|
1322
|
+
- [@opentelemetry/sdk-node](https://www.npmjs.com/package/@opentelemetry/sdk-node) - Core OpenTelemetry SDK
|
|
1323
|
+
- [@opentelemetry/auto-instrumentations-node](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) - Auto-instrumentation
|
|
1324
|
+
- [@opentelemetry/exporter-trace-otlp-http](https://www.npmjs.com/package/@opentelemetry/exporter-trace-otlp-http) - OTLP exporter
|
|
1325
|
+
|
|
1326
|
+
---
|
|
1327
|
+
|
|
1328
|
+
**Made with ❤️ for the Node.js community**
|