@senzops/apm-node 1.2.7 → 1.3.0
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/CHANGELOG.md +9 -0
- package/README.md +479 -398
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/register.js +1 -1
- package/dist/register.js.map +1 -1
- package/dist/register.mjs +1 -1
- package/dist/register.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/client.ts +57 -0
- package/src/core/context.ts +71 -9
- package/src/core/transport.ts +20 -3
- package/src/core/types.ts +5 -1
- package/src/index.ts +4 -0
- package/src/instrumentation/amqplib.ts +371 -0
- package/src/instrumentation/anthropic.ts +245 -0
- package/src/instrumentation/aws-sdk.ts +403 -0
- package/src/instrumentation/azure-openai.ts +177 -0
- package/src/instrumentation/bunyan.ts +93 -0
- package/src/instrumentation/cassandra.ts +367 -0
- package/src/instrumentation/cohere.ts +227 -0
- package/src/instrumentation/connect.ts +200 -0
- package/src/instrumentation/dataloader.ts +291 -0
- package/src/instrumentation/dns.ts +220 -0
- package/src/instrumentation/firebase.ts +445 -0
- package/src/instrumentation/fs.ts +260 -0
- package/src/instrumentation/generic-pool.ts +317 -0
- package/src/instrumentation/google-genai.ts +426 -0
- package/src/instrumentation/graphql.ts +434 -0
- package/src/instrumentation/grpc.ts +666 -0
- package/src/instrumentation/hapi.ts +257 -0
- package/src/instrumentation/kafka.ts +360 -0
- package/src/instrumentation/knex.ts +249 -0
- package/src/instrumentation/lru-memoizer.ts +175 -0
- package/src/instrumentation/memcached.ts +190 -0
- package/src/instrumentation/mistral.ts +254 -0
- package/src/instrumentation/nestjs.ts +243 -0
- package/src/instrumentation/net.ts +171 -0
- package/src/instrumentation/openai.ts +281 -0
- package/src/instrumentation/pino.ts +170 -0
- package/src/instrumentation/restify.ts +213 -0
- package/src/instrumentation/runtime.ts +352 -0
- package/src/instrumentation/socketio.ts +272 -0
- package/src/instrumentation/tedious.ts +509 -0
- package/src/instrumentation/winston.ts +149 -0
- package/src/register.ts +22 -3
- package/src/wrappers/lambda.ts +417 -0
- package/tsup.config.ts +3 -3
- package/wiki.md +1547 -852
package/README.md
CHANGED
|
@@ -1,398 +1,479 @@
|
|
|
1
|
-
# @senzops/apm-node
|
|
2
|
-
|
|
3
|
-
Official Node.js SDK for Senzor
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
|
87
|
-
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Senzor
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Senzor
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
1
|
+
# @senzops/apm-node
|
|
2
|
+
|
|
3
|
+
Official Node.js APM SDK for [Senzor](https://senzor.dev). Zero-dependency, production-grade distributed tracing, error tracking, log correlation, background task monitoring, and runtime metrics for Node.js services.
|
|
4
|
+
|
|
5
|
+
Replaces OpenTelemetry auto-instrumentation with a lightweight, Senzor-native alternative. 43 auto-instrumentations, 8 framework wrappers, and full AWS Lambda support in a single package with zero runtime dependencies.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @senzops/apm-node
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Option 1: Preload Mode (Recommended)
|
|
16
|
+
|
|
17
|
+
Preload ensures instrumentation hooks install before your application imports any library.
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
# CommonJS
|
|
21
|
+
SENZOR_API_KEY=sz_apm_xxx node -r @senzops/apm-node/register server.js
|
|
22
|
+
|
|
23
|
+
# ESM
|
|
24
|
+
SENZOR_API_KEY=sz_apm_xxx node --import @senzops/apm-node/register server.mjs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Option 2: Programmatic Init
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import Senzor from '@senzops/apm-node';
|
|
31
|
+
|
|
32
|
+
Senzor.init({
|
|
33
|
+
apiKey: process.env.SENZOR_API_KEY!,
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Initialize as early as possible, before importing application modules.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Auto-Instrumentation Coverage
|
|
42
|
+
|
|
43
|
+
All instrumentations activate automatically when the corresponding library is imported. No configuration required.
|
|
44
|
+
|
|
45
|
+
### Web Frameworks & HTTP
|
|
46
|
+
|
|
47
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
48
|
+
|---|---------|-------------------|-----------------|
|
|
49
|
+
| 1 | Node `http` / `https` | `http` | Inbound requests, outbound calls, distributed trace propagation |
|
|
50
|
+
| 2 | `fetch` (global) | `fetch` | Outbound HTTP, W3C Traceparent propagation |
|
|
51
|
+
| 3 | `undici` | `undici` | Outbound HTTP via Node's native HTTP client |
|
|
52
|
+
| 4 | Express | `express` | Route matching, middleware spans, error capture |
|
|
53
|
+
| 5 | Fastify | `fastify` | Route matching, hook spans, lifecycle spans |
|
|
54
|
+
| 6 | Koa | `koa` | Middleware stack, route detection |
|
|
55
|
+
| 7 | NestJS | `nestjs` | Controller/method resolution, Guards, Interceptors, Pipes |
|
|
56
|
+
| 8 | Hapi | `hapi` | Route handling, request lifecycle |
|
|
57
|
+
| 9 | Restify | `restify` | Route matching, handler chain spans |
|
|
58
|
+
| 10 | Connect | `connect` | Middleware stack instrumentation |
|
|
59
|
+
|
|
60
|
+
### Databases
|
|
61
|
+
|
|
62
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
63
|
+
|---|---------|-------------------|-----------------|
|
|
64
|
+
| 11 | `pg` (PostgreSQL) | `pg` | Queries, prepared statements, row counts, sanitized SQL |
|
|
65
|
+
| 12 | `mongodb` | `mongo` | Collection operations (find, insert, update, delete, aggregate, bulk) |
|
|
66
|
+
| 13 | `mongoose` | `mongoose` | Model operations with model/collection names |
|
|
67
|
+
| 14 | `mysql` / `mysql2` | `mysql` | Queries, sanitized SQL, connection metadata |
|
|
68
|
+
| 15 | `redis` / `ioredis` | `redis` | Commands (GET, SET, HGETALL, etc.), key names |
|
|
69
|
+
| 16 | `knex` | `knex` | Query builder operations, raw queries, transactions |
|
|
70
|
+
| 17 | `tedious` (SQL Server) | `tedious` | T-SQL queries, stored procedures, row counts |
|
|
71
|
+
| 18 | `cassandra-driver` | `cassandra` | CQL queries, batch operations, prepared statements |
|
|
72
|
+
| 19 | `memcached` | `memcached` | get, set, delete, incr/decr, flush operations |
|
|
73
|
+
|
|
74
|
+
### Messaging & Queues
|
|
75
|
+
|
|
76
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
77
|
+
|---|---------|-------------------|-----------------|
|
|
78
|
+
| 20 | `kafkajs` | `kafka` | Producer send, consumer message processing, topic/partition |
|
|
79
|
+
| 21 | `amqplib` (RabbitMQ) | `amqplib` | Publish, consume, ack/nack, queue/exchange names |
|
|
80
|
+
| 22 | `socket.io` | `socketio` | Event emit/receive, namespace, room operations |
|
|
81
|
+
| 23 | `bullmq` | `bullmq` | Worker job processing as task runs, queue delay, retries |
|
|
82
|
+
| 24 | `node-cron` | `cron` | Scheduled job execution as task runs |
|
|
83
|
+
|
|
84
|
+
### AI / LLM SDKs
|
|
85
|
+
|
|
86
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
87
|
+
|---|---------|-------------------|-----------------|
|
|
88
|
+
| 25 | `openai` | `openai` | Chat completions, embeddings, images, audio, model, token usage |
|
|
89
|
+
| 26 | `@anthropic-ai/sdk` | `anthropic` | Messages, completions, model, input/output tokens, stop reason |
|
|
90
|
+
| 27 | `@google/generative-ai` | `google-genai` | generateContent, chat, embeddings, countTokens, token usage |
|
|
91
|
+
| 28 | `@google-cloud/vertexai` | `google-genai` | Vertex AI generateContent, generateContentStream |
|
|
92
|
+
| 29 | `@azure/openai` | `azure-openai` | Chat, completions, embeddings, images, audio (v1.x API) |
|
|
93
|
+
| 30 | `cohere-ai` | `cohere` | Chat, embed, rerank, classify, summarize, tokenize |
|
|
94
|
+
| 31 | `@mistralai/mistralai` | `mistral` | Chat, FIM, embeddings, model, token usage |
|
|
95
|
+
|
|
96
|
+
All AI instrumentations follow [OTel GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) (`gen_ai.system`, `gen_ai.request.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.response.finish_reason`).
|
|
97
|
+
|
|
98
|
+
### Cloud & Infrastructure
|
|
99
|
+
|
|
100
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
101
|
+
|---|---------|-------------------|-----------------|
|
|
102
|
+
| 32 | `@aws-sdk/*` (AWS SDK v3) | `aws-sdk` | All AWS service calls (S3, DynamoDB, SQS, SNS, Lambda, etc.), request ID, region, HTTP status |
|
|
103
|
+
| 33 | AWS Bedrock Runtime | `aws-sdk` | Model invocations with GenAI attributes (tokens, model ID, finish reason) |
|
|
104
|
+
| 34 | Firebase Admin (Firestore) | `firebase` | Document CRUD, collection queries, transactions, batch commits |
|
|
105
|
+
| 35 | Firebase Admin (Auth) | `firebase` | User management, token verification, session cookies (16 methods) |
|
|
106
|
+
| 36 | Firebase Admin (FCM) | `firebase` | Push notification delivery, multicast, topic operations (9 methods) |
|
|
107
|
+
|
|
108
|
+
### Logging Libraries
|
|
109
|
+
|
|
110
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
111
|
+
|---|---------|-------------------|-----------------|
|
|
112
|
+
| 37 | `pino` | `pino` | Trace/span ID injection into structured log output |
|
|
113
|
+
| 38 | `winston` | `winston` | Trace/span ID injection into transport output |
|
|
114
|
+
| 39 | `bunyan` | `bunyan` | Trace/span ID injection into log records |
|
|
115
|
+
|
|
116
|
+
### RPC & Network
|
|
117
|
+
|
|
118
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
119
|
+
|---|---------|-------------------|-----------------|
|
|
120
|
+
| 40 | `@grpc/grpc-js` | `grpc` | Unary/streaming calls, service/method, status codes, metadata propagation |
|
|
121
|
+
| 41 | `graphql` | `graphql` | Resolvers, operation name/type, field paths, errors |
|
|
122
|
+
| 42 | Node `dns` | `dns` | DNS lookups, resolve calls, hostname, record types |
|
|
123
|
+
| 43 | Node `net` | `net` | TCP socket connections, data transfer, connection timing |
|
|
124
|
+
|
|
125
|
+
### Utilities
|
|
126
|
+
|
|
127
|
+
| # | Library | Instrumentation Key | What's Captured |
|
|
128
|
+
|---|---------|-------------------|-----------------|
|
|
129
|
+
| 44 | `dataloader` | `dataloader` | Batch load calls, batch size, cache hits |
|
|
130
|
+
| 45 | `lru-memoizer` | `lru-memoizer` | Memoized function calls, cache hit/miss |
|
|
131
|
+
| 46 | `generic-pool` | `generic-pool` | Pool acquire/release, pool size, pending count |
|
|
132
|
+
| 47 | Node `fs` | `fs` | File system reads, writes, stats, directory operations |
|
|
133
|
+
|
|
134
|
+
### Runtime Metrics
|
|
135
|
+
|
|
136
|
+
Collected every 15 seconds (configurable) and sent alongside trace data:
|
|
137
|
+
|
|
138
|
+
- **Event Loop**: lag (p50, p99, max), utilization (ELU)
|
|
139
|
+
- **Garbage Collection**: duration by GC type (minor, major, incremental, weakcb)
|
|
140
|
+
- **Memory**: heap used/total, RSS, external, array buffers
|
|
141
|
+
- **Active Handles & Requests**: open file descriptors, active network connections
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Framework Wrappers
|
|
146
|
+
|
|
147
|
+
### Express
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import Senzor from '@senzops/apm-node';
|
|
151
|
+
|
|
152
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
153
|
+
|
|
154
|
+
const app = express();
|
|
155
|
+
app.use(Senzor.requestHandler()); // First middleware
|
|
156
|
+
app.get('/users/:id', handler);
|
|
157
|
+
app.use(Senzor.errorHandler()); // Last middleware
|
|
158
|
+
app.listen(3000);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Fastify
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import Senzor from '@senzops/apm-node';
|
|
165
|
+
|
|
166
|
+
fastify.register(Senzor.fastifyPlugin, {
|
|
167
|
+
apiKey: process.env.SENZOR_API_KEY!,
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### NestJS
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import Senzor from '@senzops/apm-node';
|
|
175
|
+
|
|
176
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
177
|
+
|
|
178
|
+
async function bootstrap() {
|
|
179
|
+
const app = await NestFactory.create(AppModule);
|
|
180
|
+
app.use(Senzor.requestHandler());
|
|
181
|
+
await app.listen(3000);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Next.js (App Router)
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import Senzor from '@senzops/apm-node';
|
|
189
|
+
|
|
190
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
191
|
+
|
|
192
|
+
export const GET = Senzor.wrapNextRoute(async (req) => {
|
|
193
|
+
return Response.json({ ok: true });
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Next.js (Pages Router)
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import Senzor from '@senzops/apm-node';
|
|
201
|
+
|
|
202
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
203
|
+
|
|
204
|
+
export default Senzor.wrapNextPages(async (req, res) => {
|
|
205
|
+
res.status(200).json({ ok: true });
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### H3 / Nuxt / Nitro
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import Senzor from '@senzops/apm-node';
|
|
213
|
+
|
|
214
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
215
|
+
|
|
216
|
+
export default Senzor.wrapH3(defineEventHandler(async (event) => {
|
|
217
|
+
return { ok: true };
|
|
218
|
+
}));
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Nitro Plugin (Cloudflare Workers)
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { Senzor } from '@senzops/apm-node';
|
|
225
|
+
|
|
226
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
227
|
+
Senzor.init({ apiKey: '<YOUR_APM_KEY>' });
|
|
228
|
+
Senzor.nitroPlugin(nitroApp);
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Cloudflare Workers
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import Senzor from '@senzops/apm-node';
|
|
236
|
+
|
|
237
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
238
|
+
|
|
239
|
+
export default {
|
|
240
|
+
fetch: Senzor.worker(async (request, env, ctx) => {
|
|
241
|
+
return new Response('OK');
|
|
242
|
+
}),
|
|
243
|
+
};
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### AWS Lambda
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import Senzor from '@senzops/apm-node';
|
|
250
|
+
|
|
251
|
+
Senzor.init({ apiKey: process.env.SENZOR_API_KEY! });
|
|
252
|
+
|
|
253
|
+
export const handler = Senzor.wrapLambda(async (event, context) => {
|
|
254
|
+
return { statusCode: 200, body: JSON.stringify({ ok: true }) };
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`wrapLambda` provides:
|
|
259
|
+
- **Cold start detection** tagged on the first invocation per container
|
|
260
|
+
- **Trigger-type detection**: API Gateway v1/v2, ALB, SQS, SNS, DynamoDB Streams, EventBridge, S3, Scheduled events
|
|
261
|
+
- **Lambda context extraction**: function name, request ID, memory limit, log group, invoked ARN, region, account ID
|
|
262
|
+
- **Forced flush** before each invocation returns (Lambda freezes the process immediately after)
|
|
263
|
+
- **Lambda Extensions API** registration for SHUTDOWN lifecycle safety-net flush
|
|
264
|
+
|
|
265
|
+
#### Lambda Layer Deployment (No Code Changes)
|
|
266
|
+
|
|
267
|
+
```sh
|
|
268
|
+
# Set environment variables on your Lambda function
|
|
269
|
+
SENZOR_API_KEY=sz_apm_xxx
|
|
270
|
+
NODE_OPTIONS=--require @senzops/apm-node/register
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
When running inside Lambda, the SDK auto-detects the environment and optimizes:
|
|
274
|
+
- Runtime metrics are disabled (meaningless per-invocation)
|
|
275
|
+
- Batch size reduced to 10
|
|
276
|
+
- Flush interval set to 0 (flush only on demand)
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Background Task Monitoring
|
|
281
|
+
|
|
282
|
+
### Auto-Instrumented Tasks
|
|
283
|
+
|
|
284
|
+
BullMQ workers and node-cron jobs are captured automatically as task runs with queue delay, retry count, dead-letter detection, and CPU/memory resource metrics.
|
|
285
|
+
|
|
286
|
+
### Manual Task Wrapping
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
const processPayment = Senzor.wrapTask(
|
|
290
|
+
'process_payment',
|
|
291
|
+
'custom',
|
|
292
|
+
{ metadata: { owner: 'billing' } },
|
|
293
|
+
async (invoiceId: string) => {
|
|
294
|
+
await chargeCustomer(invoiceId);
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
await processPayment('inv_123');
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Manual Spans
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const span = Senzor.startSpan('calculate_invoice', 'function');
|
|
307
|
+
try {
|
|
308
|
+
const total = await calculateInvoice(invoiceId);
|
|
309
|
+
span.end({ invoiceId, total }, 200);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
span.end({ invoiceId, error: String(error) }, 500);
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Span types: `http`, `db`, `function`, `custom`, `rpc`, `messaging`, `dns`, `net`.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Error Tracking
|
|
321
|
+
|
|
322
|
+
Automatic capture of `uncaughtException`, `unhandledRejection`, process warnings, `SIGTERM`, and `SIGINT` with full stack traces, process context, and memory snapshots.
|
|
323
|
+
|
|
324
|
+
Manual capture:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
Senzor.captureException(error, { userId, operation: 'charge' });
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Log Correlation
|
|
333
|
+
|
|
334
|
+
Console logs (`log`, `info`, `warn`, `error`, `debug`) are automatically captured and correlated with the active trace or task context. Structured logging libraries (pino, winston, bunyan) get trace/span IDs injected for correlation.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Configuration
|
|
339
|
+
|
|
340
|
+
| Option | Type | Default | Description |
|
|
341
|
+
|--------|------|---------|-------------|
|
|
342
|
+
| `apiKey` | `string` | **required** | Senzor service API key |
|
|
343
|
+
| `endpoint` | `string` | `https://api.senzor.dev` | Ingest endpoint |
|
|
344
|
+
| `batchSize` | `number` | `100` | Flush threshold |
|
|
345
|
+
| `flushInterval` | `number` | `10000` | Flush interval (ms) |
|
|
346
|
+
| `flushTimeoutMs` | `number` | `5000` | Per-request timeout (ms) |
|
|
347
|
+
| `maxQueueSize` | `number` | `10000` | Max queued items before drop |
|
|
348
|
+
| `maxSpansPerTrace` | `number` | `500` | Max child spans per trace |
|
|
349
|
+
| `maxAttributeLength` | `number` | `2048` | Max string length for attributes |
|
|
350
|
+
| `maxAttributes` | `number` | `64` | Max attributes per object |
|
|
351
|
+
| `captureHeaders` | `boolean` | `false` | Capture sanitized request headers |
|
|
352
|
+
| `captureDbStatement` | `boolean` | `true` | Capture sanitized SQL in spans |
|
|
353
|
+
| `instrumentations` | `boolean \| string[]` | `true` | Enable/disable specific instrumentations |
|
|
354
|
+
| `frameworkSpans` | `boolean` | `true` | Capture framework middleware/router spans |
|
|
355
|
+
| `captureMiddlewareSpans` | `boolean` | `true` | Capture middleware execution spans |
|
|
356
|
+
| `captureRouterSpans` | `boolean` | `true` | Capture router dispatch spans |
|
|
357
|
+
| `captureLifecycleHookSpans` | `boolean` | `true` | Capture framework lifecycle hook spans |
|
|
358
|
+
| `autoLogs` | `boolean` | `true` | Capture and correlate console logs |
|
|
359
|
+
| `runtimeMetrics` | `boolean` | `true` | Collect runtime metrics (event loop, GC, heap) |
|
|
360
|
+
| `runtimeMetricsInterval` | `number` | `15000` | Runtime metrics collection interval (ms) |
|
|
361
|
+
| `debug` | `boolean` | `false` | Print SDK diagnostics |
|
|
362
|
+
|
|
363
|
+
### Selective Instrumentation
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
// Enable only specific instrumentations
|
|
367
|
+
Senzor.init({
|
|
368
|
+
apiKey: process.env.SENZOR_API_KEY!,
|
|
369
|
+
instrumentations: ['http', 'fetch', 'pg', 'redis', 'openai'],
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// Disable all auto-instrumentation (manual APIs only)
|
|
373
|
+
Senzor.init({
|
|
374
|
+
apiKey: process.env.SENZOR_API_KEY!,
|
|
375
|
+
instrumentations: false,
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
All instrumentation key names:
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
http, fetch, undici, express, fastify, koa, nestjs, hapi, restify, connect,
|
|
383
|
+
pg, mongo, mongoose, mysql, redis, knex, tedious, cassandra, memcached,
|
|
384
|
+
kafka, amqplib, socketio, bullmq, cron,
|
|
385
|
+
openai, anthropic, google-genai, azure-openai, cohere, mistral,
|
|
386
|
+
aws-sdk, firebase,
|
|
387
|
+
pino, winston, bunyan,
|
|
388
|
+
grpc, graphql, dns, net,
|
|
389
|
+
dataloader, lru-memoizer, generic-pool, fs
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Environment Variables
|
|
395
|
+
|
|
396
|
+
| Variable | Description |
|
|
397
|
+
|----------|-------------|
|
|
398
|
+
| `SENZOR_API_KEY` | Service API key |
|
|
399
|
+
| `SENZOR_ENDPOINT` | Ingest endpoint |
|
|
400
|
+
| `SENZOR_DEBUG` | `true` / `1` to enable diagnostics |
|
|
401
|
+
| `SENZOR_AUTO_LOGS` | `false` to disable log capture |
|
|
402
|
+
| `SENZOR_BATCH_SIZE` | Batch size |
|
|
403
|
+
| `SENZOR_FLUSH_INTERVAL` | Flush interval (ms) |
|
|
404
|
+
| `SENZOR_FLUSH_TIMEOUT_MS` | Flush timeout (ms) |
|
|
405
|
+
| `SENZOR_MAX_QUEUE_SIZE` | Max queued items |
|
|
406
|
+
| `SENZOR_MAX_SPANS_PER_TRACE` | Max spans per trace |
|
|
407
|
+
| `SENZOR_CAPTURE_HEADERS` | `true` to capture headers |
|
|
408
|
+
| `SENZOR_CAPTURE_DB_STATEMENT` | `false` for restrictive SQL |
|
|
409
|
+
| `SENZOR_FRAMEWORK_SPANS` | `false` to disable framework spans |
|
|
410
|
+
| `SENZOR_CAPTURE_MIDDLEWARE_SPANS` | `false` to disable middleware spans |
|
|
411
|
+
| `SENZOR_CAPTURE_ROUTER_SPANS` | `false` to disable router spans |
|
|
412
|
+
| `SENZOR_CAPTURE_LIFECYCLE_HOOK_SPANS` | `false` to disable lifecycle spans |
|
|
413
|
+
| `SENZOR_RUNTIME_METRICS` | `false` to disable runtime metrics |
|
|
414
|
+
| `SENZOR_RUNTIME_METRICS_INTERVAL` | Collection interval (ms) |
|
|
415
|
+
|
|
416
|
+
Alternative API key variables: `SENZOR_APM_API_KEY`, `SENZOR_SERVICE_API_KEY`.
|
|
417
|
+
Alternative endpoint variables: `SENZOR_APM_ENDPOINT`.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Distributed Tracing
|
|
422
|
+
|
|
423
|
+
The SDK automatically propagates trace context on outgoing HTTP calls:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
traceparent: 00-{traceId}-{spanId}-01
|
|
427
|
+
x-senzor-trace-id: {traceId}
|
|
428
|
+
x-senzor-parent-span-id: {spanId}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Incoming `traceparent` headers are parsed to link upstream traces.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Security Defaults
|
|
436
|
+
|
|
437
|
+
Sensitive fields are automatically redacted from attributes, headers, logs, and error context:
|
|
438
|
+
|
|
439
|
+
`authorization`, `cookie`, `set-cookie`, `password`, `secret`, `token`, `apiKey`, `x-api-key`, `accessToken`, `refreshToken`, `clientSecret`, `privateKey`
|
|
440
|
+
|
|
441
|
+
Header capture is disabled by default. SQL statements are normalized to strip literal values.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Public API Reference
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
Senzor.init(options) // Initialize SDK
|
|
449
|
+
Senzor.preload(options) // Preload instrumentation hooks
|
|
450
|
+
Senzor.flush() // Force flush queued telemetry
|
|
451
|
+
Senzor.track(data) // Send a manual trace
|
|
452
|
+
Senzor.startSpan(name, type) // Start a manual span
|
|
453
|
+
Senzor.captureException(error, ctx) // Capture an error
|
|
454
|
+
|
|
455
|
+
Senzor.wrapTask(name, type, opts, fn) // Wrap a function as a task
|
|
456
|
+
Senzor.startTask(name, type, opts, fn) // Start a task context
|
|
457
|
+
|
|
458
|
+
Senzor.requestHandler() // Express request middleware
|
|
459
|
+
Senzor.errorHandler() // Express error middleware
|
|
460
|
+
Senzor.fastifyPlugin // Fastify plugin
|
|
461
|
+
Senzor.wrapNextRoute(handler) // Next.js App Router wrapper
|
|
462
|
+
Senzor.wrapNextPages(handler) // Next.js Pages Router wrapper
|
|
463
|
+
Senzor.wrapH3(handler) // H3/Nuxt/Nitro wrapper
|
|
464
|
+
Senzor.nitroPlugin // Nitro plugin (Cloudflare Workers)
|
|
465
|
+
Senzor.worker(handler) // Cloudflare Workers wrapper
|
|
466
|
+
Senzor.wrapLambda(handler) // AWS Lambda wrapper
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Requirements
|
|
472
|
+
|
|
473
|
+
- Node.js >= 18.0.0 (or Bun >= 1.0.0)
|
|
474
|
+
- A Senzor service API key
|
|
475
|
+
- Network access to the Senzor ingest endpoint
|
|
476
|
+
|
|
477
|
+
## License
|
|
478
|
+
|
|
479
|
+
MIT
|