@loggerjs/node 0.4.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.
- 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,60 @@
|
|
|
1
|
+
import { withContext } from "@loggerjs/core";
|
|
2
|
+
//#region src/hapi-integration.ts
|
|
3
|
+
function responseStatus(response) {
|
|
4
|
+
if (!response) return 200;
|
|
5
|
+
if ("statusCode" in response && typeof response.statusCode === "number") return response.statusCode;
|
|
6
|
+
if ("output" in response && typeof response.output?.statusCode === "number") return response.output.statusCode;
|
|
7
|
+
return 200;
|
|
8
|
+
}
|
|
9
|
+
function levelFor(status) {
|
|
10
|
+
if (status >= 500) return "error";
|
|
11
|
+
if (status >= 400) return "warn";
|
|
12
|
+
return "info";
|
|
13
|
+
}
|
|
14
|
+
function hapiIntegration(logger, options = {}) {
|
|
15
|
+
const minStatus = options.minStatus ?? 400;
|
|
16
|
+
const captureAll = options.captureAll ?? false;
|
|
17
|
+
const bindContext = options.bindContext ?? true;
|
|
18
|
+
const getLevel = options.level ?? levelFor;
|
|
19
|
+
return {
|
|
20
|
+
name: "loggerjs-hapi",
|
|
21
|
+
register(server) {
|
|
22
|
+
server.ext("onRequest", (request, h) => {
|
|
23
|
+
const context = {
|
|
24
|
+
httpMethod: (request.method ?? "GET").toUpperCase(),
|
|
25
|
+
httpUrl: request.url?.pathname ?? request.path ?? "/",
|
|
26
|
+
requestId: options.getRequestId?.(request) ?? request.info?.id,
|
|
27
|
+
...options.context?.(request)
|
|
28
|
+
};
|
|
29
|
+
request.app = {
|
|
30
|
+
...request.app,
|
|
31
|
+
loggerjsStartedAt: Date.now()
|
|
32
|
+
};
|
|
33
|
+
if (bindContext) return withContext(context, () => h.continue);
|
|
34
|
+
return h.continue;
|
|
35
|
+
});
|
|
36
|
+
server.events?.on?.("response", (request) => {
|
|
37
|
+
const status = responseStatus(request.response);
|
|
38
|
+
if (!captureAll && status < minStatus) return;
|
|
39
|
+
const method = (request.method ?? "GET").toUpperCase();
|
|
40
|
+
const url = request.url?.pathname ?? request.path ?? "/";
|
|
41
|
+
const requestId = options.getRequestId?.(request) ?? request.info?.id;
|
|
42
|
+
const started = request.app?.loggerjsStartedAt;
|
|
43
|
+
logger.log(getLevel(status, request), `Hapi ${status} ${method} ${url}`, { http: {
|
|
44
|
+
framework: "hapi",
|
|
45
|
+
kind: "hapi",
|
|
46
|
+
method,
|
|
47
|
+
url,
|
|
48
|
+
status,
|
|
49
|
+
durationMs: started ? Date.now() - started : void 0,
|
|
50
|
+
requestId,
|
|
51
|
+
remoteAddress: request.info?.remoteAddress
|
|
52
|
+
} });
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { hapiIntegration };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=hapi-integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hapi-integration.js","names":[],"sources":["../src/hapi-integration.ts"],"sourcesContent":["import { withContext, type LoggerLevel, type LoggerLike, type LogData } from \"@loggerjs/core\";\n\nexport interface HapiRequestLike {\n method?: string;\n path?: string;\n url?: { pathname?: string };\n info?: { id?: string; received?: number; remoteAddress?: string };\n response?: { statusCode?: number } | { isBoom?: boolean; output?: { statusCode?: number } };\n app?: Record<string, unknown>;\n}\n\nexport interface HapiToolkitLike {\n continue: unknown;\n}\n\nexport interface HapiServerLike {\n ext: (\n event: \"onRequest\",\n handler: (request: HapiRequestLike, h: HapiToolkitLike) => unknown,\n ) => unknown;\n events?: {\n on?: (event: \"response\", handler: (request: HapiRequestLike) => void) => unknown;\n };\n}\n\nexport interface HapiIntegrationOptions {\n minStatus?: number;\n captureAll?: boolean;\n bindContext?: boolean;\n getRequestId?: (request: HapiRequestLike) => string | undefined;\n context?: (request: HapiRequestLike) => Record<string, unknown> | undefined;\n level?: (status: number, request: HapiRequestLike) => LoggerLevel;\n}\n\nfunction responseStatus(response: HapiRequestLike[\"response\"]): number {\n if (!response) return 200;\n if (\"statusCode\" in response && typeof response.statusCode === \"number\")\n return response.statusCode;\n if (\"output\" in response && typeof response.output?.statusCode === \"number\") {\n return response.output.statusCode;\n }\n return 200;\n}\n\nfunction levelFor(status: number): LoggerLevel {\n if (status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nexport function hapiIntegration(logger: LoggerLike, options: HapiIntegrationOptions = {}) {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? false;\n const bindContext = options.bindContext ?? true;\n const getLevel = options.level ?? levelFor;\n\n return {\n name: \"loggerjs-hapi\",\n register(server: HapiServerLike) {\n server.ext(\"onRequest\", (request, h) => {\n const method = (request.method ?? \"GET\").toUpperCase();\n const url = request.url?.pathname ?? request.path ?? \"/\";\n const requestId = options.getRequestId?.(request) ?? request.info?.id;\n const context = {\n httpMethod: method,\n httpUrl: url,\n requestId,\n ...options.context?.(request),\n };\n request.app = { ...request.app, loggerjsStartedAt: Date.now() };\n if (bindContext) return withContext(context, () => h.continue);\n return h.continue;\n });\n\n server.events?.on?.(\"response\", (request) => {\n const status = responseStatus(request.response);\n if (!captureAll && status < minStatus) return;\n const method = (request.method ?? \"GET\").toUpperCase();\n const url = request.url?.pathname ?? request.path ?? \"/\";\n const requestId = options.getRequestId?.(request) ?? request.info?.id;\n const started = request.app?.loggerjsStartedAt as number | undefined;\n logger.log(getLevel(status, request), `Hapi ${status} ${method} ${url}`, {\n http: {\n framework: \"hapi\",\n kind: \"hapi\",\n method,\n url,\n status,\n durationMs: started ? Date.now() - started : undefined,\n requestId,\n remoteAddress: request.info?.remoteAddress,\n },\n } as LogData);\n });\n },\n };\n}\n"],"mappings":";;AAkCA,SAAS,eAAe,UAA+C;CACrE,IAAI,CAAC,UAAU,OAAO;CACtB,IAAI,gBAAgB,YAAY,OAAO,SAAS,eAAe,UAC7D,OAAO,SAAS;CAClB,IAAI,YAAY,YAAY,OAAO,SAAS,QAAQ,eAAe,UACjE,OAAO,SAAS,OAAO;CAEzB,OAAO;AACT;AAEA,SAAS,SAAS,QAA6B;CAC7C,IAAI,UAAU,KAAK,OAAO;CAC1B,IAAI,UAAU,KAAK,OAAO;CAC1B,OAAO;AACT;AAEA,SAAgB,gBAAgB,QAAoB,UAAkC,CAAC,GAAG;CACxF,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,WAAW,QAAQ,SAAS;CAElC,OAAO;EACL,MAAM;EACN,SAAS,QAAwB;GAC/B,OAAO,IAAI,cAAc,SAAS,MAAM;IAItC,MAAM,UAAU;KACd,aAJc,QAAQ,UAAU,MAAA,CAAO,YAItB;KACjB,SAJU,QAAQ,KAAK,YAAY,QAAQ,QAAQ;KAKnD,WAJgB,QAAQ,eAAe,OAAO,KAAK,QAAQ,MAAM;KAKjE,GAAG,QAAQ,UAAU,OAAO;IAC9B;IACA,QAAQ,MAAM;KAAE,GAAG,QAAQ;KAAK,mBAAmB,KAAK,IAAI;IAAE;IAC9D,IAAI,aAAa,OAAO,YAAY,eAAe,EAAE,QAAQ;IAC7D,OAAO,EAAE;GACX,CAAC;GAED,OAAO,QAAQ,KAAK,aAAa,YAAY;IAC3C,MAAM,SAAS,eAAe,QAAQ,QAAQ;IAC9C,IAAI,CAAC,cAAc,SAAS,WAAW;IACvC,MAAM,UAAU,QAAQ,UAAU,MAAA,CAAO,YAAY;IACrD,MAAM,MAAM,QAAQ,KAAK,YAAY,QAAQ,QAAQ;IACrD,MAAM,YAAY,QAAQ,eAAe,OAAO,KAAK,QAAQ,MAAM;IACnE,MAAM,UAAU,QAAQ,KAAK;IAC7B,OAAO,IAAI,SAAS,QAAQ,OAAO,GAAG,QAAQ,OAAO,GAAG,OAAO,GAAG,OAAO,EACvE,MAAM;KACJ,WAAW;KACX,MAAM;KACN;KACA;KACA;KACA,YAAY,UAAU,KAAK,IAAI,IAAI,UAAU,KAAA;KAC7C;KACA,eAAe,QAAQ,MAAM;IAC/B,EACF,CAAY;GACd,CAAC;EACH;CACF;AACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
//#region src/http-transport.ts
|
|
4
|
+
function payloadToBody(payload) {
|
|
5
|
+
if (typeof payload === "string") return payload;
|
|
6
|
+
return Uint8Array.from(payload);
|
|
7
|
+
}
|
|
8
|
+
function nodeHttpTransport(options) {
|
|
9
|
+
const codec = options.codec ?? (0, _loggerjs_core.safeJsonCodec)();
|
|
10
|
+
const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);
|
|
11
|
+
return (0, _loggerjs_core.batchTransport)({
|
|
12
|
+
name: options.name ?? "node-http-inner",
|
|
13
|
+
minLevel: options.minLevel,
|
|
14
|
+
async logBatch(events) {
|
|
15
|
+
if (!fetchFn) throw new Error("fetch is not available. Use Node.js 18+ or pass fetchFn.");
|
|
16
|
+
const transformed = await (0, _loggerjs_core.applyPayloadTransforms)(codec.encode(events), {
|
|
17
|
+
contentType: codec.contentType,
|
|
18
|
+
events,
|
|
19
|
+
transport: options.name ?? "node-http"
|
|
20
|
+
}, options.transformPayload);
|
|
21
|
+
const response = await fetchFn(options.url, {
|
|
22
|
+
method: options.method ?? "POST",
|
|
23
|
+
headers: {
|
|
24
|
+
"content-type": transformed.contentType,
|
|
25
|
+
...transformed.headers,
|
|
26
|
+
...options.headers
|
|
27
|
+
},
|
|
28
|
+
body: payloadToBody(transformed.payload)
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) throw new Error(`nodeHttpTransport failed with status ${response.status}`);
|
|
31
|
+
}
|
|
32
|
+
}, {
|
|
33
|
+
name: options.name ?? "node-http",
|
|
34
|
+
maxRecords: options.maxRecords,
|
|
35
|
+
maxBatchSize: options.maxBatchSize,
|
|
36
|
+
maxBytes: options.maxBytes,
|
|
37
|
+
maxWaitMs: options.maxWaitMs,
|
|
38
|
+
flushIntervalMs: options.flushIntervalMs,
|
|
39
|
+
concurrency: options.concurrency,
|
|
40
|
+
maxQueueSize: options.maxQueueSize,
|
|
41
|
+
dropPolicy: options.dropPolicy,
|
|
42
|
+
estimateEventBytes: options.estimateEventBytes,
|
|
43
|
+
maxRetries: options.maxRetries,
|
|
44
|
+
retryBaseDelayMs: options.retryBaseDelayMs,
|
|
45
|
+
retryMaxDelayMs: options.retryMaxDelayMs,
|
|
46
|
+
random: options.random,
|
|
47
|
+
circuitBreakerFailureThreshold: options.circuitBreakerFailureThreshold,
|
|
48
|
+
circuitBreakerResetMs: options.circuitBreakerResetMs,
|
|
49
|
+
onDrop: options.onDrop
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.nodeHttpTransport = nodeHttpTransport;
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=http-transport.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-transport.cjs","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n applyPayloadTransforms,\n batchTransport,\n safeJsonCodec,\n type BatchTransportOptions,\n type Codec,\n type EncodedPayload,\n type LogEvent,\n type LoggerLevel,\n type PayloadTransform,\n type Transport,\n} from \"@loggerjs/core\";\n\nexport interface NodeHttpTransportOptions extends BatchTransportOptions {\n url: string;\n name?: string;\n method?: \"POST\" | \"PUT\";\n headers?: Record<string, string>;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n fetchFn?: typeof fetch;\n transformPayload?: PayloadTransform | readonly PayloadTransform[];\n}\n\nfunction payloadToBody(payload: EncodedPayload): BodyInit {\n if (typeof payload === \"string\") return payload;\n return Uint8Array.from(payload);\n}\n\nexport function nodeHttpTransport(options: NodeHttpTransportOptions): Transport {\n const codec = options.codec ?? safeJsonCodec();\n const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);\n const inner: Transport = {\n name: options.name ?? \"node-http-inner\",\n minLevel: options.minLevel,\n async logBatch(events: LogEvent[]) {\n if (!fetchFn) throw new Error(\"fetch is not available. Use Node.js 18+ or pass fetchFn.\");\n const encoded = codec.encode(events);\n const transformed = await applyPayloadTransforms(\n encoded,\n {\n contentType: codec.contentType,\n events,\n transport: options.name ?? \"node-http\",\n },\n options.transformPayload,\n );\n const response = await fetchFn(options.url, {\n method: options.method ?? \"POST\",\n headers: {\n \"content-type\": transformed.contentType,\n ...transformed.headers,\n ...options.headers,\n },\n body: payloadToBody(transformed.payload),\n });\n if (!response.ok) throw new Error(`nodeHttpTransport failed with status ${response.status}`);\n },\n };\n return batchTransport(inner, {\n name: options.name ?? \"node-http\",\n maxRecords: options.maxRecords,\n maxBatchSize: options.maxBatchSize,\n maxBytes: options.maxBytes,\n maxWaitMs: options.maxWaitMs,\n flushIntervalMs: options.flushIntervalMs,\n concurrency: options.concurrency,\n maxQueueSize: options.maxQueueSize,\n dropPolicy: options.dropPolicy,\n estimateEventBytes: options.estimateEventBytes,\n maxRetries: options.maxRetries,\n retryBaseDelayMs: options.retryBaseDelayMs,\n retryMaxDelayMs: options.retryMaxDelayMs,\n random: options.random,\n circuitBreakerFailureThreshold: options.circuitBreakerFailureThreshold,\n circuitBreakerResetMs: options.circuitBreakerResetMs,\n onDrop: options.onDrop,\n });\n}\n"],"mappings":";;;AAwBA,SAAS,cAAc,SAAmC;CACxD,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,OAAO,WAAW,KAAK,OAAO;AAChC;AAEA,SAAgB,kBAAkB,SAA8C;CAC9E,MAAM,QAAQ,QAAQ,UAAA,GAAA,eAAA,cAAA,CAAuB;CAC7C,MAAM,UAAU,QAAQ,WAAW,WAAW,OAAO,KAAK,UAAU;CA4BpE,QAAA,GAAA,eAAA,eAAA,CAAsB;EA1BpB,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ;EAClB,MAAM,SAAS,QAAoB;GACjC,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,0DAA0D;GAExF,MAAM,cAAc,OAAA,GAAA,eAAA,uBAAA,CADJ,MAAM,OAAO,MAErB,GACN;IACE,aAAa,MAAM;IACnB;IACA,WAAW,QAAQ,QAAQ;GAC7B,GACA,QAAQ,gBACV;GACA,MAAM,WAAW,MAAM,QAAQ,QAAQ,KAAK;IAC1C,QAAQ,QAAQ,UAAU;IAC1B,SAAS;KACP,gBAAgB,YAAY;KAC5B,GAAG,YAAY;KACf,GAAG,QAAQ;IACb;IACA,MAAM,cAAc,YAAY,OAAO;GACzC,CAAC;GACD,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,wCAAwC,SAAS,QAAQ;EAC7F;CAEwB,GAAG;EAC3B,MAAM,QAAQ,QAAQ;EACtB,YAAY,QAAQ;EACpB,cAAc,QAAQ;EACtB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACnB,iBAAiB,QAAQ;EACzB,aAAa,QAAQ;EACrB,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACpB,oBAAoB,QAAQ;EAC5B,YAAY,QAAQ;EACpB,kBAAkB,QAAQ;EAC1B,iBAAiB,QAAQ;EACzB,QAAQ,QAAQ;EAChB,gCAAgC,QAAQ;EACxC,uBAAuB,QAAQ;EAC/B,QAAQ,QAAQ;CAClB,CAAC;AACH"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { applyPayloadTransforms, batchTransport, safeJsonCodec } from "@loggerjs/core";
|
|
2
|
+
//#region src/http-transport.ts
|
|
3
|
+
function payloadToBody(payload) {
|
|
4
|
+
if (typeof payload === "string") return payload;
|
|
5
|
+
return Uint8Array.from(payload);
|
|
6
|
+
}
|
|
7
|
+
function nodeHttpTransport(options) {
|
|
8
|
+
const codec = options.codec ?? safeJsonCodec();
|
|
9
|
+
const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);
|
|
10
|
+
return batchTransport({
|
|
11
|
+
name: options.name ?? "node-http-inner",
|
|
12
|
+
minLevel: options.minLevel,
|
|
13
|
+
async logBatch(events) {
|
|
14
|
+
if (!fetchFn) throw new Error("fetch is not available. Use Node.js 18+ or pass fetchFn.");
|
|
15
|
+
const transformed = await applyPayloadTransforms(codec.encode(events), {
|
|
16
|
+
contentType: codec.contentType,
|
|
17
|
+
events,
|
|
18
|
+
transport: options.name ?? "node-http"
|
|
19
|
+
}, options.transformPayload);
|
|
20
|
+
const response = await fetchFn(options.url, {
|
|
21
|
+
method: options.method ?? "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"content-type": transformed.contentType,
|
|
24
|
+
...transformed.headers,
|
|
25
|
+
...options.headers
|
|
26
|
+
},
|
|
27
|
+
body: payloadToBody(transformed.payload)
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) throw new Error(`nodeHttpTransport failed with status ${response.status}`);
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
name: options.name ?? "node-http",
|
|
33
|
+
maxRecords: options.maxRecords,
|
|
34
|
+
maxBatchSize: options.maxBatchSize,
|
|
35
|
+
maxBytes: options.maxBytes,
|
|
36
|
+
maxWaitMs: options.maxWaitMs,
|
|
37
|
+
flushIntervalMs: options.flushIntervalMs,
|
|
38
|
+
concurrency: options.concurrency,
|
|
39
|
+
maxQueueSize: options.maxQueueSize,
|
|
40
|
+
dropPolicy: options.dropPolicy,
|
|
41
|
+
estimateEventBytes: options.estimateEventBytes,
|
|
42
|
+
maxRetries: options.maxRetries,
|
|
43
|
+
retryBaseDelayMs: options.retryBaseDelayMs,
|
|
44
|
+
retryMaxDelayMs: options.retryMaxDelayMs,
|
|
45
|
+
random: options.random,
|
|
46
|
+
circuitBreakerFailureThreshold: options.circuitBreakerFailureThreshold,
|
|
47
|
+
circuitBreakerResetMs: options.circuitBreakerResetMs,
|
|
48
|
+
onDrop: options.onDrop
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { nodeHttpTransport };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=http-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-transport.js","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n applyPayloadTransforms,\n batchTransport,\n safeJsonCodec,\n type BatchTransportOptions,\n type Codec,\n type EncodedPayload,\n type LogEvent,\n type LoggerLevel,\n type PayloadTransform,\n type Transport,\n} from \"@loggerjs/core\";\n\nexport interface NodeHttpTransportOptions extends BatchTransportOptions {\n url: string;\n name?: string;\n method?: \"POST\" | \"PUT\";\n headers?: Record<string, string>;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n fetchFn?: typeof fetch;\n transformPayload?: PayloadTransform | readonly PayloadTransform[];\n}\n\nfunction payloadToBody(payload: EncodedPayload): BodyInit {\n if (typeof payload === \"string\") return payload;\n return Uint8Array.from(payload);\n}\n\nexport function nodeHttpTransport(options: NodeHttpTransportOptions): Transport {\n const codec = options.codec ?? safeJsonCodec();\n const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);\n const inner: Transport = {\n name: options.name ?? \"node-http-inner\",\n minLevel: options.minLevel,\n async logBatch(events: LogEvent[]) {\n if (!fetchFn) throw new Error(\"fetch is not available. Use Node.js 18+ or pass fetchFn.\");\n const encoded = codec.encode(events);\n const transformed = await applyPayloadTransforms(\n encoded,\n {\n contentType: codec.contentType,\n events,\n transport: options.name ?? \"node-http\",\n },\n options.transformPayload,\n );\n const response = await fetchFn(options.url, {\n method: options.method ?? \"POST\",\n headers: {\n \"content-type\": transformed.contentType,\n ...transformed.headers,\n ...options.headers,\n },\n body: payloadToBody(transformed.payload),\n });\n if (!response.ok) throw new Error(`nodeHttpTransport failed with status ${response.status}`);\n },\n };\n return batchTransport(inner, {\n name: options.name ?? \"node-http\",\n maxRecords: options.maxRecords,\n maxBatchSize: options.maxBatchSize,\n maxBytes: options.maxBytes,\n maxWaitMs: options.maxWaitMs,\n flushIntervalMs: options.flushIntervalMs,\n concurrency: options.concurrency,\n maxQueueSize: options.maxQueueSize,\n dropPolicy: options.dropPolicy,\n estimateEventBytes: options.estimateEventBytes,\n maxRetries: options.maxRetries,\n retryBaseDelayMs: options.retryBaseDelayMs,\n retryMaxDelayMs: options.retryMaxDelayMs,\n random: options.random,\n circuitBreakerFailureThreshold: options.circuitBreakerFailureThreshold,\n circuitBreakerResetMs: options.circuitBreakerResetMs,\n onDrop: options.onDrop,\n });\n}\n"],"mappings":";;AAwBA,SAAS,cAAc,SAAmC;CACxD,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,OAAO,WAAW,KAAK,OAAO;AAChC;AAEA,SAAgB,kBAAkB,SAA8C;CAC9E,MAAM,QAAQ,QAAQ,SAAS,cAAc;CAC7C,MAAM,UAAU,QAAQ,WAAW,WAAW,OAAO,KAAK,UAAU;CA4BpE,OAAO,eAAe;EA1BpB,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ;EAClB,MAAM,SAAS,QAAoB;GACjC,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,0DAA0D;GAExF,MAAM,cAAc,MAAM,uBADV,MAAM,OAAO,MAErB,GACN;IACE,aAAa,MAAM;IACnB;IACA,WAAW,QAAQ,QAAQ;GAC7B,GACA,QAAQ,gBACV;GACA,MAAM,WAAW,MAAM,QAAQ,QAAQ,KAAK;IAC1C,QAAQ,QAAQ,UAAU;IAC1B,SAAS;KACP,gBAAgB,YAAY;KAC5B,GAAG,YAAY;KACf,GAAG,QAAQ;IACb;IACA,MAAM,cAAc,YAAY,OAAO;GACzC,CAAC;GACD,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,wCAAwC,SAAS,QAAQ;EAC7F;CAEwB,GAAG;EAC3B,MAAM,QAAQ,QAAQ;EACtB,YAAY,QAAQ;EACpB,cAAc,QAAQ;EACtB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACnB,iBAAiB,QAAQ;EACzB,aAAa,QAAQ;EACrB,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACpB,oBAAoB,QAAQ;EAC5B,YAAY,QAAQ;EACpB,kBAAkB,QAAQ;EAC1B,iBAAiB,QAAQ;EACzB,QAAQ,QAAQ;EAChB,gCAAgC,QAAQ;EACxC,uBAAuB,QAAQ;EAC/B,QAAQ,QAAQ;CAClB,CAAC;AACH"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
//#region src/koa-integration.ts
|
|
4
|
+
function sanitizeUrl(url) {
|
|
5
|
+
return url.split(/[?#]/, 1)[0] || "/";
|
|
6
|
+
}
|
|
7
|
+
function levelFor(status, _ctx, error) {
|
|
8
|
+
if (error || status >= 500) return "error";
|
|
9
|
+
if (status >= 400) return "warn";
|
|
10
|
+
return "info";
|
|
11
|
+
}
|
|
12
|
+
function koaIntegration(logger, options = {}) {
|
|
13
|
+
const minStatus = options.minStatus ?? 400;
|
|
14
|
+
const captureAll = options.captureAll ?? false;
|
|
15
|
+
const bindContext = options.bindContext ?? true;
|
|
16
|
+
const sanitize = options.sanitizeUrl ?? sanitizeUrl;
|
|
17
|
+
const getLevel = options.level ?? levelFor;
|
|
18
|
+
return async (ctx, next) => {
|
|
19
|
+
const started = Date.now();
|
|
20
|
+
const method = (ctx.method ?? "GET").toUpperCase();
|
|
21
|
+
const url = sanitize(ctx.originalUrl ?? ctx.url ?? ctx.path ?? "/");
|
|
22
|
+
const requestId = options.getRequestId?.(ctx) ?? ctx.state?.requestId;
|
|
23
|
+
const context = {
|
|
24
|
+
httpMethod: method,
|
|
25
|
+
httpUrl: url,
|
|
26
|
+
requestId,
|
|
27
|
+
...options.context?.(ctx)
|
|
28
|
+
};
|
|
29
|
+
let error;
|
|
30
|
+
try {
|
|
31
|
+
if (bindContext) await (0, _loggerjs_core.withContext)(context, next);
|
|
32
|
+
else await next();
|
|
33
|
+
} catch (caught) {
|
|
34
|
+
error = caught;
|
|
35
|
+
throw caught;
|
|
36
|
+
} finally {
|
|
37
|
+
const status = ctx.status ?? (error ? 500 : 200);
|
|
38
|
+
if (error || captureAll || status >= minStatus) logger.log(getLevel(status, ctx, error), `Koa ${status} ${method} ${url}`, {
|
|
39
|
+
http: {
|
|
40
|
+
framework: "koa",
|
|
41
|
+
kind: "koa",
|
|
42
|
+
method,
|
|
43
|
+
url,
|
|
44
|
+
status,
|
|
45
|
+
durationMs: Date.now() - started,
|
|
46
|
+
requestId,
|
|
47
|
+
remoteAddress: ctx.ip
|
|
48
|
+
},
|
|
49
|
+
error
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
exports.koaIntegration = koaIntegration;
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=koa-integration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"koa-integration.cjs","names":[],"sources":["../src/koa-integration.ts"],"sourcesContent":["import { withContext, type LoggerLevel, type LoggerLike, type LogData } from \"@loggerjs/core\";\n\nexport interface KoaContextLike {\n method?: string;\n originalUrl?: string;\n url?: string;\n path?: string;\n status?: number;\n ip?: string;\n state?: Record<string, unknown>;\n request?: { headers?: Record<string, string | string[] | undefined> };\n}\n\nexport type KoaNext = () => Promise<unknown>;\nexport type KoaMiddleware = (ctx: KoaContextLike, next: KoaNext) => Promise<void>;\n\nexport interface KoaIntegrationOptions {\n minStatus?: number;\n captureAll?: boolean;\n bindContext?: boolean;\n sanitizeUrl?: (url: string) => string;\n getRequestId?: (ctx: KoaContextLike) => string | undefined;\n context?: (ctx: KoaContextLike) => Record<string, unknown> | undefined;\n level?: (status: number, ctx: KoaContextLike, error: unknown) => LoggerLevel;\n}\n\nfunction sanitizeUrl(url: string): string {\n return url.split(/[?#]/, 1)[0] || \"/\";\n}\n\nfunction levelFor(status: number, _ctx: KoaContextLike, error: unknown): LoggerLevel {\n if (error || status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nexport function koaIntegration(\n logger: LoggerLike,\n options: KoaIntegrationOptions = {},\n): KoaMiddleware {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? false;\n const bindContext = options.bindContext ?? true;\n const sanitize = options.sanitizeUrl ?? sanitizeUrl;\n const getLevel = options.level ?? levelFor;\n\n return async (ctx, next) => {\n const started = Date.now();\n const method = (ctx.method ?? \"GET\").toUpperCase();\n const url = sanitize(ctx.originalUrl ?? ctx.url ?? ctx.path ?? \"/\");\n const requestId = options.getRequestId?.(ctx) ?? (ctx.state?.requestId as string | undefined);\n const context = { httpMethod: method, httpUrl: url, requestId, ...options.context?.(ctx) };\n let error: unknown;\n try {\n if (bindContext) await withContext(context, next);\n else await next();\n } catch (caught) {\n error = caught;\n throw caught;\n } finally {\n const status = ctx.status ?? (error ? 500 : 200);\n if (error || captureAll || status >= minStatus) {\n logger.log(getLevel(status, ctx, error), `Koa ${status} ${method} ${url}`, {\n http: {\n framework: \"koa\",\n kind: \"koa\",\n method,\n url,\n status,\n durationMs: Date.now() - started,\n requestId,\n remoteAddress: ctx.ip,\n },\n error,\n } as LogData);\n }\n }\n };\n}\n"],"mappings":";;;AA0BA,SAAS,YAAY,KAAqB;CACxC,OAAO,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;AACpC;AAEA,SAAS,SAAS,QAAgB,MAAsB,OAA6B;CACnF,IAAI,SAAS,UAAU,KAAK,OAAO;CACnC,IAAI,UAAU,KAAK,OAAO;CAC1B,OAAO;AACT;AAEA,SAAgB,eACd,QACA,UAAiC,CAAC,GACnB;CACf,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,WAAW,QAAQ,eAAe;CACxC,MAAM,WAAW,QAAQ,SAAS;CAElC,OAAO,OAAO,KAAK,SAAS;EAC1B,MAAM,UAAU,KAAK,IAAI;EACzB,MAAM,UAAU,IAAI,UAAU,MAAA,CAAO,YAAY;EACjD,MAAM,MAAM,SAAS,IAAI,eAAe,IAAI,OAAO,IAAI,QAAQ,GAAG;EAClE,MAAM,YAAY,QAAQ,eAAe,GAAG,KAAM,IAAI,OAAO;EAC7D,MAAM,UAAU;GAAE,YAAY;GAAQ,SAAS;GAAK;GAAW,GAAG,QAAQ,UAAU,GAAG;EAAE;EACzF,IAAI;EACJ,IAAI;GACF,IAAI,aAAa,OAAA,GAAA,eAAA,YAAA,CAAkB,SAAS,IAAI;QAC3C,MAAM,KAAK;EAClB,SAAS,QAAQ;GACf,QAAQ;GACR,MAAM;EACR,UAAU;GACR,MAAM,SAAS,IAAI,WAAW,QAAQ,MAAM;GAC5C,IAAI,SAAS,cAAc,UAAU,WACnC,OAAO,IAAI,SAAS,QAAQ,KAAK,KAAK,GAAG,OAAO,OAAO,GAAG,OAAO,GAAG,OAAO;IACzE,MAAM;KACJ,WAAW;KACX,MAAM;KACN;KACA;KACA;KACA,YAAY,KAAK,IAAI,IAAI;KACzB;KACA,eAAe,IAAI;IACrB;IACA;GACF,CAAY;EAEhB;CACF;AACF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { withContext } from "@loggerjs/core";
|
|
2
|
+
//#region src/koa-integration.ts
|
|
3
|
+
function sanitizeUrl(url) {
|
|
4
|
+
return url.split(/[?#]/, 1)[0] || "/";
|
|
5
|
+
}
|
|
6
|
+
function levelFor(status, _ctx, error) {
|
|
7
|
+
if (error || status >= 500) return "error";
|
|
8
|
+
if (status >= 400) return "warn";
|
|
9
|
+
return "info";
|
|
10
|
+
}
|
|
11
|
+
function koaIntegration(logger, options = {}) {
|
|
12
|
+
const minStatus = options.minStatus ?? 400;
|
|
13
|
+
const captureAll = options.captureAll ?? false;
|
|
14
|
+
const bindContext = options.bindContext ?? true;
|
|
15
|
+
const sanitize = options.sanitizeUrl ?? sanitizeUrl;
|
|
16
|
+
const getLevel = options.level ?? levelFor;
|
|
17
|
+
return async (ctx, next) => {
|
|
18
|
+
const started = Date.now();
|
|
19
|
+
const method = (ctx.method ?? "GET").toUpperCase();
|
|
20
|
+
const url = sanitize(ctx.originalUrl ?? ctx.url ?? ctx.path ?? "/");
|
|
21
|
+
const requestId = options.getRequestId?.(ctx) ?? ctx.state?.requestId;
|
|
22
|
+
const context = {
|
|
23
|
+
httpMethod: method,
|
|
24
|
+
httpUrl: url,
|
|
25
|
+
requestId,
|
|
26
|
+
...options.context?.(ctx)
|
|
27
|
+
};
|
|
28
|
+
let error;
|
|
29
|
+
try {
|
|
30
|
+
if (bindContext) await withContext(context, next);
|
|
31
|
+
else await next();
|
|
32
|
+
} catch (caught) {
|
|
33
|
+
error = caught;
|
|
34
|
+
throw caught;
|
|
35
|
+
} finally {
|
|
36
|
+
const status = ctx.status ?? (error ? 500 : 200);
|
|
37
|
+
if (error || captureAll || status >= minStatus) logger.log(getLevel(status, ctx, error), `Koa ${status} ${method} ${url}`, {
|
|
38
|
+
http: {
|
|
39
|
+
framework: "koa",
|
|
40
|
+
kind: "koa",
|
|
41
|
+
method,
|
|
42
|
+
url,
|
|
43
|
+
status,
|
|
44
|
+
durationMs: Date.now() - started,
|
|
45
|
+
requestId,
|
|
46
|
+
remoteAddress: ctx.ip
|
|
47
|
+
},
|
|
48
|
+
error
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { koaIntegration };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=koa-integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"koa-integration.js","names":[],"sources":["../src/koa-integration.ts"],"sourcesContent":["import { withContext, type LoggerLevel, type LoggerLike, type LogData } from \"@loggerjs/core\";\n\nexport interface KoaContextLike {\n method?: string;\n originalUrl?: string;\n url?: string;\n path?: string;\n status?: number;\n ip?: string;\n state?: Record<string, unknown>;\n request?: { headers?: Record<string, string | string[] | undefined> };\n}\n\nexport type KoaNext = () => Promise<unknown>;\nexport type KoaMiddleware = (ctx: KoaContextLike, next: KoaNext) => Promise<void>;\n\nexport interface KoaIntegrationOptions {\n minStatus?: number;\n captureAll?: boolean;\n bindContext?: boolean;\n sanitizeUrl?: (url: string) => string;\n getRequestId?: (ctx: KoaContextLike) => string | undefined;\n context?: (ctx: KoaContextLike) => Record<string, unknown> | undefined;\n level?: (status: number, ctx: KoaContextLike, error: unknown) => LoggerLevel;\n}\n\nfunction sanitizeUrl(url: string): string {\n return url.split(/[?#]/, 1)[0] || \"/\";\n}\n\nfunction levelFor(status: number, _ctx: KoaContextLike, error: unknown): LoggerLevel {\n if (error || status >= 500) return \"error\";\n if (status >= 400) return \"warn\";\n return \"info\";\n}\n\nexport function koaIntegration(\n logger: LoggerLike,\n options: KoaIntegrationOptions = {},\n): KoaMiddleware {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? false;\n const bindContext = options.bindContext ?? true;\n const sanitize = options.sanitizeUrl ?? sanitizeUrl;\n const getLevel = options.level ?? levelFor;\n\n return async (ctx, next) => {\n const started = Date.now();\n const method = (ctx.method ?? \"GET\").toUpperCase();\n const url = sanitize(ctx.originalUrl ?? ctx.url ?? ctx.path ?? \"/\");\n const requestId = options.getRequestId?.(ctx) ?? (ctx.state?.requestId as string | undefined);\n const context = { httpMethod: method, httpUrl: url, requestId, ...options.context?.(ctx) };\n let error: unknown;\n try {\n if (bindContext) await withContext(context, next);\n else await next();\n } catch (caught) {\n error = caught;\n throw caught;\n } finally {\n const status = ctx.status ?? (error ? 500 : 200);\n if (error || captureAll || status >= minStatus) {\n logger.log(getLevel(status, ctx, error), `Koa ${status} ${method} ${url}`, {\n http: {\n framework: \"koa\",\n kind: \"koa\",\n method,\n url,\n status,\n durationMs: Date.now() - started,\n requestId,\n remoteAddress: ctx.ip,\n },\n error,\n } as LogData);\n }\n }\n };\n}\n"],"mappings":";;AA0BA,SAAS,YAAY,KAAqB;CACxC,OAAO,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;AACpC;AAEA,SAAS,SAAS,QAAgB,MAAsB,OAA6B;CACnF,IAAI,SAAS,UAAU,KAAK,OAAO;CACnC,IAAI,UAAU,KAAK,OAAO;CAC1B,OAAO;AACT;AAEA,SAAgB,eACd,QACA,UAAiC,CAAC,GACnB;CACf,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,WAAW,QAAQ,eAAe;CACxC,MAAM,WAAW,QAAQ,SAAS;CAElC,OAAO,OAAO,KAAK,SAAS;EAC1B,MAAM,UAAU,KAAK,IAAI;EACzB,MAAM,UAAU,IAAI,UAAU,MAAA,CAAO,YAAY;EACjD,MAAM,MAAM,SAAS,IAAI,eAAe,IAAI,OAAO,IAAI,QAAQ,GAAG;EAClE,MAAM,YAAY,QAAQ,eAAe,GAAG,KAAM,IAAI,OAAO;EAC7D,MAAM,UAAU;GAAE,YAAY;GAAQ,SAAS;GAAK;GAAW,GAAG,QAAQ,UAAU,GAAG;EAAE;EACzF,IAAI;EACJ,IAAI;GACF,IAAI,aAAa,MAAM,YAAY,SAAS,IAAI;QAC3C,MAAM,KAAK;EAClB,SAAS,QAAQ;GACf,QAAQ;GACR,MAAM;EACR,UAAU;GACR,MAAM,SAAS,IAAI,WAAW,QAAQ,MAAM;GAC5C,IAAI,SAAS,cAAc,UAAU,WACnC,OAAO,IAAI,SAAS,QAAQ,KAAK,KAAK,GAAG,OAAO,OAAO,GAAG,OAAO,GAAG,OAAO;IACzE,MAAM;KACJ,WAAW;KACX,MAAM;KACN;KACA;KACA;KACA,YAAY,KAAK,IAAI,IAAI;KACzB;KACA,eAAe,IAAI;IACrB;IACA;GACF,CAAY;EAEhB;CACF;AACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let node_module = require("node:module");
|
|
3
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
4
|
+
//#region src/logger-diagnostics.ts
|
|
5
|
+
const requireBuiltin = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
6
|
+
let cachedDiagnosticsChannel;
|
|
7
|
+
function loadDiagnosticsChannel() {
|
|
8
|
+
if (cachedDiagnosticsChannel !== void 0) return cachedDiagnosticsChannel;
|
|
9
|
+
try {
|
|
10
|
+
cachedDiagnosticsChannel = requireBuiltin("node:diagnostics_channel");
|
|
11
|
+
} catch {
|
|
12
|
+
try {
|
|
13
|
+
cachedDiagnosticsChannel = requireBuiltin("diagnostics_channel");
|
|
14
|
+
} catch {
|
|
15
|
+
cachedDiagnosticsChannel = null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return cachedDiagnosticsChannel;
|
|
19
|
+
}
|
|
20
|
+
function installLoggerDiagnosticsChannel(options = {}) {
|
|
21
|
+
const diagnosticsChannel = options.diagnosticsChannel === void 0 ? loadDiagnosticsChannel() : options.diagnosticsChannel;
|
|
22
|
+
if (!diagnosticsChannel) return () => {};
|
|
23
|
+
const prefix = options.prefix ?? "loggerjs";
|
|
24
|
+
const channels = /* @__PURE__ */ new Map();
|
|
25
|
+
const channelFor = (stage) => {
|
|
26
|
+
const name = `${prefix}.${stage}`;
|
|
27
|
+
let channel = channels.get(name);
|
|
28
|
+
if (!channel) {
|
|
29
|
+
channel = diagnosticsChannel.channel(name);
|
|
30
|
+
channels.set(name, channel);
|
|
31
|
+
}
|
|
32
|
+
return channel;
|
|
33
|
+
};
|
|
34
|
+
const sink = (event) => {
|
|
35
|
+
channelFor(event.stage).publish(event);
|
|
36
|
+
};
|
|
37
|
+
sink.enabled = (stage) => channelFor(stage).hasSubscribers !== false;
|
|
38
|
+
const previous = (0, _loggerjs_core.setLoggerDiagnosticSink)(sink);
|
|
39
|
+
return () => {
|
|
40
|
+
(0, _loggerjs_core.setLoggerDiagnosticSink)(previous);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
exports.installLoggerDiagnosticsChannel = installLoggerDiagnosticsChannel;
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=logger-diagnostics.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-diagnostics.cjs","names":[],"sources":["../src/logger-diagnostics.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport {\n setLoggerDiagnosticSink,\n type LoggerDiagnosticEvent,\n type LoggerDiagnosticSink,\n type LoggerDiagnosticStage,\n} from \"@loggerjs/core\";\n\nexport interface LoggerDiagnosticsChannelPublisher {\n hasSubscribers?: boolean;\n publish: (message: LoggerDiagnosticEvent) => void;\n}\n\nexport interface LoggerDiagnosticsChannelModule {\n channel: (name: string) => LoggerDiagnosticsChannelPublisher;\n}\n\nexport interface InstallLoggerDiagnosticsChannelOptions {\n diagnosticsChannel?: LoggerDiagnosticsChannelModule | null;\n prefix?: string;\n}\n\nconst requireBuiltin = createRequire(import.meta.url);\nlet cachedDiagnosticsChannel: LoggerDiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): LoggerDiagnosticsChannelModule | null {\n if (cachedDiagnosticsChannel !== undefined) return cachedDiagnosticsChannel;\n try {\n cachedDiagnosticsChannel = requireBuiltin(\n \"node:diagnostics_channel\",\n ) as LoggerDiagnosticsChannelModule;\n } catch {\n try {\n cachedDiagnosticsChannel = requireBuiltin(\n \"diagnostics_channel\",\n ) as LoggerDiagnosticsChannelModule;\n } catch {\n cachedDiagnosticsChannel = null;\n }\n }\n return cachedDiagnosticsChannel;\n}\n\nexport function installLoggerDiagnosticsChannel(\n options: InstallLoggerDiagnosticsChannelOptions = {},\n): () => void {\n const diagnosticsChannel =\n options.diagnosticsChannel === undefined\n ? loadDiagnosticsChannel()\n : options.diagnosticsChannel;\n if (!diagnosticsChannel) return () => {};\n\n const prefix = options.prefix ?? \"loggerjs\";\n const channels = new Map<string, LoggerDiagnosticsChannelPublisher>();\n const channelFor = (stage: LoggerDiagnosticStage) => {\n const name = `${prefix}.${stage}`;\n let channel = channels.get(name);\n if (!channel) {\n channel = diagnosticsChannel.channel(name);\n channels.set(name, channel);\n }\n return channel;\n };\n const sink: LoggerDiagnosticSink = (event) => {\n channelFor(event.stage).publish(event);\n };\n sink.enabled = (stage) => channelFor(stage).hasSubscribers !== false;\n const previous = setLoggerDiagnosticSink(sink);\n\n return () => {\n setLoggerDiagnosticSink(previous);\n };\n}\n"],"mappings":";;;;AAsBA,MAAM,kBAAA,GAAA,YAAA,cAAA,CAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,IAA8C;AACpD,IAAI;AAEJ,SAAS,yBAAgE;CACvE,IAAI,6BAA6B,KAAA,GAAW,OAAO;CACnD,IAAI;EACF,2BAA2B,eACzB,0BACF;CACF,QAAQ;EACN,IAAI;GACF,2BAA2B,eACzB,qBACF;EACF,QAAQ;GACN,2BAA2B;EAC7B;CACF;CACA,OAAO;AACT;AAEA,SAAgB,gCACd,UAAkD,CAAC,GACvC;CACZ,MAAM,qBACJ,QAAQ,uBAAuB,KAAA,IAC3B,uBAAuB,IACvB,QAAQ;CACd,IAAI,CAAC,oBAAoB,aAAa,CAAC;CAEvC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,2BAAW,IAAI,IAA+C;CACpE,MAAM,cAAc,UAAiC;EACnD,MAAM,OAAO,GAAG,OAAO,GAAG;EAC1B,IAAI,UAAU,SAAS,IAAI,IAAI;EAC/B,IAAI,CAAC,SAAS;GACZ,UAAU,mBAAmB,QAAQ,IAAI;GACzC,SAAS,IAAI,MAAM,OAAO;EAC5B;EACA,OAAO;CACT;CACA,MAAM,QAA8B,UAAU;EAC5C,WAAW,MAAM,KAAK,CAAC,CAAC,QAAQ,KAAK;CACvC;CACA,KAAK,WAAW,UAAU,WAAW,KAAK,CAAC,CAAC,mBAAmB;CAC/D,MAAM,YAAA,GAAA,eAAA,wBAAA,CAAmC,IAAI;CAE7C,aAAa;EACX,CAAA,GAAA,eAAA,wBAAA,CAAwB,QAAQ;CAClC;AACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { setLoggerDiagnosticSink } from "@loggerjs/core";
|
|
3
|
+
//#region src/logger-diagnostics.ts
|
|
4
|
+
const requireBuiltin = createRequire(import.meta.url);
|
|
5
|
+
let cachedDiagnosticsChannel;
|
|
6
|
+
function loadDiagnosticsChannel() {
|
|
7
|
+
if (cachedDiagnosticsChannel !== void 0) return cachedDiagnosticsChannel;
|
|
8
|
+
try {
|
|
9
|
+
cachedDiagnosticsChannel = requireBuiltin("node:diagnostics_channel");
|
|
10
|
+
} catch {
|
|
11
|
+
try {
|
|
12
|
+
cachedDiagnosticsChannel = requireBuiltin("diagnostics_channel");
|
|
13
|
+
} catch {
|
|
14
|
+
cachedDiagnosticsChannel = null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return cachedDiagnosticsChannel;
|
|
18
|
+
}
|
|
19
|
+
function installLoggerDiagnosticsChannel(options = {}) {
|
|
20
|
+
const diagnosticsChannel = options.diagnosticsChannel === void 0 ? loadDiagnosticsChannel() : options.diagnosticsChannel;
|
|
21
|
+
if (!diagnosticsChannel) return () => {};
|
|
22
|
+
const prefix = options.prefix ?? "loggerjs";
|
|
23
|
+
const channels = /* @__PURE__ */ new Map();
|
|
24
|
+
const channelFor = (stage) => {
|
|
25
|
+
const name = `${prefix}.${stage}`;
|
|
26
|
+
let channel = channels.get(name);
|
|
27
|
+
if (!channel) {
|
|
28
|
+
channel = diagnosticsChannel.channel(name);
|
|
29
|
+
channels.set(name, channel);
|
|
30
|
+
}
|
|
31
|
+
return channel;
|
|
32
|
+
};
|
|
33
|
+
const sink = (event) => {
|
|
34
|
+
channelFor(event.stage).publish(event);
|
|
35
|
+
};
|
|
36
|
+
sink.enabled = (stage) => channelFor(stage).hasSubscribers !== false;
|
|
37
|
+
const previous = setLoggerDiagnosticSink(sink);
|
|
38
|
+
return () => {
|
|
39
|
+
setLoggerDiagnosticSink(previous);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { installLoggerDiagnosticsChannel };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=logger-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-diagnostics.js","names":[],"sources":["../src/logger-diagnostics.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport {\n setLoggerDiagnosticSink,\n type LoggerDiagnosticEvent,\n type LoggerDiagnosticSink,\n type LoggerDiagnosticStage,\n} from \"@loggerjs/core\";\n\nexport interface LoggerDiagnosticsChannelPublisher {\n hasSubscribers?: boolean;\n publish: (message: LoggerDiagnosticEvent) => void;\n}\n\nexport interface LoggerDiagnosticsChannelModule {\n channel: (name: string) => LoggerDiagnosticsChannelPublisher;\n}\n\nexport interface InstallLoggerDiagnosticsChannelOptions {\n diagnosticsChannel?: LoggerDiagnosticsChannelModule | null;\n prefix?: string;\n}\n\nconst requireBuiltin = createRequire(import.meta.url);\nlet cachedDiagnosticsChannel: LoggerDiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): LoggerDiagnosticsChannelModule | null {\n if (cachedDiagnosticsChannel !== undefined) return cachedDiagnosticsChannel;\n try {\n cachedDiagnosticsChannel = requireBuiltin(\n \"node:diagnostics_channel\",\n ) as LoggerDiagnosticsChannelModule;\n } catch {\n try {\n cachedDiagnosticsChannel = requireBuiltin(\n \"diagnostics_channel\",\n ) as LoggerDiagnosticsChannelModule;\n } catch {\n cachedDiagnosticsChannel = null;\n }\n }\n return cachedDiagnosticsChannel;\n}\n\nexport function installLoggerDiagnosticsChannel(\n options: InstallLoggerDiagnosticsChannelOptions = {},\n): () => void {\n const diagnosticsChannel =\n options.diagnosticsChannel === undefined\n ? loadDiagnosticsChannel()\n : options.diagnosticsChannel;\n if (!diagnosticsChannel) return () => {};\n\n const prefix = options.prefix ?? \"loggerjs\";\n const channels = new Map<string, LoggerDiagnosticsChannelPublisher>();\n const channelFor = (stage: LoggerDiagnosticStage) => {\n const name = `${prefix}.${stage}`;\n let channel = channels.get(name);\n if (!channel) {\n channel = diagnosticsChannel.channel(name);\n channels.set(name, channel);\n }\n return channel;\n };\n const sink: LoggerDiagnosticSink = (event) => {\n channelFor(event.stage).publish(event);\n };\n sink.enabled = (stage) => channelFor(stage).hasSubscribers !== false;\n const previous = setLoggerDiagnosticSink(sink);\n\n return () => {\n setLoggerDiagnosticSink(previous);\n };\n}\n"],"mappings":";;;AAsBA,MAAM,iBAAiB,cAAc,OAAO,KAAK,GAAG;AACpD,IAAI;AAEJ,SAAS,yBAAgE;CACvE,IAAI,6BAA6B,KAAA,GAAW,OAAO;CACnD,IAAI;EACF,2BAA2B,eACzB,0BACF;CACF,QAAQ;EACN,IAAI;GACF,2BAA2B,eACzB,qBACF;EACF,QAAQ;GACN,2BAA2B;EAC7B;CACF;CACA,OAAO;AACT;AAEA,SAAgB,gCACd,UAAkD,CAAC,GACvC;CACZ,MAAM,qBACJ,QAAQ,uBAAuB,KAAA,IAC3B,uBAAuB,IACvB,QAAQ;CACd,IAAI,CAAC,oBAAoB,aAAa,CAAC;CAEvC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,2BAAW,IAAI,IAA+C;CACpE,MAAM,cAAc,UAAiC;EACnD,MAAM,OAAO,GAAG,OAAO,GAAG;EAC1B,IAAI,UAAU,SAAS,IAAI,IAAI;EAC/B,IAAI,CAAC,SAAS;GACZ,UAAU,mBAAmB,QAAQ,IAAI;GACzC,SAAS,IAAI,MAAM,OAAO;EAC5B;EACA,OAAO;CACT;CACA,MAAM,QAA8B,UAAU;EAC5C,WAAW,MAAM,KAAK,CAAC,CAAC,QAAQ,KAAK;CACvC;CACA,KAAK,WAAW,UAAU,WAAW,KAAK,CAAC,CAAC,mBAAmB;CAC/D,MAAM,WAAW,wBAAwB,IAAI;CAE7C,aAAa;EACX,wBAAwB,QAAQ;CAClC;AACF"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
//#region src/express-integration.ts
|
|
4
|
+
const defaultRandom = () => Math.random();
|
|
5
|
+
function defaultSanitizeUrl(url) {
|
|
6
|
+
const queryIndex = url.indexOf("?");
|
|
7
|
+
const hashIndex = url.indexOf("#");
|
|
8
|
+
const end = Math.min(queryIndex >= 0 ? queryIndex : url.length, hashIndex >= 0 ? hashIndex : url.length);
|
|
9
|
+
return url.slice(0, end);
|
|
10
|
+
}
|
|
11
|
+
function defaultLevel(status, _req, _res, aborted) {
|
|
12
|
+
if (aborted) return "warn";
|
|
13
|
+
if (status >= 500) return "error";
|
|
14
|
+
if (status >= 400) return "warn";
|
|
15
|
+
return "info";
|
|
16
|
+
}
|
|
17
|
+
function requestUrl(req) {
|
|
18
|
+
return req.originalUrl ?? req.url ?? req.path ?? "/";
|
|
19
|
+
}
|
|
20
|
+
function headerValue(value) {
|
|
21
|
+
if (typeof value === "number") return String(value);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
function pickRequestHeaders(req, names) {
|
|
25
|
+
if (!names || names.length === 0 || !req.headers) return void 0;
|
|
26
|
+
const out = {};
|
|
27
|
+
for (const name of names) {
|
|
28
|
+
const value = req.headers[name.toLowerCase()] ?? req.headers[name];
|
|
29
|
+
if (value !== void 0) out[name.toLowerCase()] = value;
|
|
30
|
+
}
|
|
31
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
32
|
+
}
|
|
33
|
+
function pickResponseHeaders(res, names) {
|
|
34
|
+
if (!names || names.length === 0 || !res.getHeader) return void 0;
|
|
35
|
+
const out = {};
|
|
36
|
+
for (const name of names) {
|
|
37
|
+
const value = headerValue(res.getHeader(name));
|
|
38
|
+
if (value !== void 0) out[name.toLowerCase()] = value;
|
|
39
|
+
}
|
|
40
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
41
|
+
}
|
|
42
|
+
function defaultRoute(req) {
|
|
43
|
+
const path = req.route?.path;
|
|
44
|
+
return typeof path === "string" ? path : void 0;
|
|
45
|
+
}
|
|
46
|
+
function removeListener(res, event, listener) {
|
|
47
|
+
if (res.off) {
|
|
48
|
+
res.off(event, listener);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
res.removeListener?.(event, listener);
|
|
52
|
+
}
|
|
53
|
+
function onResponseDone(res, event, listener) {
|
|
54
|
+
if (res.once) {
|
|
55
|
+
res.once(event, listener);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
res.on?.(event, listener);
|
|
59
|
+
}
|
|
60
|
+
function expressIntegration(logger, options = {}) {
|
|
61
|
+
const name = options.name ?? "express";
|
|
62
|
+
const minStatus = options.minStatus ?? 400;
|
|
63
|
+
const captureAll = options.captureAll ?? options.captureSuccessful ?? false;
|
|
64
|
+
const captureAborted = options.captureAborted ?? true;
|
|
65
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
66
|
+
const random = options.random ?? defaultRandom;
|
|
67
|
+
const sanitizeUrl = options.sanitizeUrl ?? defaultSanitizeUrl;
|
|
68
|
+
const levelFor = options.level ?? defaultLevel;
|
|
69
|
+
const routeFor = options.getRoute ?? defaultRoute;
|
|
70
|
+
const bindContext = options.bindContext ?? true;
|
|
71
|
+
return (req, res, next) => {
|
|
72
|
+
const started = Date.now();
|
|
73
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
74
|
+
const url = sanitizeUrl(requestUrl(req));
|
|
75
|
+
const requestId = options.getRequestId?.(req, res);
|
|
76
|
+
let completed = false;
|
|
77
|
+
const context = {
|
|
78
|
+
httpMethod: method,
|
|
79
|
+
httpUrl: url,
|
|
80
|
+
requestId,
|
|
81
|
+
...options.context?.(req, res)
|
|
82
|
+
};
|
|
83
|
+
const shouldCapture = (status, aborted) => {
|
|
84
|
+
if (aborted && captureAborted) return true;
|
|
85
|
+
if (status >= minStatus) return true;
|
|
86
|
+
if (!captureAll) return false;
|
|
87
|
+
return sampleRate >= 1 || random() < sampleRate;
|
|
88
|
+
};
|
|
89
|
+
const cleanup = () => {
|
|
90
|
+
removeListener(res, "finish", onFinish);
|
|
91
|
+
removeListener(res, "close", onClose);
|
|
92
|
+
};
|
|
93
|
+
const logRequest = (event) => {
|
|
94
|
+
if (completed) return;
|
|
95
|
+
completed = true;
|
|
96
|
+
cleanup();
|
|
97
|
+
const status = res.statusCode ?? 0;
|
|
98
|
+
const aborted = event === "close" && res.writableEnded !== true;
|
|
99
|
+
if (!shouldCapture(status, aborted)) return;
|
|
100
|
+
const http = {
|
|
101
|
+
kind: name,
|
|
102
|
+
framework: "express",
|
|
103
|
+
method,
|
|
104
|
+
url,
|
|
105
|
+
route: routeFor(req),
|
|
106
|
+
status,
|
|
107
|
+
durationMs: Date.now() - started,
|
|
108
|
+
aborted,
|
|
109
|
+
requestId,
|
|
110
|
+
remoteAddress: req.ip ?? req.socket?.remoteAddress,
|
|
111
|
+
requestHeaders: pickRequestHeaders(req, options.captureRequestHeaders),
|
|
112
|
+
responseHeaders: pickResponseHeaders(res, options.captureResponseHeaders)
|
|
113
|
+
};
|
|
114
|
+
logger.log(levelFor(status, req, res, aborted), `Express ${status} ${method} ${url}`, { http });
|
|
115
|
+
};
|
|
116
|
+
const onFinish = () => logRequest("finish");
|
|
117
|
+
const onClose = () => logRequest("close");
|
|
118
|
+
onResponseDone(res, "finish", onFinish);
|
|
119
|
+
onResponseDone(res, "close", onClose);
|
|
120
|
+
if (bindContext) {
|
|
121
|
+
(0, _loggerjs_core.withContext)(context, () => next());
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
next();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/nest-integration.ts
|
|
129
|
+
function nestMiddlewareIntegration(logger, options = {}) {
|
|
130
|
+
return expressIntegration(logger, {
|
|
131
|
+
name: "nestjs",
|
|
132
|
+
...options
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
exports.nestMiddlewareIntegration = nestMiddlewareIntegration;
|
|
137
|
+
|
|
138
|
+
//# sourceMappingURL=nest-integration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest-integration.cjs","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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"}
|