@senzops/apm-node 1.2.4 → 1.2.6

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/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@senzops/apm-node",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "Universal APM SDK for Senzor",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
8
8
  ".": {
9
9
  "types": "./dist/index.d.ts",
10
+ "worker": "./dist/index.mjs",
10
11
  "require": "./dist/index.js",
11
12
  "import": "./dist/index.mjs"
12
13
  },
@@ -26,7 +27,8 @@
26
27
  "typescript": "^5.0.0"
27
28
  },
28
29
  "engines": {
29
- "node": ">=18.0.0"
30
+ "node": ">=18.0.0",
31
+ "bun": ">=1.0.0"
30
32
  },
31
33
  "keywords": [
32
34
  "apm",
@@ -35,7 +37,10 @@
35
37
  "node",
36
38
  "javascript",
37
39
  "api",
38
- "observability"
40
+ "observability",
41
+ "cloudflare-workers",
42
+ "edge",
43
+ "universal"
39
44
  ],
40
45
  "author": "Senzops",
41
46
  "license": "MIT"
@@ -1,19 +1,7 @@
1
1
  import { Transport } from './transport';
2
2
  import { Context } from './context';
3
3
  import { SenzorOptions, ActiveTrace, TaskRun, SenzorLog } from './types';
4
- import { randomUUID } from 'crypto';
5
- import { instrumentHttp, instrumentFetch } from '../instrumentation/http';
6
- import { instrumentExpress } from '../instrumentation/express';
7
- import { instrumentFastify } from '../instrumentation/fastify';
8
- import { instrumentKoa } from '../instrumentation/koa';
9
- import { instrumentMongo } from '../instrumentation/mongo';
10
- import { instrumentPg } from '../instrumentation/pg';
11
- import { instrumentUndici } from '../instrumentation/undici';
12
- import { instrumentRedis } from '../instrumentation/redis';
13
- import { instrumentMysql } from '../instrumentation/mysql';
14
- import { instrumentMongoose } from '../instrumentation/mongoose';
15
- import { instrumentBullMQ } from '../instrumentation/bullmq';
16
- import { instrumentNodeCron } from '../instrumentation/cron';
4
+ import { isNode } from './runtime';
17
5
  import { SDK_META } from '../utils/sdkMeta';
18
6
  import { parseTraceparent } from '../utils/traceContext';
19
7
  import { generateSpanId, generateTraceId } from '../utils/ids';
@@ -72,29 +60,37 @@ export class SenzorClient {
72
60
  }
73
61
 
74
62
  private installNativeInstrumentations(endpoint: string, debug: boolean) {
75
- if (!this.isInstrumented) {
76
- this.setupGlobalErrorHandlers();
77
- this.setupLogInterception(); // Fire up Auto Log Instrumentation
78
-
79
- try { if (this.isInstrumentationEnabled('http')) instrumentHttp(this, endpoint, this.options || undefined); } catch (e) { }
80
- try { if (this.isInstrumentationEnabled('express')) instrumentExpress(this.options || undefined); } catch (e) { }
81
- try { if (this.isInstrumentationEnabled('fastify')) instrumentFastify(this.options || undefined); } catch (e) { }
82
- try { if (this.isInstrumentationEnabled('koa')) instrumentKoa(this.options || undefined); } catch (e) { }
83
- try { if (this.isInstrumentationEnabled('fetch')) instrumentFetch(endpoint, this.options || undefined); } catch (e) { }
84
- try { if (this.isInstrumentationEnabled('undici')) instrumentUndici(this.options || undefined); } catch (e) { }
85
- try { if (this.isInstrumentationEnabled('mongo')) instrumentMongo(this.options || undefined); } catch (e) { }
86
- try { if (this.isInstrumentationEnabled('mongoose')) instrumentMongoose(this.options || undefined); } catch (e) { }
87
- try { if (this.isInstrumentationEnabled('pg')) instrumentPg(this.options || undefined); } catch (e) { }
88
- try { if (this.isInstrumentationEnabled('mysql')) instrumentMysql(this.options || undefined); } catch (e) { }
89
- try { if (this.isInstrumentationEnabled('redis')) instrumentRedis(this.options || undefined); } catch (e) { }
90
-
91
- // Task Integrations
92
- try { if (this.isInstrumentationEnabled('bullmq')) instrumentBullMQ(this, debug); } catch (e) { }
93
- try { if (this.isInstrumentationEnabled('cron')) instrumentNodeCron(this, debug); } catch (e) { }
94
-
95
- this.isInstrumented = true;
96
- if (debug) console.log('[Senzor] Auto-instrumentation enabled');
63
+ if (this.isInstrumented) return;
64
+
65
+ this.setupGlobalErrorHandlers();
66
+ this.setupLogInterception();
67
+
68
+ // Fetch instrumentation works on all runtimes (Workers, Node, Bun, Deno)
69
+ try {
70
+ if (this.isInstrumentationEnabled('fetch')) {
71
+ const { instrumentFetch } = require('../instrumentation/http');
72
+ instrumentFetch(endpoint, this.options || undefined);
73
+ }
74
+ } catch {}
75
+
76
+ // Node-only instrumentations: http, module hooking, db drivers, etc.
77
+ if (isNode()) {
78
+ try { if (this.isInstrumentationEnabled('http')) { const { instrumentHttp } = require('../instrumentation/http'); instrumentHttp(this, endpoint, this.options || undefined); } } catch {}
79
+ try { if (this.isInstrumentationEnabled('express')) { const { instrumentExpress } = require('../instrumentation/express'); instrumentExpress(this.options || undefined); } } catch {}
80
+ try { if (this.isInstrumentationEnabled('fastify')) { const { instrumentFastify } = require('../instrumentation/fastify'); instrumentFastify(this.options || undefined); } } catch {}
81
+ try { if (this.isInstrumentationEnabled('koa')) { const { instrumentKoa } = require('../instrumentation/koa'); instrumentKoa(this.options || undefined); } } catch {}
82
+ try { if (this.isInstrumentationEnabled('undici')) { const { instrumentUndici } = require('../instrumentation/undici'); instrumentUndici(this.options || undefined); } } catch {}
83
+ try { if (this.isInstrumentationEnabled('mongo')) { const { instrumentMongo } = require('../instrumentation/mongo'); instrumentMongo(this.options || undefined); } } catch {}
84
+ try { if (this.isInstrumentationEnabled('mongoose')) { const { instrumentMongoose } = require('../instrumentation/mongoose'); instrumentMongoose(this.options || undefined); } } catch {}
85
+ try { if (this.isInstrumentationEnabled('pg')) { const { instrumentPg } = require('../instrumentation/pg'); instrumentPg(this.options || undefined); } } catch {}
86
+ try { if (this.isInstrumentationEnabled('mysql')) { const { instrumentMysql } = require('../instrumentation/mysql'); instrumentMysql(this.options || undefined); } } catch {}
87
+ try { if (this.isInstrumentationEnabled('redis')) { const { instrumentRedis } = require('../instrumentation/redis'); instrumentRedis(this.options || undefined); } } catch {}
88
+ try { if (this.isInstrumentationEnabled('bullmq')) { const { instrumentBullMQ } = require('../instrumentation/bullmq'); instrumentBullMQ(this, debug); } } catch {}
89
+ try { if (this.isInstrumentationEnabled('cron')) { const { instrumentNodeCron } = require('../instrumentation/cron'); instrumentNodeCron(this, debug); } } catch {}
97
90
  }
91
+
92
+ this.isInstrumented = true;
93
+ if (debug) console.log('[Senzor] Auto-instrumentation enabled');
98
94
  }
99
95
 
100
96
  // --- Enterprise Auto-Log Interception ---
@@ -177,6 +173,8 @@ export class SenzorClient {
177
173
  }
178
174
 
179
175
  private setupGlobalErrorHandlers() {
176
+ if (!isNode()) return;
177
+
180
178
  if ((process as any).__senzorGlobalHandlersInstalled) {
181
179
  return;
182
180
  }
@@ -338,11 +336,11 @@ export class SenzorClient {
338
336
  const currentContext = Context.current();
339
337
  const triggerTraceId = currentContext?.contextType === 'apm' ? currentContext.id : undefined;
340
338
 
341
- const startMemory = process.memoryUsage ? process.memoryUsage().heapUsed : 0;
342
- const startCpu = process.cpuUsage ? process.cpuUsage() : undefined;
339
+ const startMemory = isNode() && process.memoryUsage ? process.memoryUsage().heapUsed : 0;
340
+ const startCpu = isNode() && process.cpuUsage ? process.cpuUsage() : undefined;
343
341
 
344
342
  const task: ActiveTrace = {
345
- id: randomUUID(),
343
+ id: generateTraceId(),
346
344
  contextType: 'task',
347
345
  startTime: performance.now(),
348
346
  rootSpanId: generateSpanId(),
@@ -367,7 +365,7 @@ export class SenzorClient {
367
365
  task.state.ended = true;
368
366
 
369
367
  let resourceMetrics;
370
- if (process.memoryUsage && task.startMemory !== undefined && process.cpuUsage && task.startCpu) {
368
+ if (isNode() && process.memoryUsage && task.startMemory !== undefined && process.cpuUsage && task.startCpu) {
371
369
  const endMemory = process.memoryUsage().heapUsed;
372
370
  const cpuDelta = process.cpuUsage(task.startCpu);
373
371
 
@@ -1,7 +1,51 @@
1
- import { AsyncLocalStorage } from 'async_hooks';
2
1
  import { ActiveTrace, Span } from './types';
3
2
 
4
- export const storage = new AsyncLocalStorage<ActiveTrace>();
3
+ interface IStorage<T> {
4
+ run<R>(store: T, callback: (...args: any[]) => R, ...args: any[]): R;
5
+ getStore(): T | undefined;
6
+ }
7
+
8
+ class NaiveStorage<T> implements IStorage<T> {
9
+ private store: T | undefined;
10
+
11
+ run<R>(store: T, callback: (...args: any[]) => R, ...args: any[]): R {
12
+ const prev = this.store;
13
+ this.store = store;
14
+ try {
15
+ return callback(...args);
16
+ } finally {
17
+ this.store = prev;
18
+ }
19
+ }
20
+
21
+ getStore(): T | undefined {
22
+ return this.store;
23
+ }
24
+ }
25
+
26
+ const resolveStorage = <T>(): IStorage<T> => {
27
+ if (typeof globalThis !== 'undefined' && (globalThis as any).AsyncLocalStorage) {
28
+ return new (globalThis as any).AsyncLocalStorage();
29
+ }
30
+
31
+ try {
32
+ if (typeof require !== 'undefined') {
33
+ const { AsyncLocalStorage } = require('node:async_hooks');
34
+ if (AsyncLocalStorage) return new AsyncLocalStorage();
35
+ }
36
+ } catch {}
37
+
38
+ try {
39
+ if (typeof require !== 'undefined') {
40
+ const { AsyncLocalStorage } = require('async_hooks');
41
+ if (AsyncLocalStorage) return new AsyncLocalStorage();
42
+ }
43
+ } catch {}
44
+
45
+ return new NaiveStorage<T>();
46
+ };
47
+
48
+ export const storage = resolveStorage<ActiveTrace>();
5
49
 
6
50
  export const Context = {
7
51
  run: <T>(trace: ActiveTrace, fn: () => T): T => {
@@ -0,0 +1,15 @@
1
+ const _isNode = typeof process !== 'undefined' &&
2
+ typeof process.versions !== 'undefined' &&
3
+ typeof process.versions.node !== 'undefined';
4
+
5
+ export const isNode = (): boolean => _isNode;
6
+
7
+ export const isEdgeRuntime = (): boolean =>
8
+ typeof navigator !== 'undefined' &&
9
+ typeof navigator.userAgent === 'string' &&
10
+ navigator.userAgent.includes('Cloudflare');
11
+
12
+ export const getEnv = (key: string): string | undefined => {
13
+ if (_isNode) return process.env[key];
14
+ return undefined;
15
+ };
@@ -255,6 +255,8 @@ export class Transport {
255
255
  }
256
256
 
257
257
  private installShutdownFlush() {
258
+ if (typeof process === 'undefined' || typeof process.once !== 'function') return;
259
+
258
260
  const key = Symbol.for('senzor.transport.shutdownFlushInstalled');
259
261
  const proc = process as unknown as Record<symbol, boolean>;
260
262
  if (proc[key]) return;
package/src/index.ts CHANGED
@@ -2,18 +2,20 @@ import { client } from './core/client';
2
2
  import { expressMiddleware, expressErrorHandler } from './middleware/express';
3
3
  import { wrapH3 } from './wrappers/h3';
4
4
  import { wrapNextRoute, wrapNextPages } from './wrappers/next';
5
+ import { wrapWorker } from './wrappers/worker';
6
+ import { nitroPlugin } from './wrappers/nitro';
5
7
  import { senzorPlugin } from './wrappers/fastify';
6
8
  import { SenzorOptions } from './core/types';
7
9
 
8
- const Senzor = {
9
- preload: (options: Partial<SenzorOptions> = {}) => client.preload(options),
10
- init: (options: SenzorOptions) => client.init(options),
11
- flush: () => client.flush(),
10
+ const Senzor = {
11
+ preload: (options: Partial<SenzorOptions> = {}) => client.preload(options),
12
+ init: (options: SenzorOptions) => client.init(options),
13
+ flush: () => client.flush(),
12
14
  track: client.track.bind(client),
13
15
  startSpan: client.startSpan.bind(client),
14
16
  captureException: client.captureError.bind(client),
15
17
 
16
- // Task Monitoring (NEW)
18
+ // Task Monitoring
17
19
  wrapTask: client.wrapTask.bind(client),
18
20
  startTask: client.startTask.bind(client),
19
21
 
@@ -29,8 +31,14 @@ const Senzor = {
29
31
  wrapH3,
30
32
 
31
33
  // Fastify
32
- fastifyPlugin: senzorPlugin
34
+ fastifyPlugin: senzorPlugin,
35
+
36
+ // Cloudflare Workers
37
+ worker: wrapWorker,
38
+
39
+ // Nitro / Nuxt
40
+ nitroPlugin
33
41
  };
34
42
 
35
43
  export default Senzor;
36
- export { Senzor };
44
+ export { Senzor };
@@ -57,18 +57,24 @@ const getRequestRoute = (
57
57
  layer: any,
58
58
  layerPath?: string
59
59
  ): string | undefined => {
60
- const routePath = stringifyPath(layer?.route?.path);
61
- if (routePath) {
60
+ if (layer?.route?.path) {
61
+ const routePath = stringifyPath(layer.route.path);
62
62
  const baseUrl = req?.baseUrl || '';
63
+ // If baseUrl already ends with or contains the routePath, be careful
63
64
  return `${baseUrl}${routePath}` || routePath;
64
65
  }
65
66
 
66
67
  if (req?.route?.path) {
67
- return `${req.baseUrl || ''}${req.route.path}`;
68
+ const baseUrl = req?.baseUrl || '';
69
+ return `${baseUrl}${req.route.path}`;
68
70
  }
69
71
 
70
72
  if (layerPath) {
71
73
  const baseUrl = req?.baseUrl || '';
74
+ // If baseUrl already contains layerPath, don't double it
75
+ if (baseUrl === layerPath || baseUrl.endsWith(layerPath)) {
76
+ return baseUrl;
77
+ }
72
78
  return `${baseUrl}${layerPath}` || layerPath;
73
79
  }
74
80
 
@@ -84,9 +90,14 @@ const getLayerType = (
84
90
  if (forcedType) return forcedType;
85
91
  if (original.length === 4) return 'error_handler' as const;
86
92
  if (layer?.route) return 'request_handler' as const;
87
- if (layer?.name === 'router' || layer?.handle?.stack || layer?.handle?.name === 'router') {
88
- return 'router' as const;
89
- }
93
+
94
+ const isRouter =
95
+ layer?.name === 'router' ||
96
+ layer?.handle?.name === 'router' ||
97
+ typeof layer?.handle?.stack !== 'undefined' ||
98
+ typeof layer?.handle?.route === 'function';
99
+
100
+ if (isRouter) return 'router' as const;
90
101
  return 'middleware' as const;
91
102
  };
92
103
 
@@ -105,6 +116,7 @@ const copyEnumerableProperties = (
105
116
  source: Function,
106
117
  target: Function
107
118
  ) => {
119
+ // Copy enumerable properties
108
120
  for (const key in source as any) {
109
121
  try {
110
122
  Object.defineProperty(target, key, {
@@ -119,6 +131,13 @@ const copyEnumerableProperties = (
119
131
  });
120
132
  } catch { }
121
133
  }
134
+
135
+ // Ensure 'stack' is copied even if not enumerable (though it usually is)
136
+ if ((source as any).stack && !(target as any).stack) {
137
+ try {
138
+ (target as any).stack = (source as any).stack;
139
+ } catch { }
140
+ }
122
141
  };
123
142
 
124
143
  const patchLayer = (
@@ -145,7 +164,7 @@ const patchLayer = (
145
164
  const handlerName =
146
165
  original.name ||
147
166
  layer.name ||
148
- layerType;
167
+ (layerType === 'request_handler' ? 'handler' : layerType);
149
168
 
150
169
  if (original.length === 4) {
151
170
  const wrapped = function senzorExpressErrorHandler(
@@ -264,7 +283,7 @@ const patchRouteMethodHandlers = (
264
283
  const stack = this?.stack || [];
265
284
 
266
285
  for (const layer of stack) {
267
- patchLayer(layer, routePath, options, 'request_handler');
286
+ patchLayer(layer, routePath, options, 'request_handler');
268
287
  }
269
288
 
270
289
  return result;
@@ -277,10 +296,13 @@ const getSafeRouter = (app: any) => {
277
296
  if (!app) return undefined;
278
297
  if (app._router) return app._router;
279
298
  try {
280
- return app.router;
281
- } catch {
282
- return undefined;
283
- }
299
+ // In Express 4, app.router is a getter that throws.
300
+ // We only want it if it's not a throwing getter (Express 3)
301
+ // or if it actually has a stack.
302
+ const r = app.router;
303
+ if (r && (r.stack || typeof r === 'function')) return r;
304
+ } catch { }
305
+ return undefined;
284
306
  };
285
307
 
286
308
  const patchExpress = (
@@ -290,7 +312,7 @@ const patchExpress = (
290
312
  if (!expressModule) return;
291
313
 
292
314
  const routerProto =
293
- typeof expressModule?.Router?.prototype?.route === 'function'
315
+ typeof expressModule?.Router?.prototype?.use === 'function'
294
316
  ? expressModule.Router.prototype
295
317
  : expressModule.Router;
296
318
 
@@ -302,8 +324,9 @@ const patchExpress = (
302
324
  function patchedExpressRoute(this: any, ...args: any[]) {
303
325
  const route = original.apply(this, args);
304
326
  const routePath = getLayerPath(args);
305
- const layer = this?.stack?.[this.stack.length - 1];
327
+ const stack = this?.stack || [];
306
328
 
329
+ const layer = stack[stack.length - 1];
307
330
  patchLayer(layer, routePath, options, 'router');
308
331
  patchRouteMethodHandlers(route, routePath, options);
309
332
 
@@ -317,9 +340,13 @@ const patchExpress = (
317
340
  'senzor.express.router.use',
318
341
  (original) =>
319
342
  function patchedExpressRouterUse(this: any, ...args: any[]) {
343
+ const prevStackLength = this?.stack?.length || 0;
320
344
  const result = original.apply(this, args);
321
- const layer = this?.stack?.[this.stack.length - 1];
322
- patchLayer(layer, getLayerPath(args), options);
345
+ const stack = this?.stack || [];
346
+
347
+ for (let i = prevStackLength; i < stack.length; i++) {
348
+ patchLayer(stack[i], getLayerPath(args), options);
349
+ }
323
350
  return result;
324
351
  }
325
352
  );
@@ -330,11 +357,17 @@ const patchExpress = (
330
357
  'senzor.express.application.use',
331
358
  (original) =>
332
359
  function patchedExpressApplicationUse(this: any, ...args: any[]) {
333
- const router = getSafeRouter(this);
360
+ const routerBefore = getSafeRouter(this);
361
+ const prevStackLength = routerBefore?.stack?.length || 0;
362
+
334
363
  const result = original.apply(this, args);
335
- const activeRouter = getSafeRouter(this) || router;
336
- const layer = activeRouter?.stack?.[activeRouter.stack.length - 1];
337
- patchLayer(layer, getLayerPath(args), options);
364
+
365
+ const routerAfter = getSafeRouter(this);
366
+ const stack = routerAfter?.stack || [];
367
+
368
+ for (let i = prevStackLength; i < stack.length; i++) {
369
+ patchLayer(stack[i], getLayerPath(args), options);
370
+ }
338
371
  return result;
339
372
  }
340
373
  );
@@ -1,18 +1,20 @@
1
- import Module from 'module';
2
-
3
- const SENZOR_PATCHED = Symbol.for('senzor.require.patched');
4
- const SENZOR_HOOKS = Symbol.for('senzor.require.hooks');
5
-
6
1
  type HookFn = (exports: unknown) => unknown | void;
7
2
  type HookMap = Map<string, HookFn[]>;
8
3
 
9
- // Module.createRequire works in both CJS and ESM contexts,
10
- // unlike bare `require` which is unavailable in ESM builds.
11
- const safeRequire: NodeRequire = Module.createRequire(
12
- typeof __filename !== 'undefined'
13
- ? __filename
14
- : process.cwd() + '/'
15
- );
4
+ let Module: any;
5
+ let safeRequire: NodeRequire;
6
+
7
+ try {
8
+ Module = require('module');
9
+ safeRequire = Module.createRequire(
10
+ typeof __filename !== 'undefined'
11
+ ? __filename
12
+ : process.cwd() + '/'
13
+ );
14
+ } catch {}
15
+
16
+ const SENZOR_PATCHED = Symbol.for('senzor.require.patched');
17
+ const SENZOR_HOOKS = Symbol.for('senzor.require.hooks');
16
18
 
17
19
  function getHookRegistry(): HookMap {
18
20
  const mod = Module as unknown as Record<symbol, HookMap>;
@@ -119,6 +121,8 @@ function retryPatch(moduleName: string, hook: HookFn) {
119
121
  }
120
122
 
121
123
  export const hookRequire = (moduleName: string, onRequire: HookFn) => {
124
+ if (!Module || !safeRequire) return;
125
+
122
126
  const registry = getHookRegistry();
123
127
 
124
128
  if (!registry.has(moduleName)) {
@@ -1,6 +1,3 @@
1
- import http from 'http';
2
- import https from 'https';
3
- import { URL } from 'url';
4
1
  import type { SenzorClient } from '../core/client';
5
2
  import { Context } from '../core/context';
6
3
  import { getRoute, normalizePath } from '../core/normalizer';
@@ -299,7 +296,7 @@ const patchIncomingServer = (
299
296
  };
300
297
 
301
298
  const patchOutgoing = (
302
- moduleRef: typeof http | typeof https,
299
+ moduleRef: any,
303
300
  protocol: 'http:' | 'https:',
304
301
  ingestUrl: string,
305
302
  options?: SenzorOptions
@@ -522,9 +519,19 @@ export const instrumentHttp = (
522
519
  ingestUrl: string,
523
520
  options?: SenzorOptions
524
521
  ) => {
525
- patchIncomingServer(http.Server?.prototype, 'http', client, options);
526
- patchIncomingServer(https.Server?.prototype, 'https', client, options);
522
+ let httpMod: any;
523
+ let httpsMod: any;
527
524
 
528
- patchOutgoing(http, 'http:', ingestUrl, options);
529
- patchOutgoing(https, 'https:', ingestUrl, options);
525
+ try { httpMod = require('http'); } catch { return; }
526
+ try { httpsMod = require('https'); } catch {}
527
+
528
+ if (httpMod?.Server?.prototype) {
529
+ patchIncomingServer(httpMod.Server.prototype, 'http', client, options);
530
+ }
531
+ if (httpsMod?.Server?.prototype) {
532
+ patchIncomingServer(httpsMod.Server.prototype, 'https', client, options);
533
+ }
534
+
535
+ patchOutgoing(httpMod, 'http:', ingestUrl, options);
536
+ if (httpsMod) patchOutgoing(httpsMod, 'https:', ingestUrl, options);
530
537
  };
@@ -3,7 +3,7 @@ import { getClientIp } from '../utils/getClientIp';
3
3
 
4
4
  // 1. Request Handler (Place before routes)
5
5
  export const expressMiddleware = () => {
6
- return (req: any, res: any, next: () => void) => {
6
+ return function senzorMiddleware(req: any, res: any, next: () => void) {
7
7
  client.startTrace({
8
8
  method: req.method,
9
9
  path: req.originalUrl || req.url,
@@ -37,7 +37,7 @@ export const expressMiddleware = () => {
37
37
  // 2. Error Handler (Place after routes)
38
38
  // This is required in Express to capture the actual Error Object (Stack Trace)
39
39
  export const expressErrorHandler = () => {
40
- return (err: any, req: any, res: any, next: (err?: any) => void) => {
40
+ return function senzorErrorHandler(err: any, req: any, res: any, next: (err?: any) => void) {
41
41
 
42
42
  // 1. Capture the exception context
43
43
  client.captureError(err);
package/src/register.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { client } from './core/client';
2
+ import { getEnv } from './core/runtime';
2
3
 
3
4
  const truthy = (value: string | undefined): boolean =>
4
5
  value === '1' || value === 'true' || value === 'yes';
@@ -10,43 +11,43 @@ const numberFromEnv = (value: string | undefined): number | undefined => {
10
11
  };
11
12
 
12
13
  const apiKey =
13
- process.env.SENZOR_API_KEY ||
14
- process.env.SENZOR_APM_API_KEY ||
15
- process.env.SENZOR_SERVICE_API_KEY;
14
+ getEnv('SENZOR_API_KEY') ||
15
+ getEnv('SENZOR_APM_API_KEY') ||
16
+ getEnv('SENZOR_SERVICE_API_KEY');
16
17
 
17
18
  const endpoint =
18
- process.env.SENZOR_ENDPOINT ||
19
- process.env.SENZOR_APM_ENDPOINT;
19
+ getEnv('SENZOR_ENDPOINT') ||
20
+ getEnv('SENZOR_APM_ENDPOINT');
20
21
 
21
22
  const options = {
22
23
  apiKey: apiKey || '',
23
24
  endpoint,
24
- debug: truthy(process.env.SENZOR_DEBUG),
25
- autoLogs: process.env.SENZOR_AUTO_LOGS === 'false' ? false : undefined,
26
- batchSize: numberFromEnv(process.env.SENZOR_BATCH_SIZE),
27
- flushInterval: numberFromEnv(process.env.SENZOR_FLUSH_INTERVAL),
28
- flushTimeoutMs: numberFromEnv(process.env.SENZOR_FLUSH_TIMEOUT_MS),
29
- maxQueueSize: numberFromEnv(process.env.SENZOR_MAX_QUEUE_SIZE),
30
- maxSpansPerTrace: numberFromEnv(process.env.SENZOR_MAX_SPANS_PER_TRACE),
31
- captureHeaders: truthy(process.env.SENZOR_CAPTURE_HEADERS),
25
+ debug: truthy(getEnv('SENZOR_DEBUG')),
26
+ autoLogs: getEnv('SENZOR_AUTO_LOGS') === 'false' ? false : undefined,
27
+ batchSize: numberFromEnv(getEnv('SENZOR_BATCH_SIZE')),
28
+ flushInterval: numberFromEnv(getEnv('SENZOR_FLUSH_INTERVAL')),
29
+ flushTimeoutMs: numberFromEnv(getEnv('SENZOR_FLUSH_TIMEOUT_MS')),
30
+ maxQueueSize: numberFromEnv(getEnv('SENZOR_MAX_QUEUE_SIZE')),
31
+ maxSpansPerTrace: numberFromEnv(getEnv('SENZOR_MAX_SPANS_PER_TRACE')),
32
+ captureHeaders: truthy(getEnv('SENZOR_CAPTURE_HEADERS')),
32
33
  captureDbStatement:
33
- process.env.SENZOR_CAPTURE_DB_STATEMENT === 'false'
34
+ getEnv('SENZOR_CAPTURE_DB_STATEMENT') === 'false'
34
35
  ? false
35
36
  : undefined,
36
37
  frameworkSpans:
37
- process.env.SENZOR_FRAMEWORK_SPANS === 'false'
38
+ getEnv('SENZOR_FRAMEWORK_SPANS') === 'false'
38
39
  ? false
39
40
  : undefined,
40
41
  captureMiddlewareSpans:
41
- process.env.SENZOR_CAPTURE_MIDDLEWARE_SPANS === 'false'
42
+ getEnv('SENZOR_CAPTURE_MIDDLEWARE_SPANS') === 'false'
42
43
  ? false
43
44
  : undefined,
44
45
  captureRouterSpans:
45
- process.env.SENZOR_CAPTURE_ROUTER_SPANS === 'false'
46
+ getEnv('SENZOR_CAPTURE_ROUTER_SPANS') === 'false'
46
47
  ? false
47
48
  : undefined,
48
49
  captureLifecycleHookSpans:
49
- process.env.SENZOR_CAPTURE_LIFECYCLE_HOOK_SPANS === 'false'
50
+ getEnv('SENZOR_CAPTURE_LIFECYCLE_HOOK_SPANS') === 'false'
50
51
  ? false
51
52
  : undefined
52
53
  };