@loggerjs/node 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/bullmq-integration.cjs +169 -0
- package/dist/bullmq-integration.cjs.map +1 -0
- package/dist/bullmq-integration.js +168 -0
- package/dist/bullmq-integration.js.map +1 -0
- package/dist/cli-integration.cjs +116 -0
- package/dist/cli-integration.cjs.map +1 -0
- package/dist/cli-integration.js +115 -0
- package/dist/cli-integration.js.map +1 -0
- package/dist/context.cjs +37 -0
- package/dist/context.cjs.map +1 -0
- package/dist/context.js +35 -0
- package/dist/context.js.map +1 -0
- package/dist/database-integration.cjs +128 -0
- package/dist/database-integration.cjs.map +1 -0
- package/dist/database-integration.js +127 -0
- package/dist/database-integration.js.map +1 -0
- package/dist/diagnostics-channel-integration.cjs +66 -0
- package/dist/diagnostics-channel-integration.cjs.map +1 -0
- package/dist/diagnostics-channel-integration.js +65 -0
- package/dist/diagnostics-channel-integration.js.map +1 -0
- package/dist/express-integration.cjs +130 -0
- package/dist/express-integration.cjs.map +1 -0
- package/dist/express-integration.js +129 -0
- package/dist/express-integration.js.map +1 -0
- package/dist/fastify-integration.cjs +120 -0
- package/dist/fastify-integration.cjs.map +1 -0
- package/dist/fastify-integration.js +119 -0
- package/dist/fastify-integration.js.map +1 -0
- package/dist/file-transport.cjs +260 -0
- package/dist/file-transport.cjs.map +1 -0
- package/dist/file-transport.js +259 -0
- package/dist/file-transport.js.map +1 -0
- package/dist/hapi-integration.cjs +61 -0
- package/dist/hapi-integration.cjs.map +1 -0
- package/dist/hapi-integration.js +60 -0
- package/dist/hapi-integration.js.map +1 -0
- package/dist/http-transport.cjs +55 -0
- package/dist/http-transport.cjs.map +1 -0
- package/dist/http-transport.js +54 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/koa-integration.cjs +57 -0
- package/dist/koa-integration.cjs.map +1 -0
- package/dist/koa-integration.js +56 -0
- package/dist/koa-integration.js.map +1 -0
- package/dist/logger-diagnostics.cjs +46 -0
- package/dist/logger-diagnostics.cjs.map +1 -0
- package/dist/logger-diagnostics.js +45 -0
- package/dist/logger-diagnostics.js.map +1 -0
- package/dist/nest-integration.cjs +138 -0
- package/dist/nest-integration.cjs.map +1 -0
- package/dist/nest-integration.js +137 -0
- package/dist/nest-integration.js.map +1 -0
- package/dist/node-fetch-integration.cjs +113 -0
- package/dist/node-fetch-integration.cjs.map +1 -0
- package/dist/node-fetch-integration.js +112 -0
- package/dist/node-fetch-integration.js.map +1 -0
- package/dist/node-http-client-integration.cjs +192 -0
- package/dist/node-http-client-integration.cjs.map +1 -0
- package/dist/node-http-client-integration.js +192 -0
- package/dist/node-http-client-integration.js.map +1 -0
- package/dist/payload-transforms.cjs +29 -0
- package/dist/payload-transforms.cjs.map +1 -0
- package/dist/payload-transforms.js +28 -0
- package/dist/payload-transforms.js.map +1 -0
- package/dist/prisma-integration.cjs +150 -0
- package/dist/prisma-integration.cjs.map +1 -0
- package/dist/prisma-integration.js +149 -0
- package/dist/prisma-integration.js.map +1 -0
- package/dist/process-integration.cjs +134 -0
- package/dist/process-integration.cjs.map +1 -0
- package/dist/process-integration.js +133 -0
- package/dist/process-integration.js.map +1 -0
- package/dist/queue-integration.cjs +148 -0
- package/dist/queue-integration.cjs.map +1 -0
- package/dist/queue-integration.js +147 -0
- package/dist/queue-integration.js.map +1 -0
- package/dist/redis-integration.cjs +154 -0
- package/dist/redis-integration.cjs.map +1 -0
- package/dist/redis-integration.js +153 -0
- package/dist/redis-integration.js.map +1 -0
- package/dist/rotating-file-transport.cjs +318 -0
- package/dist/rotating-file-transport.cjs.map +1 -0
- package/dist/rotating-file-transport.js +317 -0
- package/dist/rotating-file-transport.js.map +1 -0
- package/dist/serverless-integration.cjs +104 -0
- package/dist/serverless-integration.cjs.map +1 -0
- package/dist/serverless-integration.js +103 -0
- package/dist/serverless-integration.js.map +1 -0
- package/dist/stdout-transport.cjs +197 -0
- package/dist/stdout-transport.cjs.map +1 -0
- package/dist/stdout-transport.js +195 -0
- package/dist/stdout-transport.js.map +1 -0
- package/dist/syslog-transport.cjs +135 -0
- package/dist/syslog-transport.cjs.map +1 -0
- package/dist/syslog-transport.js +133 -0
- package/dist/syslog-transport.js.map +1 -0
- package/dist/worker-transport.cjs +285 -0
- package/dist/worker-transport.cjs.map +1 -0
- package/dist/worker-transport.js +284 -0
- package/dist/worker-transport.js.map +1 -0
- package/package.json +104 -77
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
//#region src/node-http-client-integration.ts
|
|
3
|
+
const requireBuiltin = createRequire(import.meta.url);
|
|
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
|
+
export { nodeHttpClientIntegration };
|
|
191
|
+
|
|
192
|
+
//# sourceMappingURL=node-http-client-integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-http-client-integration.js","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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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let node_zlib = require("node:zlib");
|
|
3
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
4
|
+
//#region src/payload-transforms.ts
|
|
5
|
+
const contentEncodingByFormat = {
|
|
6
|
+
gzip: "gzip",
|
|
7
|
+
brotli: "br",
|
|
8
|
+
deflate: "deflate"
|
|
9
|
+
};
|
|
10
|
+
function compressPayload(payload, format, options) {
|
|
11
|
+
const input = (0, _loggerjs_core.encodedPayloadToUint8Array)(payload);
|
|
12
|
+
if (format === "brotli") return Uint8Array.from((0, node_zlib.brotliCompressSync)(input, options.brotliOptions));
|
|
13
|
+
if (format === "deflate") return Uint8Array.from((0, node_zlib.deflateSync)(input, options.deflateOptions));
|
|
14
|
+
return Uint8Array.from((0, node_zlib.gzipSync)(input, options.gzipOptions));
|
|
15
|
+
}
|
|
16
|
+
function nodeCompressionPayloadTransform(options = {}) {
|
|
17
|
+
const format = options.format ?? "gzip";
|
|
18
|
+
return (payload) => ({
|
|
19
|
+
payload: compressPayload(payload, format, options),
|
|
20
|
+
headers: {
|
|
21
|
+
"content-encoding": contentEncodingByFormat[format],
|
|
22
|
+
...options.headers
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.nodeCompressionPayloadTransform = nodeCompressionPayloadTransform;
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=payload-transforms.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-transforms.cjs","names":[],"sources":["../src/payload-transforms.ts"],"sourcesContent":["import {\n brotliCompressSync,\n deflateSync,\n gzipSync,\n type BrotliOptions,\n type ZlibOptions,\n} from \"node:zlib\";\nimport {\n encodedPayloadToUint8Array,\n type EncodedPayload,\n type PayloadTransform,\n} from \"@loggerjs/core\";\n\nexport type NodeCompressionFormat = \"gzip\" | \"brotli\" | \"deflate\";\n\nexport interface NodeCompressionPayloadTransformOptions {\n format?: NodeCompressionFormat;\n gzipOptions?: ZlibOptions;\n brotliOptions?: BrotliOptions;\n deflateOptions?: ZlibOptions;\n headers?: Record<string, string>;\n}\n\nconst contentEncodingByFormat: Record<NodeCompressionFormat, string> = {\n gzip: \"gzip\",\n brotli: \"br\",\n deflate: \"deflate\",\n};\n\nfunction compressPayload(\n payload: EncodedPayload,\n format: NodeCompressionFormat,\n options: NodeCompressionPayloadTransformOptions,\n): Uint8Array {\n const input = encodedPayloadToUint8Array(payload);\n if (format === \"brotli\") return Uint8Array.from(brotliCompressSync(input, options.brotliOptions));\n if (format === \"deflate\") return Uint8Array.from(deflateSync(input, options.deflateOptions));\n return Uint8Array.from(gzipSync(input, options.gzipOptions));\n}\n\nexport function nodeCompressionPayloadTransform(\n options: NodeCompressionPayloadTransformOptions = {},\n): PayloadTransform {\n const format = options.format ?? \"gzip\";\n return (payload) => ({\n payload: compressPayload(payload, format, options),\n headers: {\n \"content-encoding\": contentEncodingByFormat[format],\n ...options.headers,\n },\n });\n}\n"],"mappings":";;;;AAuBA,MAAM,0BAAiE;CACrE,MAAM;CACN,QAAQ;CACR,SAAS;AACX;AAEA,SAAS,gBACP,SACA,QACA,SACY;CACZ,MAAM,SAAA,GAAA,eAAA,2BAAA,CAAmC,OAAO;CAChD,IAAI,WAAW,UAAU,OAAO,WAAW,MAAA,GAAA,UAAA,mBAAA,CAAwB,OAAO,QAAQ,aAAa,CAAC;CAChG,IAAI,WAAW,WAAW,OAAO,WAAW,MAAA,GAAA,UAAA,YAAA,CAAiB,OAAO,QAAQ,cAAc,CAAC;CAC3F,OAAO,WAAW,MAAA,GAAA,UAAA,SAAA,CAAc,OAAO,QAAQ,WAAW,CAAC;AAC7D;AAEA,SAAgB,gCACd,UAAkD,CAAC,GACjC;CAClB,MAAM,SAAS,QAAQ,UAAU;CACjC,QAAQ,aAAa;EACnB,SAAS,gBAAgB,SAAS,QAAQ,OAAO;EACjD,SAAS;GACP,oBAAoB,wBAAwB;GAC5C,GAAG,QAAQ;EACb;CACF;AACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
|
|
2
|
+
import { encodedPayloadToUint8Array } from "@loggerjs/core";
|
|
3
|
+
//#region src/payload-transforms.ts
|
|
4
|
+
const contentEncodingByFormat = {
|
|
5
|
+
gzip: "gzip",
|
|
6
|
+
brotli: "br",
|
|
7
|
+
deflate: "deflate"
|
|
8
|
+
};
|
|
9
|
+
function compressPayload(payload, format, options) {
|
|
10
|
+
const input = encodedPayloadToUint8Array(payload);
|
|
11
|
+
if (format === "brotli") return Uint8Array.from(brotliCompressSync(input, options.brotliOptions));
|
|
12
|
+
if (format === "deflate") return Uint8Array.from(deflateSync(input, options.deflateOptions));
|
|
13
|
+
return Uint8Array.from(gzipSync(input, options.gzipOptions));
|
|
14
|
+
}
|
|
15
|
+
function nodeCompressionPayloadTransform(options = {}) {
|
|
16
|
+
const format = options.format ?? "gzip";
|
|
17
|
+
return (payload) => ({
|
|
18
|
+
payload: compressPayload(payload, format, options),
|
|
19
|
+
headers: {
|
|
20
|
+
"content-encoding": contentEncodingByFormat[format],
|
|
21
|
+
...options.headers
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { nodeCompressionPayloadTransform };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=payload-transforms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-transforms.js","names":[],"sources":["../src/payload-transforms.ts"],"sourcesContent":["import {\n brotliCompressSync,\n deflateSync,\n gzipSync,\n type BrotliOptions,\n type ZlibOptions,\n} from \"node:zlib\";\nimport {\n encodedPayloadToUint8Array,\n type EncodedPayload,\n type PayloadTransform,\n} from \"@loggerjs/core\";\n\nexport type NodeCompressionFormat = \"gzip\" | \"brotli\" | \"deflate\";\n\nexport interface NodeCompressionPayloadTransformOptions {\n format?: NodeCompressionFormat;\n gzipOptions?: ZlibOptions;\n brotliOptions?: BrotliOptions;\n deflateOptions?: ZlibOptions;\n headers?: Record<string, string>;\n}\n\nconst contentEncodingByFormat: Record<NodeCompressionFormat, string> = {\n gzip: \"gzip\",\n brotli: \"br\",\n deflate: \"deflate\",\n};\n\nfunction compressPayload(\n payload: EncodedPayload,\n format: NodeCompressionFormat,\n options: NodeCompressionPayloadTransformOptions,\n): Uint8Array {\n const input = encodedPayloadToUint8Array(payload);\n if (format === \"brotli\") return Uint8Array.from(brotliCompressSync(input, options.brotliOptions));\n if (format === \"deflate\") return Uint8Array.from(deflateSync(input, options.deflateOptions));\n return Uint8Array.from(gzipSync(input, options.gzipOptions));\n}\n\nexport function nodeCompressionPayloadTransform(\n options: NodeCompressionPayloadTransformOptions = {},\n): PayloadTransform {\n const format = options.format ?? \"gzip\";\n return (payload) => ({\n payload: compressPayload(payload, format, options),\n headers: {\n \"content-encoding\": contentEncodingByFormat[format],\n ...options.headers,\n },\n });\n}\n"],"mappings":";;;AAuBA,MAAM,0BAAiE;CACrE,MAAM;CACN,QAAQ;CACR,SAAS;AACX;AAEA,SAAS,gBACP,SACA,QACA,SACY;CACZ,MAAM,QAAQ,2BAA2B,OAAO;CAChD,IAAI,WAAW,UAAU,OAAO,WAAW,KAAK,mBAAmB,OAAO,QAAQ,aAAa,CAAC;CAChG,IAAI,WAAW,WAAW,OAAO,WAAW,KAAK,YAAY,OAAO,QAAQ,cAAc,CAAC;CAC3F,OAAO,WAAW,KAAK,SAAS,OAAO,QAAQ,WAAW,CAAC;AAC7D;AAEA,SAAgB,gCACd,UAAkD,CAAC,GACjC;CAClB,MAAM,SAAS,QAAQ,UAAU;CACjC,QAAQ,aAAa;EACnB,SAAS,gBAAgB,SAAS,QAAQ,OAAO;EACjD,SAAS;GACP,oBAAoB,wBAAwB;GAC5C,GAAG,QAAQ;EACb;CACF;AACF"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
//#region src/database-integration.ts
|
|
4
|
+
const defaultMethods = [
|
|
5
|
+
"query",
|
|
6
|
+
"execute",
|
|
7
|
+
"run",
|
|
8
|
+
"all",
|
|
9
|
+
"get"
|
|
10
|
+
];
|
|
11
|
+
const defaultRandom = () => Math.random();
|
|
12
|
+
function defaultLevel(_durationMs, error) {
|
|
13
|
+
return error ? "error" : "debug";
|
|
14
|
+
}
|
|
15
|
+
function isPromiseLike(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
17
|
+
}
|
|
18
|
+
function defaultStatement(args) {
|
|
19
|
+
const first = args[0];
|
|
20
|
+
if (typeof first === "string") return first;
|
|
21
|
+
if (typeof first !== "object" || first === null) return void 0;
|
|
22
|
+
const input = first;
|
|
23
|
+
if (typeof input.sql === "string") return input.sql;
|
|
24
|
+
if (typeof input.text === "string") return input.text;
|
|
25
|
+
if (typeof input.query === "string") return input.query;
|
|
26
|
+
}
|
|
27
|
+
function statementFor(args, method, options) {
|
|
28
|
+
const statement = options.getStatement?.(args, method) ?? defaultStatement(args);
|
|
29
|
+
return statement && options.sanitizeStatement ? options.sanitizeStatement(statement) : statement;
|
|
30
|
+
}
|
|
31
|
+
function parametersFor(args, captureParameters) {
|
|
32
|
+
if (!captureParameters) return void 0;
|
|
33
|
+
const first = args[0];
|
|
34
|
+
const parameters = args[1] ?? (typeof first === "object" && first ? first.values ?? first.params ?? first.parameters : void 0);
|
|
35
|
+
return parameters === void 0 ? void 0 : (0, _loggerjs_core.normalizeValue)(parameters, {
|
|
36
|
+
maxDepth: 4,
|
|
37
|
+
maxObjectKeys: 80
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function databaseIntegration(options = {}) {
|
|
41
|
+
const targets = options.targets ?? (options.client ? [{
|
|
42
|
+
client: options.client,
|
|
43
|
+
name: options.name,
|
|
44
|
+
system: options.system,
|
|
45
|
+
methods: options.methods
|
|
46
|
+
}] : []);
|
|
47
|
+
const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
|
|
48
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
49
|
+
const random = options.random ?? defaultRandom;
|
|
50
|
+
const levelFor = options.level ?? defaultLevel;
|
|
51
|
+
const shouldCapture = (durationMs, error) => {
|
|
52
|
+
if (error) return true;
|
|
53
|
+
if (options.minDurationMs !== void 0 && durationMs >= options.minDurationMs) return true;
|
|
54
|
+
if (!captureAll) return false;
|
|
55
|
+
return sampleRate >= 1 || random() < sampleRate;
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
name: "database",
|
|
59
|
+
setup(api) {
|
|
60
|
+
const capture = api.guard((input) => api.capture(input));
|
|
61
|
+
const disposers = [];
|
|
62
|
+
let disposed = false;
|
|
63
|
+
const captureResult = (info, started, args, error) => {
|
|
64
|
+
const durationMs = Date.now() - started;
|
|
65
|
+
if (disposed || !shouldCapture(durationMs, error)) return;
|
|
66
|
+
capture({
|
|
67
|
+
level: levelFor(durationMs, error, info),
|
|
68
|
+
message: error ? `Database error ${info.method}${info.statement ? ` ${info.statement}` : ""}` : `Database ${info.method}${info.statement ? ` ${info.statement}` : ""}`,
|
|
69
|
+
error,
|
|
70
|
+
props: { db: {
|
|
71
|
+
kind: info.target,
|
|
72
|
+
system: info.system,
|
|
73
|
+
method: info.method,
|
|
74
|
+
statement: info.statement,
|
|
75
|
+
durationMs,
|
|
76
|
+
parameters: parametersFor(args, options.captureParameters ?? false)
|
|
77
|
+
} }
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
for (const target of targets) {
|
|
81
|
+
const methods = target.methods ?? options.methods ?? defaultMethods;
|
|
82
|
+
for (const method of methods) {
|
|
83
|
+
const original = target.client[method];
|
|
84
|
+
if (typeof original !== "function") continue;
|
|
85
|
+
const originalMethod = original;
|
|
86
|
+
const targetName = target.name ?? options.name ?? "database";
|
|
87
|
+
const system = target.system ?? options.system;
|
|
88
|
+
target.client[method] = function wrappedDatabaseMethod(...args) {
|
|
89
|
+
const started = Date.now();
|
|
90
|
+
const info = {
|
|
91
|
+
target: targetName,
|
|
92
|
+
system,
|
|
93
|
+
method,
|
|
94
|
+
statement: statementFor(args, method, options)
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
const result = originalMethod.apply(this, args);
|
|
98
|
+
if (isPromiseLike(result)) return result.then((value) => {
|
|
99
|
+
captureResult(info, started, args, void 0);
|
|
100
|
+
return value;
|
|
101
|
+
}, (error) => {
|
|
102
|
+
captureResult(info, started, args, error);
|
|
103
|
+
throw error;
|
|
104
|
+
});
|
|
105
|
+
captureResult(info, started, args, void 0);
|
|
106
|
+
return result;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
captureResult(info, started, args, error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
disposers.push(() => {
|
|
113
|
+
target.client[method] = originalMethod;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return () => {
|
|
118
|
+
if (disposed) return;
|
|
119
|
+
disposed = true;
|
|
120
|
+
for (const dispose of disposers) dispose();
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/prisma-integration.ts
|
|
127
|
+
const prismaMethods = [
|
|
128
|
+
"$executeRaw",
|
|
129
|
+
"$executeRawUnsafe",
|
|
130
|
+
"$queryRaw",
|
|
131
|
+
"$queryRawUnsafe"
|
|
132
|
+
];
|
|
133
|
+
function prismaStatement(args) {
|
|
134
|
+
const first = args[0];
|
|
135
|
+
if (typeof first === "string") return first;
|
|
136
|
+
if (Array.isArray(first) && "raw" in first) return first.raw?.join("?");
|
|
137
|
+
}
|
|
138
|
+
function prismaIntegration(options) {
|
|
139
|
+
return databaseIntegration({
|
|
140
|
+
...options,
|
|
141
|
+
name: options.name ?? "prisma",
|
|
142
|
+
system: "prisma",
|
|
143
|
+
methods: prismaMethods,
|
|
144
|
+
getStatement: prismaStatement
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
exports.prismaIntegration = prismaIntegration;
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=prisma-integration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-integration.cjs","names":[],"sources":["../src/database-integration.ts","../src/prisma-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type LoggerLevel,\n} from \"@loggerjs/core\";\n\nexport interface DatabaseClientLike {\n [method: string]: unknown;\n}\n\nexport interface DatabaseIntegrationTarget {\n client: DatabaseClientLike;\n name?: string;\n system?: string;\n methods?: readonly string[];\n}\n\nexport interface DatabaseOperationInfo {\n target: string;\n system?: string;\n method: string;\n statement?: string;\n}\n\nexport interface DatabaseIntegrationOptions {\n client?: DatabaseClientLike;\n targets?: readonly DatabaseIntegrationTarget[];\n name?: string;\n system?: string;\n methods?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n minDurationMs?: number;\n sampleRate?: number;\n random?: () => number;\n captureParameters?: boolean;\n sanitizeStatement?: (statement: string) => string;\n getStatement?: (args: readonly unknown[], method: string) => string | undefined;\n level?: (durationMs: number, error: unknown, info: DatabaseOperationInfo) => LoggerLevel;\n}\n\ntype DatabaseMethod = (this: unknown, ...args: unknown[]) => unknown;\n\nconst defaultMethods = [\"query\", \"execute\", \"run\", \"all\", \"get\"] as const;\nconst defaultRandom = () => Math.random();\n\nfunction defaultLevel(_durationMs: number, error: unknown): LoggerLevel {\n return error ? \"error\" : \"debug\";\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\nfunction defaultStatement(args: readonly unknown[]): string | undefined {\n const first = args[0];\n if (typeof first === \"string\") return first;\n if (typeof first !== \"object\" || first === null) return undefined;\n const input = first as { sql?: unknown; text?: unknown; query?: unknown };\n if (typeof input.sql === \"string\") return input.sql;\n if (typeof input.text === \"string\") return input.text;\n if (typeof input.query === \"string\") return input.query;\n return undefined;\n}\n\nfunction statementFor(\n args: readonly unknown[],\n method: string,\n options: DatabaseIntegrationOptions,\n) {\n const statement = options.getStatement?.(args, method) ?? defaultStatement(args);\n return statement && options.sanitizeStatement ? options.sanitizeStatement(statement) : statement;\n}\n\nfunction parametersFor(args: readonly unknown[], captureParameters: boolean) {\n if (!captureParameters) return undefined;\n const first = args[0];\n const second = args[1];\n const parameters =\n second ??\n (typeof first === \"object\" && first\n ? ((first as { values?: unknown; params?: unknown; parameters?: unknown }).values ??\n (first as { params?: unknown }).params ??\n (first as { parameters?: unknown }).parameters)\n : undefined);\n return parameters === undefined\n ? undefined\n : normalizeValue(parameters, { maxDepth: 4, maxObjectKeys: 80 });\n}\n\nexport function databaseIntegration(options: DatabaseIntegrationOptions = {}): Integration {\n const targets =\n options.targets ??\n (options.client\n ? [\n {\n client: options.client,\n name: options.name,\n system: options.system,\n methods: options.methods,\n },\n ]\n : []);\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const levelFor = options.level ?? defaultLevel;\n\n const shouldCapture = (durationMs: number, error: unknown) => {\n if (error) return true;\n if (options.minDurationMs !== undefined && durationMs >= options.minDurationMs) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n return {\n name: \"database\",\n setup(api: IntegrationSetupContext) {\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: DatabaseOperationInfo,\n started: number,\n args: readonly unknown[],\n error: unknown,\n ) => {\n const durationMs = Date.now() - started;\n if (disposed || !shouldCapture(durationMs, error)) return;\n capture({\n level: levelFor(durationMs, error, info),\n message: error\n ? `Database error ${info.method}${info.statement ? ` ${info.statement}` : \"\"}`\n : `Database ${info.method}${info.statement ? ` ${info.statement}` : \"\"}`,\n error,\n props: {\n db: {\n kind: info.target,\n system: info.system,\n method: info.method,\n statement: info.statement,\n durationMs,\n parameters: parametersFor(args, options.captureParameters ?? false),\n },\n },\n });\n };\n\n for (const target of targets) {\n const methods = target.methods ?? options.methods ?? defaultMethods;\n for (const method of methods) {\n const original = target.client[method];\n if (typeof original !== \"function\") continue;\n const originalMethod = original as DatabaseMethod;\n const targetName = target.name ?? options.name ?? \"database\";\n const system = target.system ?? options.system;\n\n target.client[method] = function wrappedDatabaseMethod(\n this: unknown,\n ...args: unknown[]\n ) {\n const started = Date.now();\n const info: DatabaseOperationInfo = {\n target: targetName,\n system,\n method,\n statement: statementFor(args, method, options),\n };\n try {\n const result = originalMethod.apply(this, args);\n if (isPromiseLike(result)) {\n return result.then(\n (value) => {\n captureResult(info, started, args, undefined);\n return value;\n },\n (error) => {\n captureResult(info, started, args, error);\n throw error;\n },\n );\n }\n captureResult(info, started, args, undefined);\n return result;\n } catch (error) {\n captureResult(info, started, args, error);\n throw error;\n }\n };\n\n disposers.push(() => {\n target.client[method] = originalMethod;\n });\n }\n }\n\n return () => {\n if (disposed) return;\n disposed = true;\n for (const dispose of disposers) dispose();\n };\n },\n };\n}\n","import {\n databaseIntegration,\n type DatabaseClientLike,\n type DatabaseIntegrationOptions,\n} from \"./database-integration\";\n\nexport interface PrismaIntegrationOptions extends Omit<\n DatabaseIntegrationOptions,\n \"client\" | \"system\" | \"methods\" | \"getStatement\"\n> {\n client: DatabaseClientLike;\n}\n\nconst prismaMethods = [\"$executeRaw\", \"$executeRawUnsafe\", \"$queryRaw\", \"$queryRawUnsafe\"] as const;\n\nfunction prismaStatement(args: readonly unknown[]): string | undefined {\n const first = args[0];\n if (typeof first === \"string\") return first;\n if (Array.isArray(first) && \"raw\" in first) return (first as { raw?: string[] }).raw?.join(\"?\");\n return undefined;\n}\n\nexport function prismaIntegration(options: PrismaIntegrationOptions) {\n return databaseIntegration({\n ...options,\n name: options.name ?? \"prisma\",\n system: \"prisma\",\n methods: prismaMethods,\n getStatement: prismaStatement,\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { normalizeValue } from "@loggerjs/core";
|
|
2
|
+
//#region src/database-integration.ts
|
|
3
|
+
const defaultMethods = [
|
|
4
|
+
"query",
|
|
5
|
+
"execute",
|
|
6
|
+
"run",
|
|
7
|
+
"all",
|
|
8
|
+
"get"
|
|
9
|
+
];
|
|
10
|
+
const defaultRandom = () => Math.random();
|
|
11
|
+
function defaultLevel(_durationMs, error) {
|
|
12
|
+
return error ? "error" : "debug";
|
|
13
|
+
}
|
|
14
|
+
function isPromiseLike(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
16
|
+
}
|
|
17
|
+
function defaultStatement(args) {
|
|
18
|
+
const first = args[0];
|
|
19
|
+
if (typeof first === "string") return first;
|
|
20
|
+
if (typeof first !== "object" || first === null) return void 0;
|
|
21
|
+
const input = first;
|
|
22
|
+
if (typeof input.sql === "string") return input.sql;
|
|
23
|
+
if (typeof input.text === "string") return input.text;
|
|
24
|
+
if (typeof input.query === "string") return input.query;
|
|
25
|
+
}
|
|
26
|
+
function statementFor(args, method, options) {
|
|
27
|
+
const statement = options.getStatement?.(args, method) ?? defaultStatement(args);
|
|
28
|
+
return statement && options.sanitizeStatement ? options.sanitizeStatement(statement) : statement;
|
|
29
|
+
}
|
|
30
|
+
function parametersFor(args, captureParameters) {
|
|
31
|
+
if (!captureParameters) return void 0;
|
|
32
|
+
const first = args[0];
|
|
33
|
+
const parameters = args[1] ?? (typeof first === "object" && first ? first.values ?? first.params ?? first.parameters : void 0);
|
|
34
|
+
return parameters === void 0 ? void 0 : normalizeValue(parameters, {
|
|
35
|
+
maxDepth: 4,
|
|
36
|
+
maxObjectKeys: 80
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function databaseIntegration(options = {}) {
|
|
40
|
+
const targets = options.targets ?? (options.client ? [{
|
|
41
|
+
client: options.client,
|
|
42
|
+
name: options.name,
|
|
43
|
+
system: options.system,
|
|
44
|
+
methods: options.methods
|
|
45
|
+
}] : []);
|
|
46
|
+
const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
|
|
47
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
48
|
+
const random = options.random ?? defaultRandom;
|
|
49
|
+
const levelFor = options.level ?? defaultLevel;
|
|
50
|
+
const shouldCapture = (durationMs, error) => {
|
|
51
|
+
if (error) return true;
|
|
52
|
+
if (options.minDurationMs !== void 0 && durationMs >= options.minDurationMs) return true;
|
|
53
|
+
if (!captureAll) return false;
|
|
54
|
+
return sampleRate >= 1 || random() < sampleRate;
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
name: "database",
|
|
58
|
+
setup(api) {
|
|
59
|
+
const capture = api.guard((input) => api.capture(input));
|
|
60
|
+
const disposers = [];
|
|
61
|
+
let disposed = false;
|
|
62
|
+
const captureResult = (info, started, args, error) => {
|
|
63
|
+
const durationMs = Date.now() - started;
|
|
64
|
+
if (disposed || !shouldCapture(durationMs, error)) return;
|
|
65
|
+
capture({
|
|
66
|
+
level: levelFor(durationMs, error, info),
|
|
67
|
+
message: error ? `Database error ${info.method}${info.statement ? ` ${info.statement}` : ""}` : `Database ${info.method}${info.statement ? ` ${info.statement}` : ""}`,
|
|
68
|
+
error,
|
|
69
|
+
props: { db: {
|
|
70
|
+
kind: info.target,
|
|
71
|
+
system: info.system,
|
|
72
|
+
method: info.method,
|
|
73
|
+
statement: info.statement,
|
|
74
|
+
durationMs,
|
|
75
|
+
parameters: parametersFor(args, options.captureParameters ?? false)
|
|
76
|
+
} }
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
for (const target of targets) {
|
|
80
|
+
const methods = target.methods ?? options.methods ?? defaultMethods;
|
|
81
|
+
for (const method of methods) {
|
|
82
|
+
const original = target.client[method];
|
|
83
|
+
if (typeof original !== "function") continue;
|
|
84
|
+
const originalMethod = original;
|
|
85
|
+
const targetName = target.name ?? options.name ?? "database";
|
|
86
|
+
const system = target.system ?? options.system;
|
|
87
|
+
target.client[method] = function wrappedDatabaseMethod(...args) {
|
|
88
|
+
const started = Date.now();
|
|
89
|
+
const info = {
|
|
90
|
+
target: targetName,
|
|
91
|
+
system,
|
|
92
|
+
method,
|
|
93
|
+
statement: statementFor(args, method, options)
|
|
94
|
+
};
|
|
95
|
+
try {
|
|
96
|
+
const result = originalMethod.apply(this, args);
|
|
97
|
+
if (isPromiseLike(result)) return result.then((value) => {
|
|
98
|
+
captureResult(info, started, args, void 0);
|
|
99
|
+
return value;
|
|
100
|
+
}, (error) => {
|
|
101
|
+
captureResult(info, started, args, error);
|
|
102
|
+
throw error;
|
|
103
|
+
});
|
|
104
|
+
captureResult(info, started, args, void 0);
|
|
105
|
+
return result;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
captureResult(info, started, args, error);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
disposers.push(() => {
|
|
112
|
+
target.client[method] = originalMethod;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return () => {
|
|
117
|
+
if (disposed) return;
|
|
118
|
+
disposed = true;
|
|
119
|
+
for (const dispose of disposers) dispose();
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/prisma-integration.ts
|
|
126
|
+
const prismaMethods = [
|
|
127
|
+
"$executeRaw",
|
|
128
|
+
"$executeRawUnsafe",
|
|
129
|
+
"$queryRaw",
|
|
130
|
+
"$queryRawUnsafe"
|
|
131
|
+
];
|
|
132
|
+
function prismaStatement(args) {
|
|
133
|
+
const first = args[0];
|
|
134
|
+
if (typeof first === "string") return first;
|
|
135
|
+
if (Array.isArray(first) && "raw" in first) return first.raw?.join("?");
|
|
136
|
+
}
|
|
137
|
+
function prismaIntegration(options) {
|
|
138
|
+
return databaseIntegration({
|
|
139
|
+
...options,
|
|
140
|
+
name: options.name ?? "prisma",
|
|
141
|
+
system: "prisma",
|
|
142
|
+
methods: prismaMethods,
|
|
143
|
+
getStatement: prismaStatement
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { prismaIntegration };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=prisma-integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-integration.js","names":[],"sources":["../src/database-integration.ts","../src/prisma-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type LoggerLevel,\n} from \"@loggerjs/core\";\n\nexport interface DatabaseClientLike {\n [method: string]: unknown;\n}\n\nexport interface DatabaseIntegrationTarget {\n client: DatabaseClientLike;\n name?: string;\n system?: string;\n methods?: readonly string[];\n}\n\nexport interface DatabaseOperationInfo {\n target: string;\n system?: string;\n method: string;\n statement?: string;\n}\n\nexport interface DatabaseIntegrationOptions {\n client?: DatabaseClientLike;\n targets?: readonly DatabaseIntegrationTarget[];\n name?: string;\n system?: string;\n methods?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n minDurationMs?: number;\n sampleRate?: number;\n random?: () => number;\n captureParameters?: boolean;\n sanitizeStatement?: (statement: string) => string;\n getStatement?: (args: readonly unknown[], method: string) => string | undefined;\n level?: (durationMs: number, error: unknown, info: DatabaseOperationInfo) => LoggerLevel;\n}\n\ntype DatabaseMethod = (this: unknown, ...args: unknown[]) => unknown;\n\nconst defaultMethods = [\"query\", \"execute\", \"run\", \"all\", \"get\"] as const;\nconst defaultRandom = () => Math.random();\n\nfunction defaultLevel(_durationMs: number, error: unknown): LoggerLevel {\n return error ? \"error\" : \"debug\";\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\nfunction defaultStatement(args: readonly unknown[]): string | undefined {\n const first = args[0];\n if (typeof first === \"string\") return first;\n if (typeof first !== \"object\" || first === null) return undefined;\n const input = first as { sql?: unknown; text?: unknown; query?: unknown };\n if (typeof input.sql === \"string\") return input.sql;\n if (typeof input.text === \"string\") return input.text;\n if (typeof input.query === \"string\") return input.query;\n return undefined;\n}\n\nfunction statementFor(\n args: readonly unknown[],\n method: string,\n options: DatabaseIntegrationOptions,\n) {\n const statement = options.getStatement?.(args, method) ?? defaultStatement(args);\n return statement && options.sanitizeStatement ? options.sanitizeStatement(statement) : statement;\n}\n\nfunction parametersFor(args: readonly unknown[], captureParameters: boolean) {\n if (!captureParameters) return undefined;\n const first = args[0];\n const second = args[1];\n const parameters =\n second ??\n (typeof first === \"object\" && first\n ? ((first as { values?: unknown; params?: unknown; parameters?: unknown }).values ??\n (first as { params?: unknown }).params ??\n (first as { parameters?: unknown }).parameters)\n : undefined);\n return parameters === undefined\n ? undefined\n : normalizeValue(parameters, { maxDepth: 4, maxObjectKeys: 80 });\n}\n\nexport function databaseIntegration(options: DatabaseIntegrationOptions = {}): Integration {\n const targets =\n options.targets ??\n (options.client\n ? [\n {\n client: options.client,\n name: options.name,\n system: options.system,\n methods: options.methods,\n },\n ]\n : []);\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const levelFor = options.level ?? defaultLevel;\n\n const shouldCapture = (durationMs: number, error: unknown) => {\n if (error) return true;\n if (options.minDurationMs !== undefined && durationMs >= options.minDurationMs) return true;\n if (!captureAll) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n return {\n name: \"database\",\n setup(api: IntegrationSetupContext) {\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: DatabaseOperationInfo,\n started: number,\n args: readonly unknown[],\n error: unknown,\n ) => {\n const durationMs = Date.now() - started;\n if (disposed || !shouldCapture(durationMs, error)) return;\n capture({\n level: levelFor(durationMs, error, info),\n message: error\n ? `Database error ${info.method}${info.statement ? ` ${info.statement}` : \"\"}`\n : `Database ${info.method}${info.statement ? ` ${info.statement}` : \"\"}`,\n error,\n props: {\n db: {\n kind: info.target,\n system: info.system,\n method: info.method,\n statement: info.statement,\n durationMs,\n parameters: parametersFor(args, options.captureParameters ?? false),\n },\n },\n });\n };\n\n for (const target of targets) {\n const methods = target.methods ?? options.methods ?? defaultMethods;\n for (const method of methods) {\n const original = target.client[method];\n if (typeof original !== \"function\") continue;\n const originalMethod = original as DatabaseMethod;\n const targetName = target.name ?? options.name ?? \"database\";\n const system = target.system ?? options.system;\n\n target.client[method] = function wrappedDatabaseMethod(\n this: unknown,\n ...args: unknown[]\n ) {\n const started = Date.now();\n const info: DatabaseOperationInfo = {\n target: targetName,\n system,\n method,\n statement: statementFor(args, method, options),\n };\n try {\n const result = originalMethod.apply(this, args);\n if (isPromiseLike(result)) {\n return result.then(\n (value) => {\n captureResult(info, started, args, undefined);\n return value;\n },\n (error) => {\n captureResult(info, started, args, error);\n throw error;\n },\n );\n }\n captureResult(info, started, args, undefined);\n return result;\n } catch (error) {\n captureResult(info, started, args, error);\n throw error;\n }\n };\n\n disposers.push(() => {\n target.client[method] = originalMethod;\n });\n }\n }\n\n return () => {\n if (disposed) return;\n disposed = true;\n for (const dispose of disposers) dispose();\n };\n },\n };\n}\n","import {\n databaseIntegration,\n type DatabaseClientLike,\n type DatabaseIntegrationOptions,\n} from \"./database-integration\";\n\nexport interface PrismaIntegrationOptions extends Omit<\n DatabaseIntegrationOptions,\n \"client\" | \"system\" | \"methods\" | \"getStatement\"\n> {\n client: DatabaseClientLike;\n}\n\nconst prismaMethods = [\"$executeRaw\", \"$executeRawUnsafe\", \"$queryRaw\", \"$queryRawUnsafe\"] as const;\n\nfunction prismaStatement(args: readonly unknown[]): string | undefined {\n const first = args[0];\n if (typeof first === \"string\") return first;\n if (Array.isArray(first) && \"raw\" in first) return (first as { raw?: string[] }).raw?.join(\"?\");\n return undefined;\n}\n\nexport function prismaIntegration(options: PrismaIntegrationOptions) {\n return databaseIntegration({\n ...options,\n name: options.name ?? \"prisma\",\n system: \"prisma\",\n methods: prismaMethods,\n getStatement: prismaStatement,\n });\n}\n"],"mappings":"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"}
|