@loggerjs/node 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +5 -1
  2. package/dist/bullmq-integration.cjs +169 -0
  3. package/dist/bullmq-integration.cjs.map +1 -0
  4. package/dist/bullmq-integration.js +168 -0
  5. package/dist/bullmq-integration.js.map +1 -0
  6. package/dist/cli-integration.cjs +116 -0
  7. package/dist/cli-integration.cjs.map +1 -0
  8. package/dist/cli-integration.js +115 -0
  9. package/dist/cli-integration.js.map +1 -0
  10. package/dist/context.cjs +37 -0
  11. package/dist/context.cjs.map +1 -0
  12. package/dist/context.js +35 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/database-integration.cjs +128 -0
  15. package/dist/database-integration.cjs.map +1 -0
  16. package/dist/database-integration.js +127 -0
  17. package/dist/database-integration.js.map +1 -0
  18. package/dist/diagnostics-channel-integration.cjs +66 -0
  19. package/dist/diagnostics-channel-integration.cjs.map +1 -0
  20. package/dist/diagnostics-channel-integration.js +65 -0
  21. package/dist/diagnostics-channel-integration.js.map +1 -0
  22. package/dist/express-integration.cjs +130 -0
  23. package/dist/express-integration.cjs.map +1 -0
  24. package/dist/express-integration.js +129 -0
  25. package/dist/express-integration.js.map +1 -0
  26. package/dist/fastify-integration.cjs +120 -0
  27. package/dist/fastify-integration.cjs.map +1 -0
  28. package/dist/fastify-integration.js +119 -0
  29. package/dist/fastify-integration.js.map +1 -0
  30. package/dist/file-transport.cjs +260 -0
  31. package/dist/file-transport.cjs.map +1 -0
  32. package/dist/file-transport.js +259 -0
  33. package/dist/file-transport.js.map +1 -0
  34. package/dist/hapi-integration.cjs +61 -0
  35. package/dist/hapi-integration.cjs.map +1 -0
  36. package/dist/hapi-integration.js +60 -0
  37. package/dist/hapi-integration.js.map +1 -0
  38. package/dist/http-transport.cjs +55 -0
  39. package/dist/http-transport.cjs.map +1 -0
  40. package/dist/http-transport.js +54 -0
  41. package/dist/http-transport.js.map +1 -0
  42. package/dist/koa-integration.cjs +57 -0
  43. package/dist/koa-integration.cjs.map +1 -0
  44. package/dist/koa-integration.js +56 -0
  45. package/dist/koa-integration.js.map +1 -0
  46. package/dist/logger-diagnostics.cjs +46 -0
  47. package/dist/logger-diagnostics.cjs.map +1 -0
  48. package/dist/logger-diagnostics.js +45 -0
  49. package/dist/logger-diagnostics.js.map +1 -0
  50. package/dist/nest-integration.cjs +138 -0
  51. package/dist/nest-integration.cjs.map +1 -0
  52. package/dist/nest-integration.js +137 -0
  53. package/dist/nest-integration.js.map +1 -0
  54. package/dist/node-fetch-integration.cjs +113 -0
  55. package/dist/node-fetch-integration.cjs.map +1 -0
  56. package/dist/node-fetch-integration.js +112 -0
  57. package/dist/node-fetch-integration.js.map +1 -0
  58. package/dist/node-http-client-integration.cjs +192 -0
  59. package/dist/node-http-client-integration.cjs.map +1 -0
  60. package/dist/node-http-client-integration.js +192 -0
  61. package/dist/node-http-client-integration.js.map +1 -0
  62. package/dist/payload-transforms.cjs +29 -0
  63. package/dist/payload-transforms.cjs.map +1 -0
  64. package/dist/payload-transforms.js +28 -0
  65. package/dist/payload-transforms.js.map +1 -0
  66. package/dist/prisma-integration.cjs +150 -0
  67. package/dist/prisma-integration.cjs.map +1 -0
  68. package/dist/prisma-integration.js +149 -0
  69. package/dist/prisma-integration.js.map +1 -0
  70. package/dist/process-integration.cjs +134 -0
  71. package/dist/process-integration.cjs.map +1 -0
  72. package/dist/process-integration.js +133 -0
  73. package/dist/process-integration.js.map +1 -0
  74. package/dist/queue-integration.cjs +148 -0
  75. package/dist/queue-integration.cjs.map +1 -0
  76. package/dist/queue-integration.js +147 -0
  77. package/dist/queue-integration.js.map +1 -0
  78. package/dist/redis-integration.cjs +154 -0
  79. package/dist/redis-integration.cjs.map +1 -0
  80. package/dist/redis-integration.js +153 -0
  81. package/dist/redis-integration.js.map +1 -0
  82. package/dist/rotating-file-transport.cjs +318 -0
  83. package/dist/rotating-file-transport.cjs.map +1 -0
  84. package/dist/rotating-file-transport.js +317 -0
  85. package/dist/rotating-file-transport.js.map +1 -0
  86. package/dist/serverless-integration.cjs +104 -0
  87. package/dist/serverless-integration.cjs.map +1 -0
  88. package/dist/serverless-integration.js +103 -0
  89. package/dist/serverless-integration.js.map +1 -0
  90. package/dist/stdout-transport.cjs +197 -0
  91. package/dist/stdout-transport.cjs.map +1 -0
  92. package/dist/stdout-transport.js +195 -0
  93. package/dist/stdout-transport.js.map +1 -0
  94. package/dist/syslog-transport.cjs +135 -0
  95. package/dist/syslog-transport.cjs.map +1 -0
  96. package/dist/syslog-transport.js +133 -0
  97. package/dist/syslog-transport.js.map +1 -0
  98. package/dist/worker-transport.cjs +285 -0
  99. package/dist/worker-transport.cjs.map +1 -0
  100. package/dist/worker-transport.js +284 -0
  101. package/dist/worker-transport.js.map +1 -0
  102. package/package.json +104 -77
@@ -0,0 +1,137 @@
1
+ import { withContext } from "@loggerjs/core";
2
+ //#region src/express-integration.ts
3
+ const defaultRandom = () => Math.random();
4
+ function defaultSanitizeUrl(url) {
5
+ const queryIndex = url.indexOf("?");
6
+ const hashIndex = url.indexOf("#");
7
+ const end = Math.min(queryIndex >= 0 ? queryIndex : url.length, hashIndex >= 0 ? hashIndex : url.length);
8
+ return url.slice(0, end);
9
+ }
10
+ function defaultLevel(status, _req, _res, aborted) {
11
+ if (aborted) return "warn";
12
+ if (status >= 500) return "error";
13
+ if (status >= 400) return "warn";
14
+ return "info";
15
+ }
16
+ function requestUrl(req) {
17
+ return req.originalUrl ?? req.url ?? req.path ?? "/";
18
+ }
19
+ function headerValue(value) {
20
+ if (typeof value === "number") return String(value);
21
+ return value;
22
+ }
23
+ function pickRequestHeaders(req, names) {
24
+ if (!names || names.length === 0 || !req.headers) return void 0;
25
+ const out = {};
26
+ for (const name of names) {
27
+ const value = req.headers[name.toLowerCase()] ?? req.headers[name];
28
+ if (value !== void 0) out[name.toLowerCase()] = value;
29
+ }
30
+ return Object.keys(out).length > 0 ? out : void 0;
31
+ }
32
+ function pickResponseHeaders(res, names) {
33
+ if (!names || names.length === 0 || !res.getHeader) return void 0;
34
+ const out = {};
35
+ for (const name of names) {
36
+ const value = headerValue(res.getHeader(name));
37
+ if (value !== void 0) out[name.toLowerCase()] = value;
38
+ }
39
+ return Object.keys(out).length > 0 ? out : void 0;
40
+ }
41
+ function defaultRoute(req) {
42
+ const path = req.route?.path;
43
+ return typeof path === "string" ? path : void 0;
44
+ }
45
+ function removeListener(res, event, listener) {
46
+ if (res.off) {
47
+ res.off(event, listener);
48
+ return;
49
+ }
50
+ res.removeListener?.(event, listener);
51
+ }
52
+ function onResponseDone(res, event, listener) {
53
+ if (res.once) {
54
+ res.once(event, listener);
55
+ return;
56
+ }
57
+ res.on?.(event, listener);
58
+ }
59
+ function expressIntegration(logger, options = {}) {
60
+ const name = options.name ?? "express";
61
+ const minStatus = options.minStatus ?? 400;
62
+ const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
63
+ const captureAborted = options.captureAborted ?? true;
64
+ const sampleRate = options.sampleRate ?? 1;
65
+ const random = options.random ?? defaultRandom;
66
+ const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;
67
+ const levelFor = options.level ?? defaultLevel;
68
+ const routeFor = options.getRoute ?? defaultRoute;
69
+ const bindContext = options.bindContext ?? true;
70
+ return (req, res, next) => {
71
+ const started = Date.now();
72
+ const method = (req.method ?? "GET").toUpperCase();
73
+ const url = sanitizeUrl(requestUrl(req));
74
+ const requestId = options.getRequestId?.(req, res);
75
+ let completed = false;
76
+ const context = {
77
+ httpMethod: method,
78
+ httpUrl: url,
79
+ requestId,
80
+ ...options.context?.(req, res)
81
+ };
82
+ const shouldCapture = (status, aborted) => {
83
+ if (aborted && captureAborted) return true;
84
+ if (status >= minStatus) return true;
85
+ if (!captureAll) return false;
86
+ return sampleRate >= 1 || random() < sampleRate;
87
+ };
88
+ const cleanup = () => {
89
+ removeListener(res, "finish", onFinish);
90
+ removeListener(res, "close", onClose);
91
+ };
92
+ const logRequest = (event) => {
93
+ if (completed) return;
94
+ completed = true;
95
+ cleanup();
96
+ const status = res.statusCode ?? 0;
97
+ const aborted = event === "close" && res.writableEnded !== true;
98
+ if (!shouldCapture(status, aborted)) return;
99
+ const http = {
100
+ kind: name,
101
+ framework: "express",
102
+ method,
103
+ url,
104
+ route: routeFor(req),
105
+ status,
106
+ durationMs: Date.now() - started,
107
+ aborted,
108
+ requestId,
109
+ remoteAddress: req.ip ?? req.socket?.remoteAddress,
110
+ requestHeaders: pickRequestHeaders(req, options.captureRequestHeaders),
111
+ responseHeaders: pickResponseHeaders(res, options.captureResponseHeaders)
112
+ };
113
+ logger.log(levelFor(status, req, res, aborted), `Express ${status} ${method} ${url}`, { http });
114
+ };
115
+ const onFinish = () => logRequest("finish");
116
+ const onClose = () => logRequest("close");
117
+ onResponseDone(res, "finish", onFinish);
118
+ onResponseDone(res, "close", onClose);
119
+ if (bindContext) {
120
+ withContext(context, () => next());
121
+ return;
122
+ }
123
+ next();
124
+ };
125
+ }
126
+ //#endregion
127
+ //#region src/nest-integration.ts
128
+ function nestMiddlewareIntegration(logger, options = {}) {
129
+ return expressIntegration(logger, {
130
+ name: "nestjs",
131
+ ...options
132
+ });
133
+ }
134
+ //#endregion
135
+ export { nestMiddlewareIntegration };
136
+
137
+ //# sourceMappingURL=nest-integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nest-integration.js","names":[],"sources":["../src/express-integration.ts","../src/nest-integration.ts"],"sourcesContent":["import { withContext, type LoggerLevel, type LoggerLike, type LogData } from \"@loggerjs/core\";\n\nexport interface ExpressRequestLike {\n method?: string;\n originalUrl?: string;\n url?: string;\n path?: string;\n headers?: Record<string, string | string[] | undefined>;\n ip?: string;\n route?: { path?: string };\n socket?: { remoteAddress?: string };\n [key: string]: unknown;\n}\n\nexport interface ExpressResponseLike {\n statusCode?: number;\n writableEnded?: boolean;\n headersSent?: boolean;\n getHeader?: (name: string) => number | string | string[] | undefined;\n once?: (event: \"finish\" | \"close\", listener: () => void) => unknown;\n on?: (event: \"finish\" | \"close\", listener: () => void) => unknown;\n off?: (event: \"finish\" | \"close\", listener: () => void) => unknown;\n removeListener?: (event: \"finish\" | \"close\", listener: () => void) => unknown;\n}\n\nexport type ExpressNextFunction = (error?: unknown) => void;\nexport type ExpressRequestHandler = (\n req: ExpressRequestLike,\n res: ExpressResponseLike,\n next: ExpressNextFunction,\n) => void;\n\nexport interface ExpressIntegrationOptions {\n name?: string;\n minStatus?: number;\n captureAll?: boolean;\n captureSuccessful?: boolean;\n captureAborted?: boolean;\n sampleRate?: number;\n random?: () => number;\n bindContext?: boolean;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n sanitizeUrl?: (url: string) => string;\n getRequestId?: (req: ExpressRequestLike, res: ExpressResponseLike) => string | undefined;\n getRoute?: (req: ExpressRequestLike) => string | undefined;\n context?: (\n req: ExpressRequestLike,\n res: ExpressResponseLike,\n ) => Record<string, unknown> | undefined;\n level?: (\n status: number,\n req: ExpressRequestLike,\n res: ExpressResponseLike,\n aborted: boolean,\n ) => LoggerLevel;\n}\n\nconst defaultRandom = () => Math.random();\n\nfunction defaultSanitizeUrl(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const end = Math.min(\n queryIndex >= 0 ? queryIndex : url.length,\n hashIndex >= 0 ? hashIndex : url.length,\n );\n return url.slice(0, end);\n}\n\nfunction defaultLevel(\n status: number,\n _req: ExpressRequestLike,\n _res: ExpressResponseLike,\n aborted: boolean,\n): LoggerLevel {\n if (aborted) return \"warn\";\n if (status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nfunction requestUrl(req: ExpressRequestLike): string {\n return req.originalUrl ?? req.url ?? req.path ?? \"/\";\n}\n\nfunction headerValue(value: number | string | string[] | undefined): string | string[] | undefined {\n if (typeof value === \"number\") return String(value);\n return value;\n}\n\nfunction pickRequestHeaders(\n req: ExpressRequestLike,\n names: readonly string[] | undefined,\n): Record<string, string | string[]> | undefined {\n if (!names || names.length === 0 || !req.headers) return undefined;\n const out: Record<string, string | string[]> = {};\n for (const name of names) {\n const value = req.headers[name.toLowerCase()] ?? req.headers[name];\n if (value !== undefined) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction pickResponseHeaders(\n res: ExpressResponseLike,\n names: readonly string[] | undefined,\n): Record<string, string | string[]> | undefined {\n if (!names || names.length === 0 || !res.getHeader) return undefined;\n const out: Record<string, string | string[]> = {};\n for (const name of names) {\n const value = headerValue(res.getHeader(name));\n if (value !== undefined) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction defaultRoute(req: ExpressRequestLike): string | undefined {\n const path = req.route?.path;\n return typeof path === \"string\" ? path : undefined;\n}\n\nfunction removeListener(res: ExpressResponseLike, event: \"finish\" | \"close\", listener: () => void) {\n if (res.off) {\n res.off(event, listener);\n return;\n }\n res.removeListener?.(event, listener);\n}\n\nfunction onResponseDone(res: ExpressResponseLike, event: \"finish\" | \"close\", listener: () => void) {\n if (res.once) {\n res.once(event, listener);\n return;\n }\n res.on?.(event, listener);\n}\n\nexport function expressIntegration(\n logger: LoggerLike,\n options: ExpressIntegrationOptions = {},\n): ExpressRequestHandler {\n const name = options.name ?? \"express\";\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const captureAborted = options.captureAborted ?? true;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;\n const levelFor = options.level ?? defaultLevel;\n const routeFor = options.getRoute ?? defaultRoute;\n const bindContext = options.bindContext ?? true;\n\n return (req, res, next) => {\n const started = Date.now();\n const method = (req.method ?? \"GET\").toUpperCase();\n const url = sanitizeUrl(requestUrl(req));\n const requestId = options.getRequestId?.(req, res);\n let completed = false;\n\n const context = {\n httpMethod: method,\n httpUrl: url,\n requestId,\n ...options.context?.(req, res),\n };\n\n const shouldCapture = (status: number, aborted: boolean) => {\n if (aborted && captureAborted) return true;\n if (status >= minStatus) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n const cleanup = () => {\n removeListener(res, \"finish\", onFinish);\n removeListener(res, \"close\", onClose);\n };\n\n const logRequest = (event: \"finish\" | \"close\") => {\n if (completed) return;\n completed = true;\n cleanup();\n const status = res.statusCode ?? 0;\n const aborted = event === \"close\" && res.writableEnded !== true;\n if (!shouldCapture(status, aborted)) return;\n const http: Record<string, unknown> = {\n kind: name,\n framework: \"express\",\n method,\n url,\n route: routeFor(req),\n status,\n durationMs: Date.now() - started,\n aborted,\n requestId,\n remoteAddress: req.ip ?? req.socket?.remoteAddress,\n requestHeaders: pickRequestHeaders(req, options.captureRequestHeaders),\n responseHeaders: pickResponseHeaders(res, options.captureResponseHeaders),\n };\n logger.log(levelFor(status, req, res, aborted), `Express ${status} ${method} ${url}`, {\n http,\n } as LogData);\n };\n\n const onFinish = () => logRequest(\"finish\");\n const onClose = () => logRequest(\"close\");\n onResponseDone(res, \"finish\", onFinish);\n onResponseDone(res, \"close\", onClose);\n\n if (bindContext) {\n withContext(context, () => next());\n return;\n }\n next();\n };\n}\n","import type { LoggerLike } from \"@loggerjs/core\";\nimport {\n expressIntegration,\n type ExpressIntegrationOptions,\n type ExpressRequestHandler,\n} from \"./express-integration\";\n\nexport type NestMiddleware = ExpressRequestHandler;\n\nexport function nestMiddlewareIntegration(\n logger: LoggerLike,\n options: ExpressIntegrationOptions = {},\n): NestMiddleware {\n return expressIntegration(logger, {\n name: \"nestjs\",\n ...options,\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/node-fetch-integration.ts
3
+ const defaultRandom = () => Math.random();
4
+ function defaultSanitizeUrl(url) {
5
+ const queryIndex = url.indexOf("?");
6
+ const hashIndex = url.indexOf("#");
7
+ const end = Math.min(queryIndex >= 0 ? queryIndex : url.length, hashIndex >= 0 ? hashIndex : url.length);
8
+ return url.slice(0, end);
9
+ }
10
+ function defaultLevel(status, error) {
11
+ if (error || status === void 0 || status >= 500) return "error";
12
+ if (status >= 400) return "warn";
13
+ return "info";
14
+ }
15
+ function isUrlLike(value) {
16
+ return typeof URL !== "undefined" && value instanceof URL;
17
+ }
18
+ function isObject(value) {
19
+ return typeof value === "object" && value !== null;
20
+ }
21
+ function headerValue(headers, name) {
22
+ if (!isObject(headers)) return void 0;
23
+ if (typeof headers.get === "function") return headers.get?.(name) ?? void 0;
24
+ const value = headers[name.toLowerCase()] ?? headers[name];
25
+ return value === void 0 ? void 0 : String(value);
26
+ }
27
+ function pickHeaders(headers, names) {
28
+ if (!names || names.length === 0) return void 0;
29
+ const out = {};
30
+ for (const name of names) {
31
+ const lowerName = name.toLowerCase();
32
+ const value = headerValue(headers, lowerName) ?? headerValue(headers, name);
33
+ if (value !== void 0) out[lowerName] = value;
34
+ }
35
+ return Object.keys(out).length > 0 ? out : void 0;
36
+ }
37
+ function requestInfo(input, init, sanitizeUrl, captureRequestHeaders) {
38
+ const request = isObject(input) && !isUrlLike(input) ? input : void 0;
39
+ return {
40
+ method: (init?.method ?? request?.method ?? "GET").toUpperCase(),
41
+ url: sanitizeUrl(isUrlLike(input) ? input.href : typeof input === "string" ? input : request?.url ?? "/"),
42
+ requestHeaders: pickHeaders(init?.headers ?? request?.headers, captureRequestHeaders)
43
+ };
44
+ }
45
+ function statusMessage(status) {
46
+ return status === void 0 ? "unknown" : String(status);
47
+ }
48
+ function nodeFetchIntegration(options = {}) {
49
+ const name = options.name ?? "node-fetch";
50
+ const minStatus = options.minStatus ?? 400;
51
+ const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
52
+ const sampleRate = options.sampleRate ?? 1;
53
+ const random = options.random ?? defaultRandom;
54
+ const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;
55
+ const levelFor = options.level ?? defaultLevel;
56
+ const shouldCapture = (status, error) => {
57
+ if (error) return true;
58
+ if (status !== void 0 && status >= minStatus) return true;
59
+ if (!captureAll) return false;
60
+ return sampleRate >= 1 || random() < sampleRate;
61
+ };
62
+ return {
63
+ name: "node-fetch",
64
+ setup(api) {
65
+ const target = options.target ?? globalThis;
66
+ if (!target.fetch) return;
67
+ const originalFetch = target.fetch;
68
+ const capture = api.guard((input) => api.capture(input));
69
+ let disposed = false;
70
+ const captureResult = (info, durationMs, status, error, responseHeaders) => {
71
+ if (disposed || !shouldCapture(status, error)) return;
72
+ capture({
73
+ level: levelFor(status, error, info),
74
+ message: error ? `Fetch error ${info.method} ${info.url}` : `Fetch ${statusMessage(status)} ${info.method} ${info.url}`,
75
+ error,
76
+ props: { http: {
77
+ kind: name,
78
+ runtime: "node",
79
+ instrument: "fetch",
80
+ direction: "outgoing",
81
+ method: info.method,
82
+ url: info.url,
83
+ status,
84
+ durationMs,
85
+ requestHeaders: info.requestHeaders,
86
+ responseHeaders
87
+ } }
88
+ });
89
+ };
90
+ target.fetch = async function patchedFetch(input, init) {
91
+ const started = Date.now();
92
+ const info = requestInfo(input, init, sanitizeUrl, options.captureRequestHeaders);
93
+ try {
94
+ const response = await originalFetch.call(this, input, init);
95
+ captureResult(info, Date.now() - started, response.status, void 0, pickHeaders(response.headers, options.captureResponseHeaders));
96
+ return response;
97
+ } catch (error) {
98
+ captureResult(info, Date.now() - started, void 0, error);
99
+ throw error;
100
+ }
101
+ };
102
+ return () => {
103
+ if (disposed) return;
104
+ disposed = true;
105
+ target.fetch = originalFetch;
106
+ };
107
+ }
108
+ };
109
+ }
110
+ //#endregion
111
+ exports.nodeFetchIntegration = nodeFetchIntegration;
112
+
113
+ //# sourceMappingURL=node-fetch-integration.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-fetch-integration.cjs","names":[],"sources":["../src/node-fetch-integration.ts"],"sourcesContent":["import {\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type LoggerLevel,\n} from \"@loggerjs/core\";\n\nexport interface NodeFetchHeadersLike {\n get?: (name: string) => string | null;\n [key: string]: unknown;\n}\n\nexport interface NodeFetchRequestLike {\n url?: string;\n method?: string;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport interface NodeFetchInitLike {\n method?: string;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport interface NodeFetchResponseLike {\n status?: number;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport type NodeFetchFunction = (\n input: string | URL | NodeFetchRequestLike,\n init?: NodeFetchInitLike,\n) => Promise<NodeFetchResponseLike>;\n\nexport interface NodeFetchTargetLike {\n fetch?: NodeFetchFunction;\n}\n\nexport interface NodeFetchRequestInfo {\n method: string;\n url: string;\n requestHeaders?: Record<string, string>;\n}\n\nexport interface NodeFetchIntegrationOptions {\n name?: string;\n minStatus?: number;\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n sanitizeUrl?: (url: string) => string;\n level?: (status: number | undefined, error: unknown, info: NodeFetchRequestInfo) => LoggerLevel;\n target?: NodeFetchTargetLike;\n}\n\nconst defaultRandom = () => Math.random();\n\nfunction defaultSanitizeUrl(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const end = Math.min(\n queryIndex >= 0 ? queryIndex : url.length,\n hashIndex >= 0 ? hashIndex : url.length,\n );\n return url.slice(0, end);\n}\n\nfunction defaultLevel(status: number | undefined, error: unknown): LoggerLevel {\n if (error || status === undefined || status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nfunction isUrlLike(value: unknown): value is URL {\n return typeof URL !== \"undefined\" && value instanceof URL;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction headerValue(headers: unknown, name: string): string | undefined {\n if (!isObject(headers)) return undefined;\n if (typeof (headers as NodeFetchHeadersLike).get === \"function\") {\n return (headers as NodeFetchHeadersLike).get?.(name) ?? undefined;\n }\n const value = headers[name.toLowerCase()] ?? headers[name];\n return value === undefined ? undefined : String(value);\n}\n\nfunction pickHeaders(\n headers: unknown,\n names: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!names || names.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of names) {\n const lowerName = name.toLowerCase();\n const value = headerValue(headers, lowerName) ?? headerValue(headers, name);\n if (value !== undefined) out[lowerName] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction requestInfo(\n input: string | URL | NodeFetchRequestLike,\n init: NodeFetchInitLike | undefined,\n sanitizeUrl: (url: string) => string,\n captureRequestHeaders: readonly string[] | undefined,\n): NodeFetchRequestInfo {\n const request =\n isObject(input) && !isUrlLike(input) ? (input as NodeFetchRequestLike) : undefined;\n const method = (init?.method ?? request?.method ?? \"GET\").toUpperCase();\n const url = isUrlLike(input)\n ? input.href\n : typeof input === \"string\"\n ? input\n : (request?.url ?? \"/\");\n return {\n method,\n url: sanitizeUrl(url),\n requestHeaders: pickHeaders(init?.headers ?? request?.headers, captureRequestHeaders),\n };\n}\n\nfunction statusMessage(status: number | undefined) {\n return status === undefined ? \"unknown\" : String(status);\n}\n\nexport function nodeFetchIntegration(options: NodeFetchIntegrationOptions = {}): Integration {\n const name = options.name ?? \"node-fetch\";\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;\n const levelFor = options.level ?? defaultLevel;\n\n const shouldCapture = (status: number | undefined, error: unknown) => {\n if (error) return true;\n if (status !== undefined && status >= minStatus) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n return {\n name: \"node-fetch\",\n setup(api: IntegrationSetupContext) {\n const target = options.target ?? (globalThis as unknown as NodeFetchTargetLike);\n if (!target.fetch) return;\n\n const originalFetch = target.fetch;\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n let disposed = false;\n\n const captureResult = (\n info: NodeFetchRequestInfo,\n durationMs: number,\n status: number | undefined,\n error: unknown,\n responseHeaders?: Record<string, string>,\n ) => {\n if (disposed || !shouldCapture(status, error)) return;\n capture({\n level: levelFor(status, error, info),\n message: error\n ? `Fetch error ${info.method} ${info.url}`\n : `Fetch ${statusMessage(status)} ${info.method} ${info.url}`,\n error,\n props: {\n http: {\n kind: name,\n runtime: \"node\",\n instrument: \"fetch\",\n direction: \"outgoing\",\n method: info.method,\n url: info.url,\n status,\n durationMs,\n requestHeaders: info.requestHeaders,\n responseHeaders,\n },\n },\n });\n };\n\n target.fetch = async function patchedFetch(\n this: unknown,\n input: string | URL | NodeFetchRequestLike,\n init?: NodeFetchInitLike,\n ) {\n const started = Date.now();\n const info = requestInfo(input, init, sanitizeUrl, options.captureRequestHeaders);\n try {\n const response = await originalFetch.call(this, input, init);\n captureResult(\n info,\n Date.now() - started,\n response.status,\n undefined,\n pickHeaders(response.headers, options.captureResponseHeaders),\n );\n return response;\n } catch (error) {\n captureResult(info, Date.now() - started, undefined, error);\n throw error;\n }\n };\n\n return () => {\n if (disposed) return;\n disposed = true;\n target.fetch = originalFetch;\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ //#region src/node-fetch-integration.ts
2
+ const defaultRandom = () => Math.random();
3
+ function defaultSanitizeUrl(url) {
4
+ const queryIndex = url.indexOf("?");
5
+ const hashIndex = url.indexOf("#");
6
+ const end = Math.min(queryIndex >= 0 ? queryIndex : url.length, hashIndex >= 0 ? hashIndex : url.length);
7
+ return url.slice(0, end);
8
+ }
9
+ function defaultLevel(status, error) {
10
+ if (error || status === void 0 || status >= 500) return "error";
11
+ if (status >= 400) return "warn";
12
+ return "info";
13
+ }
14
+ function isUrlLike(value) {
15
+ return typeof URL !== "undefined" && value instanceof URL;
16
+ }
17
+ function isObject(value) {
18
+ return typeof value === "object" && value !== null;
19
+ }
20
+ function headerValue(headers, name) {
21
+ if (!isObject(headers)) return void 0;
22
+ if (typeof headers.get === "function") return headers.get?.(name) ?? void 0;
23
+ const value = headers[name.toLowerCase()] ?? headers[name];
24
+ return value === void 0 ? void 0 : String(value);
25
+ }
26
+ function pickHeaders(headers, names) {
27
+ if (!names || names.length === 0) return void 0;
28
+ const out = {};
29
+ for (const name of names) {
30
+ const lowerName = name.toLowerCase();
31
+ const value = headerValue(headers, lowerName) ?? headerValue(headers, name);
32
+ if (value !== void 0) out[lowerName] = value;
33
+ }
34
+ return Object.keys(out).length > 0 ? out : void 0;
35
+ }
36
+ function requestInfo(input, init, sanitizeUrl, captureRequestHeaders) {
37
+ const request = isObject(input) && !isUrlLike(input) ? input : void 0;
38
+ return {
39
+ method: (init?.method ?? request?.method ?? "GET").toUpperCase(),
40
+ url: sanitizeUrl(isUrlLike(input) ? input.href : typeof input === "string" ? input : request?.url ?? "/"),
41
+ requestHeaders: pickHeaders(init?.headers ?? request?.headers, captureRequestHeaders)
42
+ };
43
+ }
44
+ function statusMessage(status) {
45
+ return status === void 0 ? "unknown" : String(status);
46
+ }
47
+ function nodeFetchIntegration(options = {}) {
48
+ const name = options.name ?? "node-fetch";
49
+ const minStatus = options.minStatus ?? 400;
50
+ const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
51
+ const sampleRate = options.sampleRate ?? 1;
52
+ const random = options.random ?? defaultRandom;
53
+ const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;
54
+ const levelFor = options.level ?? defaultLevel;
55
+ const shouldCapture = (status, error) => {
56
+ if (error) return true;
57
+ if (status !== void 0 && status >= minStatus) return true;
58
+ if (!captureAll) return false;
59
+ return sampleRate >= 1 || random() < sampleRate;
60
+ };
61
+ return {
62
+ name: "node-fetch",
63
+ setup(api) {
64
+ const target = options.target ?? globalThis;
65
+ if (!target.fetch) return;
66
+ const originalFetch = target.fetch;
67
+ const capture = api.guard((input) => api.capture(input));
68
+ let disposed = false;
69
+ const captureResult = (info, durationMs, status, error, responseHeaders) => {
70
+ if (disposed || !shouldCapture(status, error)) return;
71
+ capture({
72
+ level: levelFor(status, error, info),
73
+ message: error ? `Fetch error ${info.method} ${info.url}` : `Fetch ${statusMessage(status)} ${info.method} ${info.url}`,
74
+ error,
75
+ props: { http: {
76
+ kind: name,
77
+ runtime: "node",
78
+ instrument: "fetch",
79
+ direction: "outgoing",
80
+ method: info.method,
81
+ url: info.url,
82
+ status,
83
+ durationMs,
84
+ requestHeaders: info.requestHeaders,
85
+ responseHeaders
86
+ } }
87
+ });
88
+ };
89
+ target.fetch = async function patchedFetch(input, init) {
90
+ const started = Date.now();
91
+ const info = requestInfo(input, init, sanitizeUrl, options.captureRequestHeaders);
92
+ try {
93
+ const response = await originalFetch.call(this, input, init);
94
+ captureResult(info, Date.now() - started, response.status, void 0, pickHeaders(response.headers, options.captureResponseHeaders));
95
+ return response;
96
+ } catch (error) {
97
+ captureResult(info, Date.now() - started, void 0, error);
98
+ throw error;
99
+ }
100
+ };
101
+ return () => {
102
+ if (disposed) return;
103
+ disposed = true;
104
+ target.fetch = originalFetch;
105
+ };
106
+ }
107
+ };
108
+ }
109
+ //#endregion
110
+ export { nodeFetchIntegration };
111
+
112
+ //# sourceMappingURL=node-fetch-integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-fetch-integration.js","names":[],"sources":["../src/node-fetch-integration.ts"],"sourcesContent":["import {\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type LoggerLevel,\n} from \"@loggerjs/core\";\n\nexport interface NodeFetchHeadersLike {\n get?: (name: string) => string | null;\n [key: string]: unknown;\n}\n\nexport interface NodeFetchRequestLike {\n url?: string;\n method?: string;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport interface NodeFetchInitLike {\n method?: string;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport interface NodeFetchResponseLike {\n status?: number;\n headers?: NodeFetchHeadersLike | Record<string, unknown>;\n}\n\nexport type NodeFetchFunction = (\n input: string | URL | NodeFetchRequestLike,\n init?: NodeFetchInitLike,\n) => Promise<NodeFetchResponseLike>;\n\nexport interface NodeFetchTargetLike {\n fetch?: NodeFetchFunction;\n}\n\nexport interface NodeFetchRequestInfo {\n method: string;\n url: string;\n requestHeaders?: Record<string, string>;\n}\n\nexport interface NodeFetchIntegrationOptions {\n name?: string;\n minStatus?: number;\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n sanitizeUrl?: (url: string) => string;\n level?: (status: number | undefined, error: unknown, info: NodeFetchRequestInfo) => LoggerLevel;\n target?: NodeFetchTargetLike;\n}\n\nconst defaultRandom = () => Math.random();\n\nfunction defaultSanitizeUrl(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const end = Math.min(\n queryIndex >= 0 ? queryIndex : url.length,\n hashIndex >= 0 ? hashIndex : url.length,\n );\n return url.slice(0, end);\n}\n\nfunction defaultLevel(status: number | undefined, error: unknown): LoggerLevel {\n if (error || status === undefined || status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nfunction isUrlLike(value: unknown): value is URL {\n return typeof URL !== \"undefined\" && value instanceof URL;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction headerValue(headers: unknown, name: string): string | undefined {\n if (!isObject(headers)) return undefined;\n if (typeof (headers as NodeFetchHeadersLike).get === \"function\") {\n return (headers as NodeFetchHeadersLike).get?.(name) ?? undefined;\n }\n const value = headers[name.toLowerCase()] ?? headers[name];\n return value === undefined ? undefined : String(value);\n}\n\nfunction pickHeaders(\n headers: unknown,\n names: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!names || names.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of names) {\n const lowerName = name.toLowerCase();\n const value = headerValue(headers, lowerName) ?? headerValue(headers, name);\n if (value !== undefined) out[lowerName] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction requestInfo(\n input: string | URL | NodeFetchRequestLike,\n init: NodeFetchInitLike | undefined,\n sanitizeUrl: (url: string) => string,\n captureRequestHeaders: readonly string[] | undefined,\n): NodeFetchRequestInfo {\n const request =\n isObject(input) && !isUrlLike(input) ? (input as NodeFetchRequestLike) : undefined;\n const method = (init?.method ?? request?.method ?? \"GET\").toUpperCase();\n const url = isUrlLike(input)\n ? input.href\n : typeof input === \"string\"\n ? input\n : (request?.url ?? \"/\");\n return {\n method,\n url: sanitizeUrl(url),\n requestHeaders: pickHeaders(init?.headers ?? request?.headers, captureRequestHeaders),\n };\n}\n\nfunction statusMessage(status: number | undefined) {\n return status === undefined ? \"unknown\" : String(status);\n}\n\nexport function nodeFetchIntegration(options: NodeFetchIntegrationOptions = {}): Integration {\n const name = options.name ?? \"node-fetch\";\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;\n const levelFor = options.level ?? defaultLevel;\n\n const shouldCapture = (status: number | undefined, error: unknown) => {\n if (error) return true;\n if (status !== undefined && status >= minStatus) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n return {\n name: \"node-fetch\",\n setup(api: IntegrationSetupContext) {\n const target = options.target ?? (globalThis as unknown as NodeFetchTargetLike);\n if (!target.fetch) return;\n\n const originalFetch = target.fetch;\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n let disposed = false;\n\n const captureResult = (\n info: NodeFetchRequestInfo,\n durationMs: number,\n status: number | undefined,\n error: unknown,\n responseHeaders?: Record<string, string>,\n ) => {\n if (disposed || !shouldCapture(status, error)) return;\n capture({\n level: levelFor(status, error, info),\n message: error\n ? `Fetch error ${info.method} ${info.url}`\n : `Fetch ${statusMessage(status)} ${info.method} ${info.url}`,\n error,\n props: {\n http: {\n kind: name,\n runtime: \"node\",\n instrument: \"fetch\",\n direction: \"outgoing\",\n method: info.method,\n url: info.url,\n status,\n durationMs,\n requestHeaders: info.requestHeaders,\n responseHeaders,\n },\n },\n });\n };\n\n target.fetch = async function patchedFetch(\n this: unknown,\n input: string | URL | NodeFetchRequestLike,\n init?: NodeFetchInitLike,\n ) {\n const started = Date.now();\n const info = requestInfo(input, init, sanitizeUrl, options.captureRequestHeaders);\n try {\n const response = await originalFetch.call(this, input, init);\n captureResult(\n info,\n Date.now() - started,\n response.status,\n undefined,\n pickHeaders(response.headers, options.captureResponseHeaders),\n );\n return response;\n } catch (error) {\n captureResult(info, Date.now() - started, undefined, error);\n throw error;\n }\n };\n\n return () => {\n if (disposed) return;\n disposed = true;\n target.fetch = originalFetch;\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,192 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/node-http-client-integration.ts
3
+ const requireBuiltin = (0, require("node:module").createRequire)(require("url").pathToFileURL(__filename).href);
4
+ const defaultRandom = () => Math.random();
5
+ let cachedHttpModule;
6
+ let cachedHttpsModule;
7
+ function loadBuiltin(name, fallback) {
8
+ try {
9
+ return requireBuiltin(name);
10
+ } catch {
11
+ try {
12
+ return requireBuiltin(fallback);
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ }
18
+ function loadHttpModule() {
19
+ if (cachedHttpModule !== void 0) return cachedHttpModule;
20
+ cachedHttpModule = loadBuiltin("node:http", "http");
21
+ return cachedHttpModule;
22
+ }
23
+ function loadHttpsModule() {
24
+ if (cachedHttpsModule !== void 0) return cachedHttpsModule;
25
+ cachedHttpsModule = loadBuiltin("node:https", "https");
26
+ return cachedHttpsModule;
27
+ }
28
+ function defaultSanitizeUrl(url) {
29
+ const queryIndex = url.indexOf("?");
30
+ const hashIndex = url.indexOf("#");
31
+ const end = Math.min(queryIndex >= 0 ? queryIndex : url.length, hashIndex >= 0 ? hashIndex : url.length);
32
+ return url.slice(0, end);
33
+ }
34
+ function defaultLevel(status, error) {
35
+ if (error || status === void 0 || status >= 500) return "error";
36
+ if (status >= 400) return "warn";
37
+ return "info";
38
+ }
39
+ function isUrlLike(value) {
40
+ return typeof URL !== "undefined" && value instanceof URL;
41
+ }
42
+ function isOptionsObject(value) {
43
+ return typeof value === "object" && value !== null && !isUrlLike(value);
44
+ }
45
+ function headerValue(value) {
46
+ if (value === void 0) return void 0;
47
+ if (Array.isArray(value)) return value.map(String);
48
+ return String(value);
49
+ }
50
+ function pickHeaders(headers, names) {
51
+ if (!names || names.length === 0 || !isOptionsObject(headers)) return void 0;
52
+ const out = {};
53
+ for (const name of names) {
54
+ const lowerName = name.toLowerCase();
55
+ const value = headerValue(headers[lowerName] ?? headers[name]);
56
+ if (value !== void 0) out[lowerName] = value;
57
+ }
58
+ return Object.keys(out).length > 0 ? out : void 0;
59
+ }
60
+ function maybeUrl(value) {
61
+ if (isUrlLike(value)) return value;
62
+ if (typeof value !== "string") return void 0;
63
+ try {
64
+ return new URL(value);
65
+ } catch {
66
+ return;
67
+ }
68
+ }
69
+ function pathFromUrl(url) {
70
+ if (!url) return "/";
71
+ return `${url.pathname || "/"}${url.search}`;
72
+ }
73
+ function optionString(options, key) {
74
+ const value = options[key];
75
+ if (value === void 0) return void 0;
76
+ return String(value);
77
+ }
78
+ function requestInfo(args, defaultProtocol, sanitizeUrl, captureRequestHeaders) {
79
+ const first = args[0];
80
+ const second = args[1];
81
+ const parsed = maybeUrl(first);
82
+ const options = isOptionsObject(first) ? first : isOptionsObject(second) ? second : void 0;
83
+ const protocol = optionString(options ?? {}, "protocol") ?? parsed?.protocol ?? defaultProtocol;
84
+ const method = (optionString(options ?? {}, "method") ?? "GET").toUpperCase();
85
+ const host = optionString(options ?? {}, "host") ?? optionString(options ?? {}, "hostname") ?? parsed?.host;
86
+ const port = optionString(options ?? {}, "port");
87
+ const path = optionString(options ?? {}, "path") ?? pathFromUrl(parsed);
88
+ const requestHeaders = pickHeaders(options?.headers, captureRequestHeaders);
89
+ return {
90
+ protocol,
91
+ method,
92
+ url: sanitizeUrl(parsed?.href ?? (host ? `${protocol}//${host}${port ? `:${port}` : ""}${path}` : path)),
93
+ requestHeaders
94
+ };
95
+ }
96
+ function listenOnce(request, event, listener) {
97
+ let active = true;
98
+ const wrapped = (...args) => {
99
+ if (!active) return;
100
+ active = false;
101
+ cleanup();
102
+ listener(...args);
103
+ };
104
+ const cleanup = () => {
105
+ request.off?.(event, wrapped);
106
+ request.removeListener?.(event, wrapped);
107
+ };
108
+ if (request.once) request.once(event, wrapped);
109
+ else request.on?.(event, wrapped);
110
+ }
111
+ function statusMessage(status) {
112
+ return status === void 0 ? "unknown" : String(status);
113
+ }
114
+ function nodeHttpClientIntegration(options = {}) {
115
+ const name = options.name ?? "node-http-client";
116
+ const minStatus = options.minStatus ?? 400;
117
+ const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
118
+ const sampleRate = options.sampleRate ?? 1;
119
+ const random = options.random ?? defaultRandom;
120
+ const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;
121
+ const levelFor = options.level ?? defaultLevel;
122
+ const shouldCapture = (status, error) => {
123
+ if (error) return true;
124
+ if (status !== void 0 && status >= minStatus) return true;
125
+ if (!captureAll) return false;
126
+ return sampleRate >= 1 || random() < sampleRate;
127
+ };
128
+ return {
129
+ name: "node-http-client",
130
+ setup(api) {
131
+ const httpModule = options.httpModule === void 0 ? loadHttpModule() : options.httpModule;
132
+ const httpsModule = options.httpsModule === void 0 ? loadHttpsModule() : options.httpsModule;
133
+ const capture = api.guard((input) => api.capture(input));
134
+ const disposers = [];
135
+ let disposed = false;
136
+ const captureResult = (info, status, error, responseHeaders) => {
137
+ if (disposed || !shouldCapture(status, error)) return;
138
+ capture({
139
+ level: levelFor(status, error, info),
140
+ message: error ? `HTTP error ${info.method} ${info.url}` : `HTTP ${statusMessage(status)} ${info.method} ${info.url}`,
141
+ error,
142
+ props: { http: {
143
+ kind: name,
144
+ runtime: "node",
145
+ direction: "outgoing",
146
+ protocol: info.protocol,
147
+ method: info.method,
148
+ url: info.url,
149
+ status,
150
+ requestHeaders: info.requestHeaders,
151
+ responseHeaders
152
+ } }
153
+ });
154
+ };
155
+ const patchModule = (module, defaultProtocol) => {
156
+ if (!module?.request) return;
157
+ const originalRequest = module.request;
158
+ const originalGet = module.get;
159
+ module.request = function patchedRequest(...args) {
160
+ const info = requestInfo(args, defaultProtocol, sanitizeUrl, options.captureRequestHeaders);
161
+ const request = originalRequest.apply(this, args);
162
+ listenOnce(request, "response", (message) => {
163
+ const response = message;
164
+ captureResult(info, response.statusCode, void 0, pickHeaders(response.headers, options.captureResponseHeaders));
165
+ });
166
+ listenOnce(request, "error", (error) => captureResult(info, void 0, error));
167
+ return request;
168
+ };
169
+ if (originalGet) module.get = function patchedGet(...args) {
170
+ const request = module.request?.apply(this, args) ?? originalGet.apply(this, args);
171
+ request.end?.();
172
+ return request;
173
+ };
174
+ disposers.push(() => {
175
+ module.request = originalRequest;
176
+ if (originalGet) module.get = originalGet;
177
+ });
178
+ };
179
+ patchModule(httpModule, "http:");
180
+ patchModule(httpsModule, "https:");
181
+ return () => {
182
+ if (disposed) return;
183
+ disposed = true;
184
+ for (const dispose of disposers) dispose();
185
+ };
186
+ }
187
+ };
188
+ }
189
+ //#endregion
190
+ exports.nodeHttpClientIntegration = nodeHttpClientIntegration;
191
+
192
+ //# sourceMappingURL=node-http-client-integration.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-http-client-integration.cjs","names":[],"sources":["../src/node-http-client-integration.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport {\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type LoggerLevel,\n} from \"@loggerjs/core\";\n\nexport interface NodeHttpClientRequestLike {\n once?: (event: \"response\" | \"error\", listener: (...args: unknown[]) => void) => unknown;\n on?: (event: \"response\" | \"error\", listener: (...args: unknown[]) => void) => unknown;\n off?: (event: \"response\" | \"error\", listener: (...args: unknown[]) => void) => unknown;\n removeListener?: (event: \"response\" | \"error\", listener: (...args: unknown[]) => void) => unknown;\n end?: (...args: unknown[]) => unknown;\n}\n\nexport interface NodeHttpIncomingMessageLike {\n statusCode?: number;\n headers?: Record<string, number | string | string[] | undefined>;\n}\n\nexport type NodeHttpRequestFunction = (\n this: unknown,\n ...args: unknown[]\n) => NodeHttpClientRequestLike;\n\nexport interface NodeHttpModuleLike {\n request?: NodeHttpRequestFunction;\n get?: NodeHttpRequestFunction;\n}\n\nexport interface NodeHttpClientRequestInfo {\n protocol: \"http:\" | \"https:\" | string;\n method: string;\n url: string;\n requestHeaders?: Record<string, string | string[]>;\n}\n\nexport interface NodeHttpClientIntegrationOptions {\n name?: string;\n minStatus?: number;\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n sanitizeUrl?: (url: string) => string;\n level?: (\n status: number | undefined,\n error: unknown,\n info: NodeHttpClientRequestInfo,\n ) => LoggerLevel;\n httpModule?: NodeHttpModuleLike | null;\n httpsModule?: NodeHttpModuleLike | null;\n}\n\nconst requireBuiltin = createRequire(import.meta.url);\nconst defaultRandom = () => Math.random();\n\nlet cachedHttpModule: NodeHttpModuleLike | null | undefined;\nlet cachedHttpsModule: NodeHttpModuleLike | null | undefined;\n\nfunction loadBuiltin(name: \"node:http\" | \"node:https\", fallback: \"http\" | \"https\") {\n try {\n return requireBuiltin(name) as NodeHttpModuleLike;\n } catch {\n try {\n return requireBuiltin(fallback) as NodeHttpModuleLike;\n } catch {\n return null;\n }\n }\n}\n\nfunction loadHttpModule() {\n if (cachedHttpModule !== undefined) return cachedHttpModule;\n cachedHttpModule = loadBuiltin(\"node:http\", \"http\");\n return cachedHttpModule;\n}\n\nfunction loadHttpsModule() {\n if (cachedHttpsModule !== undefined) return cachedHttpsModule;\n cachedHttpsModule = loadBuiltin(\"node:https\", \"https\");\n return cachedHttpsModule;\n}\n\nfunction defaultSanitizeUrl(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const end = Math.min(\n queryIndex >= 0 ? queryIndex : url.length,\n hashIndex >= 0 ? hashIndex : url.length,\n );\n return url.slice(0, end);\n}\n\nfunction defaultLevel(status: number | undefined, error: unknown): LoggerLevel {\n if (error || status === undefined || status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nfunction isUrlLike(value: unknown): value is URL {\n return typeof URL !== \"undefined\" && value instanceof URL;\n}\n\nfunction isOptionsObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !isUrlLike(value);\n}\n\nfunction headerValue(value: unknown): string | string[] | undefined {\n if (value === undefined) return undefined;\n if (Array.isArray(value)) return value.map(String);\n return String(value);\n}\n\nfunction pickHeaders(\n headers: unknown,\n names: readonly string[] | undefined,\n): Record<string, string | string[]> | undefined {\n if (!names || names.length === 0 || !isOptionsObject(headers)) return undefined;\n const out: Record<string, string | string[]> = {};\n for (const name of names) {\n const lowerName = name.toLowerCase();\n const value = headerValue(headers[lowerName] ?? headers[name]);\n if (value !== undefined) out[lowerName] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction maybeUrl(value: unknown): URL | undefined {\n if (isUrlLike(value)) return value;\n if (typeof value !== \"string\") return undefined;\n try {\n return new URL(value);\n } catch {\n return undefined;\n }\n}\n\nfunction pathFromUrl(url: URL | undefined): string {\n if (!url) return \"/\";\n return `${url.pathname || \"/\"}${url.search}`;\n}\n\nfunction optionString(options: Record<string, unknown>, key: string): string | undefined {\n const value = options[key];\n if (value === undefined) return undefined;\n return String(value);\n}\n\nfunction requestInfo(\n args: readonly unknown[],\n defaultProtocol: \"http:\" | \"https:\",\n sanitizeUrl: (url: string) => string,\n captureRequestHeaders: readonly string[] | undefined,\n): NodeHttpClientRequestInfo {\n const first = args[0];\n const second = args[1];\n const parsed = maybeUrl(first);\n const options = isOptionsObject(first) ? first : isOptionsObject(second) ? second : undefined;\n const protocol = optionString(options ?? {}, \"protocol\") ?? parsed?.protocol ?? defaultProtocol;\n const method = (optionString(options ?? {}, \"method\") ?? \"GET\").toUpperCase();\n const host =\n optionString(options ?? {}, \"host\") ?? optionString(options ?? {}, \"hostname\") ?? parsed?.host;\n const port = optionString(options ?? {}, \"port\");\n const path = optionString(options ?? {}, \"path\") ?? pathFromUrl(parsed);\n const requestHeaders = pickHeaders(options?.headers, captureRequestHeaders);\n const url =\n parsed?.href ?? (host ? `${protocol}//${host}${port ? `:${port}` : \"\"}${path}` : path);\n\n return {\n protocol,\n method,\n url: sanitizeUrl(url),\n requestHeaders,\n };\n}\n\nfunction listenOnce(\n request: NodeHttpClientRequestLike,\n event: \"response\" | \"error\",\n listener: (...args: unknown[]) => void,\n) {\n let active = true;\n const wrapped = (...args: unknown[]) => {\n if (!active) return;\n active = false;\n cleanup();\n listener(...args);\n };\n const cleanup = () => {\n request.off?.(event, wrapped);\n request.removeListener?.(event, wrapped);\n };\n\n if (request.once) request.once(event, wrapped);\n else request.on?.(event, wrapped);\n}\n\nfunction statusMessage(status: number | undefined) {\n return status === undefined ? \"unknown\" : String(status);\n}\n\nexport function nodeHttpClientIntegration(\n options: NodeHttpClientIntegrationOptions = {},\n): Integration {\n const name = options.name ?? \"node-http-client\";\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;\n const levelFor = options.level ?? defaultLevel;\n\n const shouldCapture = (status: number | undefined, error: unknown) => {\n if (error) return true;\n if (status !== undefined && status >= minStatus) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n return {\n name: \"node-http-client\",\n setup(api: IntegrationSetupContext) {\n const httpModule = options.httpModule === undefined ? loadHttpModule() : options.httpModule;\n const httpsModule =\n options.httpsModule === undefined ? loadHttpsModule() : options.httpsModule;\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n const disposers: Array<() => void> = [];\n let disposed = false;\n\n const captureResult = (\n info: NodeHttpClientRequestInfo,\n status: number | undefined,\n error: unknown,\n responseHeaders?: Record<string, string | string[]>,\n ) => {\n if (disposed || !shouldCapture(status, error)) return;\n capture({\n level: levelFor(status, error, info),\n message: error\n ? `HTTP error ${info.method} ${info.url}`\n : `HTTP ${statusMessage(status)} ${info.method} ${info.url}`,\n error,\n props: {\n http: {\n kind: name,\n runtime: \"node\",\n direction: \"outgoing\",\n protocol: info.protocol,\n method: info.method,\n url: info.url,\n status,\n requestHeaders: info.requestHeaders,\n responseHeaders,\n },\n },\n });\n };\n\n const patchModule = (\n module: NodeHttpModuleLike | null,\n defaultProtocol: \"http:\" | \"https:\",\n ) => {\n if (!module?.request) return;\n const originalRequest = module.request;\n const originalGet = module.get;\n module.request = function patchedRequest(this: unknown, ...args: unknown[]) {\n const info = requestInfo(\n args,\n defaultProtocol,\n sanitizeUrl,\n options.captureRequestHeaders,\n );\n const request = originalRequest.apply(this, args);\n listenOnce(request, \"response\", (message) => {\n const response = message as NodeHttpIncomingMessageLike;\n captureResult(\n info,\n response.statusCode,\n undefined,\n pickHeaders(response.headers, options.captureResponseHeaders),\n );\n });\n listenOnce(request, \"error\", (error) => captureResult(info, undefined, error));\n return request;\n };\n\n if (originalGet) {\n module.get = function patchedGet(this: unknown, ...args: unknown[]) {\n const request = module.request?.apply(this, args) ?? originalGet.apply(this, args);\n request.end?.();\n return request;\n };\n }\n\n disposers.push(() => {\n module.request = originalRequest;\n if (originalGet) module.get = originalGet;\n });\n };\n\n patchModule(httpModule, \"http:\");\n patchModule(httpsModule, \"https:\");\n\n return () => {\n if (disposed) return;\n disposed = true;\n for (const dispose of disposers) dispose();\n };\n },\n };\n}\n"],"mappings":"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"}