@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 @@
|
|
|
1
|
+
{"version":3,"file":"rotating-file-transport.cjs","names":[],"sources":["../src/node-destination.ts","../src/rotating-file-transport.ts"],"sourcesContent":["import { closeSync, createWriteStream, mkdirSync, openSync, writeSync, type WriteStream } from \"fs\";\nimport { dirname } from \"path\";\nimport type { TransportContext } from \"@loggerjs/core\";\nimport type { WritableLike } from \"./internal-types\";\n\nexport interface NodeDestination {\n stream?: WriteStream;\n write: (payload: string | Uint8Array, context?: TransportContext) => void;\n flush: () => Promise<void>;\n flushSync: () => void;\n close: () => Promise<void>;\n closeSync: () => void;\n releaseSync?: () => void;\n}\n\nexport interface NodeStreamDestinationOptions {\n name: string;\n stream: WritableLike;\n minLength?: number;\n ignoreEpipe?: boolean;\n reportOperation?: string;\n syncWrite?: (payload: string | Uint8Array) => void;\n}\n\nexport interface NodeFileDestinationOptions {\n name: string;\n path: string;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\ninterface FlushWaiter {\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst normalizeError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nfunction byteLength(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? encoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction coalescePayloads(payloads: Array<string | Uint8Array>): string | Uint8Array {\n if (payloads.every((payload) => typeof payload === \"string\")) {\n return payloads.join(\"\");\n }\n const buffers = payloads.map((payload) =>\n typeof payload === \"string\" ? Buffer.from(payload) : Buffer.from(payload),\n );\n return Buffer.concat(buffers);\n}\n\nfunction isEpipe(error: unknown): boolean {\n return (\n Boolean(error) && typeof error === \"object\" && (error as { code?: unknown }).code === \"EPIPE\"\n );\n}\n\nfunction normalizeMinLength(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return 0;\n return Math.floor(value);\n}\n\nexport function createNodeStreamDestination(\n options: NodeStreamDestinationOptions,\n): NodeDestination {\n const minLength = normalizeMinLength(options.minLength);\n const ignoreEpipe = options.ignoreEpipe ?? false;\n const waiters: FlushWaiter[] = [];\n const buffer: Array<string | Uint8Array> = [];\n const pendingPayloads: Array<string | Uint8Array> = [];\n let bufferedBytes = 0;\n let pendingWrites = 0;\n let pendingDrains = 0;\n let lastError: Error | undefined;\n let lastContext: TransportContext | undefined;\n let closed = false;\n\n const reportInternalError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) return;\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name,\n operation,\n });\n };\n\n const settleWaitersIfIdle = () => {\n if (pendingWrites + pendingDrains > 0) return;\n if (waiters.length === 0) return;\n const error = lastError;\n lastError = undefined;\n for (const waiter of waiters.splice(0)) {\n if (error) waiter.reject(error);\n else waiter.resolve();\n }\n };\n\n const recordError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) {\n closed = true;\n return;\n }\n lastError = normalizeError(error);\n reportInternalError(lastError, operation);\n };\n\n const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\n settleWaitersIfIdle();\n };\n const offError = () => options.stream.off?.(\"error\", onStreamError);\n options.stream.on?.(\"error\", onStreamError);\n\n const waitForDrain = () => {\n if (!options.stream.once) return;\n pendingDrains += 1;\n options.stream.once(\"drain\", () => {\n pendingDrains -= 1;\n settleWaitersIfIdle();\n });\n };\n\n const removePending = (payload: string | Uint8Array) => {\n const index = pendingPayloads.indexOf(payload);\n if (index >= 0) pendingPayloads.splice(index, 1);\n };\n\n const writeNow = (payload: string | Uint8Array) => {\n if (closed) return;\n pendingPayloads.push(payload);\n pendingWrites += 1;\n try {\n const result = options.stream.write(payload, (error?: Error | null) => {\n removePending(payload);\n pendingWrites -= 1;\n if (error) recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n });\n if (result === false) waitForDrain();\n } catch (error) {\n removePending(payload);\n pendingWrites -= 1;\n recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n }\n };\n\n const flushBuffered = () => {\n if (buffer.length === 0) return;\n const payload = coalescePayloads(buffer.splice(0));\n bufferedBytes = 0;\n writeNow(payload);\n };\n\n const destination: NodeDestination = {\n write(payload, context) {\n if (closed) return;\n lastContext = context;\n if (minLength > 0) {\n buffer.push(payload);\n bufferedBytes += byteLength(payload);\n if (bufferedBytes >= minLength) flushBuffered();\n return;\n }\n writeNow(payload);\n },\n flush() {\n flushBuffered();\n if (pendingWrites + pendingDrains === 0) {\n const error = lastError;\n lastError = undefined;\n if (error) return Promise.reject(error);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n waiters.push({ resolve, reject });\n });\n },\n flushSync() {\n if (!options.syncWrite) {\n flushBuffered();\n return;\n }\n for (const payload of buffer.splice(0)) options.syncWrite(payload);\n bufferedBytes = 0;\n for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);\n },\n close() {\n return destination.flush().then(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!options.stream.end) {\n closed = true;\n offError();\n resolve();\n return;\n }\n options.stream.end((error?: Error | null) => {\n closed = true;\n offError();\n if (error && !(ignoreEpipe && isEpipe(error))) reject(error);\n else resolve();\n });\n }),\n (error: unknown) => {\n offError();\n return Promise.reject(error);\n },\n );\n },\n closeSync() {\n destination.flushSync();\n closed = true;\n offError();\n },\n };\n return destination;\n}\n\nexport function createNodeFileDestination(options: NodeFileDestinationOptions): NodeDestination {\n const flags = options.flags ?? (options.append === false ? \"w\" : \"a\");\n if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });\n\n let fd: number | undefined;\n const getFd = () => {\n fd ??= openSync(options.path, flags);\n return fd;\n };\n const syncWrite = (payload: string | Uint8Array) => {\n if (typeof payload === \"string\") writeSync(getFd(), payload);\n else writeSync(getFd(), payload);\n };\n\n if (options.sync) {\n let closed = false;\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n write(payload) {\n if (closed) return;\n syncWrite(payload);\n },\n flush() {\n return Promise.resolve();\n },\n flushSync() {},\n close() {\n releaseSync();\n closed = true;\n return Promise.resolve();\n },\n closeSync() {\n releaseSync();\n closed = true;\n },\n releaseSync,\n };\n }\n\n const stream = createWriteStream(options.path, { flags });\n const destination = createNodeStreamDestination({\n name: options.name,\n stream,\n minLength: options.minLength,\n syncWrite,\n });\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n ...destination,\n stream,\n close() {\n return destination.close().finally(releaseSync);\n },\n closeSync() {\n destination.closeSync();\n releaseSync();\n },\n releaseSync,\n };\n}\n","import { existsSync, renameSync, statSync, unlinkSync } from \"fs\";\nimport {\n ndjsonCodec,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface RotatingFileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n maxBytes?: number;\n maxFiles?: number;\n archivePath?: (path: string, index: number) => string;\n}\n\nexport interface RotatingFileTransport extends Transport {\n rotate: () => void;\n flushSync: () => void;\n currentBytes: () => number;\n}\n\nconst textEncoder = new TextEncoder();\n\nfunction payloadBytes(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? textEncoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction normalizePositiveInteger(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return fallback;\n return Math.floor(value);\n}\n\nfunction normalizeNonNegativeInteger(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value < 0) return fallback;\n return Math.floor(value);\n}\n\nfunction defaultArchivePath(path: string, index: number): string {\n return `${path}.${index}`;\n}\n\nfunction fileSize(path: string): number {\n try {\n return statSync(path).size;\n } catch {\n return 0;\n }\n}\n\nexport function rotatingFileTransport(\n options: RotatingFileTransportOptions,\n): RotatingFileTransport {\n const codec = options.codec ?? ndjsonCodec();\n const maxBytes = normalizePositiveInteger(options.maxBytes, 10 * 1024 * 1024);\n const maxFiles = normalizeNonNegativeInteger(options.maxFiles, 5);\n const archivePath = options.archivePath ?? defaultArchivePath;\n const destination = createNodeFileDestination({\n name: options.name ?? \"rotating-file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: true,\n });\n let bytes = fileSize(options.path);\n\n const rotate = () => {\n destination.releaseSync?.();\n\n if (maxFiles === 0) {\n if (existsSync(options.path)) unlinkSync(options.path);\n bytes = 0;\n return;\n }\n\n const oldest = archivePath(options.path, maxFiles);\n if (existsSync(oldest)) unlinkSync(oldest);\n\n for (let index = maxFiles - 1; index >= 1; index -= 1) {\n const source = archivePath(options.path, index);\n if (existsSync(source)) renameSync(source, archivePath(options.path, index + 1));\n }\n\n if (existsSync(options.path)) renameSync(options.path, archivePath(options.path, 1));\n bytes = 0;\n };\n\n const writePayload = (payload: string | Uint8Array) => {\n const size = payloadBytes(payload);\n if (bytes > 0 && bytes + size > maxBytes) rotate();\n destination.write(payload);\n bytes += size;\n };\n\n const transport: RotatingFileTransport = {\n name: options.name ?? \"rotating-file\",\n minLevel: options.minLevel,\n log(event: LogEvent) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n writePayload(codec.encode(event));\n },\n logBatch(events: LogEvent[]) {\n for (const event of events) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel))\n continue;\n writePayload(codec.encode(event));\n }\n },\n flush() {\n return destination.flush();\n },\n flushSync: destination.flushSync,\n close() {\n return destination.close();\n },\n rotate,\n currentBytes: () => bytes,\n };\n\n return transport;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { closeSync, createWriteStream, existsSync, mkdirSync, openSync, renameSync, statSync, unlinkSync, writeSync } from "fs";
|
|
2
|
+
import { ndjsonCodec, toLevelValue } from "@loggerjs/core";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
//#region src/node-destination.ts
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
7
|
+
function byteLength(payload) {
|
|
8
|
+
return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
|
|
9
|
+
}
|
|
10
|
+
function coalescePayloads(payloads) {
|
|
11
|
+
if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
|
|
12
|
+
const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
|
|
13
|
+
return Buffer.concat(buffers);
|
|
14
|
+
}
|
|
15
|
+
function isEpipe(error) {
|
|
16
|
+
return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
|
|
17
|
+
}
|
|
18
|
+
function normalizeMinLength(value) {
|
|
19
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
|
|
20
|
+
return Math.floor(value);
|
|
21
|
+
}
|
|
22
|
+
function createNodeStreamDestination(options) {
|
|
23
|
+
const minLength = normalizeMinLength(options.minLength);
|
|
24
|
+
const ignoreEpipe = options.ignoreEpipe ?? false;
|
|
25
|
+
const waiters = [];
|
|
26
|
+
const buffer = [];
|
|
27
|
+
const pendingPayloads = [];
|
|
28
|
+
let bufferedBytes = 0;
|
|
29
|
+
let pendingWrites = 0;
|
|
30
|
+
let pendingDrains = 0;
|
|
31
|
+
let lastError;
|
|
32
|
+
let lastContext;
|
|
33
|
+
let closed = false;
|
|
34
|
+
const reportInternalError = (error, operation) => {
|
|
35
|
+
if (ignoreEpipe && isEpipe(error)) return;
|
|
36
|
+
lastContext?.reportInternalError(error, {
|
|
37
|
+
phase: "transport",
|
|
38
|
+
transport: options.name,
|
|
39
|
+
operation
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const settleWaitersIfIdle = () => {
|
|
43
|
+
if (pendingWrites + pendingDrains > 0) return;
|
|
44
|
+
if (waiters.length === 0) return;
|
|
45
|
+
const error = lastError;
|
|
46
|
+
lastError = void 0;
|
|
47
|
+
for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
|
|
48
|
+
else waiter.resolve();
|
|
49
|
+
};
|
|
50
|
+
const recordError = (error, operation) => {
|
|
51
|
+
if (ignoreEpipe && isEpipe(error)) {
|
|
52
|
+
closed = true;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
lastError = normalizeError(error);
|
|
56
|
+
reportInternalError(lastError, operation);
|
|
57
|
+
};
|
|
58
|
+
const onStreamError = (error) => {
|
|
59
|
+
recordError(error, "stream-error");
|
|
60
|
+
settleWaitersIfIdle();
|
|
61
|
+
};
|
|
62
|
+
const offError = () => options.stream.off?.("error", onStreamError);
|
|
63
|
+
options.stream.on?.("error", onStreamError);
|
|
64
|
+
const waitForDrain = () => {
|
|
65
|
+
if (!options.stream.once) return;
|
|
66
|
+
pendingDrains += 1;
|
|
67
|
+
options.stream.once("drain", () => {
|
|
68
|
+
pendingDrains -= 1;
|
|
69
|
+
settleWaitersIfIdle();
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
const removePending = (payload) => {
|
|
73
|
+
const index = pendingPayloads.indexOf(payload);
|
|
74
|
+
if (index >= 0) pendingPayloads.splice(index, 1);
|
|
75
|
+
};
|
|
76
|
+
const writeNow = (payload) => {
|
|
77
|
+
if (closed) return;
|
|
78
|
+
pendingPayloads.push(payload);
|
|
79
|
+
pendingWrites += 1;
|
|
80
|
+
try {
|
|
81
|
+
if (options.stream.write(payload, (error) => {
|
|
82
|
+
removePending(payload);
|
|
83
|
+
pendingWrites -= 1;
|
|
84
|
+
if (error) recordError(error, options.reportOperation ?? "write");
|
|
85
|
+
settleWaitersIfIdle();
|
|
86
|
+
}) === false) waitForDrain();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
removePending(payload);
|
|
89
|
+
pendingWrites -= 1;
|
|
90
|
+
recordError(error, options.reportOperation ?? "write");
|
|
91
|
+
settleWaitersIfIdle();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const flushBuffered = () => {
|
|
95
|
+
if (buffer.length === 0) return;
|
|
96
|
+
const payload = coalescePayloads(buffer.splice(0));
|
|
97
|
+
bufferedBytes = 0;
|
|
98
|
+
writeNow(payload);
|
|
99
|
+
};
|
|
100
|
+
const destination = {
|
|
101
|
+
write(payload, context) {
|
|
102
|
+
if (closed) return;
|
|
103
|
+
lastContext = context;
|
|
104
|
+
if (minLength > 0) {
|
|
105
|
+
buffer.push(payload);
|
|
106
|
+
bufferedBytes += byteLength(payload);
|
|
107
|
+
if (bufferedBytes >= minLength) flushBuffered();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
writeNow(payload);
|
|
111
|
+
},
|
|
112
|
+
flush() {
|
|
113
|
+
flushBuffered();
|
|
114
|
+
if (pendingWrites + pendingDrains === 0) {
|
|
115
|
+
const error = lastError;
|
|
116
|
+
lastError = void 0;
|
|
117
|
+
if (error) return Promise.reject(error);
|
|
118
|
+
return Promise.resolve();
|
|
119
|
+
}
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
waiters.push({
|
|
122
|
+
resolve,
|
|
123
|
+
reject
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
flushSync() {
|
|
128
|
+
if (!options.syncWrite) {
|
|
129
|
+
flushBuffered();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
for (const payload of buffer.splice(0)) options.syncWrite(payload);
|
|
133
|
+
bufferedBytes = 0;
|
|
134
|
+
for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
|
|
135
|
+
},
|
|
136
|
+
close() {
|
|
137
|
+
return destination.flush().then(() => new Promise((resolve, reject) => {
|
|
138
|
+
if (!options.stream.end) {
|
|
139
|
+
closed = true;
|
|
140
|
+
offError();
|
|
141
|
+
resolve();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
options.stream.end((error) => {
|
|
145
|
+
closed = true;
|
|
146
|
+
offError();
|
|
147
|
+
if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
|
|
148
|
+
else resolve();
|
|
149
|
+
});
|
|
150
|
+
}), (error) => {
|
|
151
|
+
offError();
|
|
152
|
+
return Promise.reject(error);
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
closeSync() {
|
|
156
|
+
destination.flushSync();
|
|
157
|
+
closed = true;
|
|
158
|
+
offError();
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
return destination;
|
|
162
|
+
}
|
|
163
|
+
function createNodeFileDestination(options) {
|
|
164
|
+
const flags = options.flags ?? (options.append === false ? "w" : "a");
|
|
165
|
+
if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });
|
|
166
|
+
let fd;
|
|
167
|
+
const getFd = () => {
|
|
168
|
+
fd ??= openSync(options.path, flags);
|
|
169
|
+
return fd;
|
|
170
|
+
};
|
|
171
|
+
const syncWrite = (payload) => {
|
|
172
|
+
if (typeof payload === "string") writeSync(getFd(), payload);
|
|
173
|
+
else writeSync(getFd(), payload);
|
|
174
|
+
};
|
|
175
|
+
if (options.sync) {
|
|
176
|
+
let closed = false;
|
|
177
|
+
const releaseSync = () => {
|
|
178
|
+
if (fd !== void 0) {
|
|
179
|
+
closeSync(fd);
|
|
180
|
+
fd = void 0;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
return {
|
|
184
|
+
write(payload) {
|
|
185
|
+
if (closed) return;
|
|
186
|
+
syncWrite(payload);
|
|
187
|
+
},
|
|
188
|
+
flush() {
|
|
189
|
+
return Promise.resolve();
|
|
190
|
+
},
|
|
191
|
+
flushSync() {},
|
|
192
|
+
close() {
|
|
193
|
+
releaseSync();
|
|
194
|
+
closed = true;
|
|
195
|
+
return Promise.resolve();
|
|
196
|
+
},
|
|
197
|
+
closeSync() {
|
|
198
|
+
releaseSync();
|
|
199
|
+
closed = true;
|
|
200
|
+
},
|
|
201
|
+
releaseSync
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const stream = createWriteStream(options.path, { flags });
|
|
205
|
+
const destination = createNodeStreamDestination({
|
|
206
|
+
name: options.name,
|
|
207
|
+
stream,
|
|
208
|
+
minLength: options.minLength,
|
|
209
|
+
syncWrite
|
|
210
|
+
});
|
|
211
|
+
const releaseSync = () => {
|
|
212
|
+
if (fd !== void 0) {
|
|
213
|
+
closeSync(fd);
|
|
214
|
+
fd = void 0;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
return {
|
|
218
|
+
...destination,
|
|
219
|
+
stream,
|
|
220
|
+
close() {
|
|
221
|
+
return destination.close().finally(releaseSync);
|
|
222
|
+
},
|
|
223
|
+
closeSync() {
|
|
224
|
+
destination.closeSync();
|
|
225
|
+
releaseSync();
|
|
226
|
+
},
|
|
227
|
+
releaseSync
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/rotating-file-transport.ts
|
|
232
|
+
const textEncoder = new TextEncoder();
|
|
233
|
+
function payloadBytes(payload) {
|
|
234
|
+
return typeof payload === "string" ? textEncoder.encode(payload).byteLength : payload.byteLength;
|
|
235
|
+
}
|
|
236
|
+
function normalizePositiveInteger(value, fallback) {
|
|
237
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return fallback;
|
|
238
|
+
return Math.floor(value);
|
|
239
|
+
}
|
|
240
|
+
function normalizeNonNegativeInteger(value, fallback) {
|
|
241
|
+
if (value === void 0 || !Number.isFinite(value) || value < 0) return fallback;
|
|
242
|
+
return Math.floor(value);
|
|
243
|
+
}
|
|
244
|
+
function defaultArchivePath(path, index) {
|
|
245
|
+
return `${path}.${index}`;
|
|
246
|
+
}
|
|
247
|
+
function fileSize(path) {
|
|
248
|
+
try {
|
|
249
|
+
return statSync(path).size;
|
|
250
|
+
} catch {
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function rotatingFileTransport(options) {
|
|
255
|
+
const codec = options.codec ?? ndjsonCodec();
|
|
256
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, 10 * 1024 * 1024);
|
|
257
|
+
const maxFiles = normalizeNonNegativeInteger(options.maxFiles, 5);
|
|
258
|
+
const archivePath = options.archivePath ?? defaultArchivePath;
|
|
259
|
+
const destination = createNodeFileDestination({
|
|
260
|
+
name: options.name ?? "rotating-file",
|
|
261
|
+
path: options.path,
|
|
262
|
+
flags: options.flags,
|
|
263
|
+
append: options.append,
|
|
264
|
+
mkdir: options.mkdir,
|
|
265
|
+
sync: true
|
|
266
|
+
});
|
|
267
|
+
let bytes = fileSize(options.path);
|
|
268
|
+
const rotate = () => {
|
|
269
|
+
destination.releaseSync?.();
|
|
270
|
+
if (maxFiles === 0) {
|
|
271
|
+
if (existsSync(options.path)) unlinkSync(options.path);
|
|
272
|
+
bytes = 0;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const oldest = archivePath(options.path, maxFiles);
|
|
276
|
+
if (existsSync(oldest)) unlinkSync(oldest);
|
|
277
|
+
for (let index = maxFiles - 1; index >= 1; index -= 1) {
|
|
278
|
+
const source = archivePath(options.path, index);
|
|
279
|
+
if (existsSync(source)) renameSync(source, archivePath(options.path, index + 1));
|
|
280
|
+
}
|
|
281
|
+
if (existsSync(options.path)) renameSync(options.path, archivePath(options.path, 1));
|
|
282
|
+
bytes = 0;
|
|
283
|
+
};
|
|
284
|
+
const writePayload = (payload) => {
|
|
285
|
+
const size = payloadBytes(payload);
|
|
286
|
+
if (bytes > 0 && bytes + size > maxBytes) rotate();
|
|
287
|
+
destination.write(payload);
|
|
288
|
+
bytes += size;
|
|
289
|
+
};
|
|
290
|
+
return {
|
|
291
|
+
name: options.name ?? "rotating-file",
|
|
292
|
+
minLevel: options.minLevel,
|
|
293
|
+
log(event) {
|
|
294
|
+
if (options.minLevel !== void 0 && event.level < toLevelValue(options.minLevel)) return;
|
|
295
|
+
writePayload(codec.encode(event));
|
|
296
|
+
},
|
|
297
|
+
logBatch(events) {
|
|
298
|
+
for (const event of events) {
|
|
299
|
+
if (options.minLevel !== void 0 && event.level < toLevelValue(options.minLevel)) continue;
|
|
300
|
+
writePayload(codec.encode(event));
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
flush() {
|
|
304
|
+
return destination.flush();
|
|
305
|
+
},
|
|
306
|
+
flushSync: destination.flushSync,
|
|
307
|
+
close() {
|
|
308
|
+
return destination.close();
|
|
309
|
+
},
|
|
310
|
+
rotate,
|
|
311
|
+
currentBytes: () => bytes
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
export { rotatingFileTransport };
|
|
316
|
+
|
|
317
|
+
//# sourceMappingURL=rotating-file-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotating-file-transport.js","names":[],"sources":["../src/node-destination.ts","../src/rotating-file-transport.ts"],"sourcesContent":["import { closeSync, createWriteStream, mkdirSync, openSync, writeSync, type WriteStream } from \"fs\";\nimport { dirname } from \"path\";\nimport type { TransportContext } from \"@loggerjs/core\";\nimport type { WritableLike } from \"./internal-types\";\n\nexport interface NodeDestination {\n stream?: WriteStream;\n write: (payload: string | Uint8Array, context?: TransportContext) => void;\n flush: () => Promise<void>;\n flushSync: () => void;\n close: () => Promise<void>;\n closeSync: () => void;\n releaseSync?: () => void;\n}\n\nexport interface NodeStreamDestinationOptions {\n name: string;\n stream: WritableLike;\n minLength?: number;\n ignoreEpipe?: boolean;\n reportOperation?: string;\n syncWrite?: (payload: string | Uint8Array) => void;\n}\n\nexport interface NodeFileDestinationOptions {\n name: string;\n path: string;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\ninterface FlushWaiter {\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst normalizeError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nfunction byteLength(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? encoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction coalescePayloads(payloads: Array<string | Uint8Array>): string | Uint8Array {\n if (payloads.every((payload) => typeof payload === \"string\")) {\n return payloads.join(\"\");\n }\n const buffers = payloads.map((payload) =>\n typeof payload === \"string\" ? Buffer.from(payload) : Buffer.from(payload),\n );\n return Buffer.concat(buffers);\n}\n\nfunction isEpipe(error: unknown): boolean {\n return (\n Boolean(error) && typeof error === \"object\" && (error as { code?: unknown }).code === \"EPIPE\"\n );\n}\n\nfunction normalizeMinLength(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return 0;\n return Math.floor(value);\n}\n\nexport function createNodeStreamDestination(\n options: NodeStreamDestinationOptions,\n): NodeDestination {\n const minLength = normalizeMinLength(options.minLength);\n const ignoreEpipe = options.ignoreEpipe ?? false;\n const waiters: FlushWaiter[] = [];\n const buffer: Array<string | Uint8Array> = [];\n const pendingPayloads: Array<string | Uint8Array> = [];\n let bufferedBytes = 0;\n let pendingWrites = 0;\n let pendingDrains = 0;\n let lastError: Error | undefined;\n let lastContext: TransportContext | undefined;\n let closed = false;\n\n const reportInternalError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) return;\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name,\n operation,\n });\n };\n\n const settleWaitersIfIdle = () => {\n if (pendingWrites + pendingDrains > 0) return;\n if (waiters.length === 0) return;\n const error = lastError;\n lastError = undefined;\n for (const waiter of waiters.splice(0)) {\n if (error) waiter.reject(error);\n else waiter.resolve();\n }\n };\n\n const recordError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) {\n closed = true;\n return;\n }\n lastError = normalizeError(error);\n reportInternalError(lastError, operation);\n };\n\n const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\n settleWaitersIfIdle();\n };\n const offError = () => options.stream.off?.(\"error\", onStreamError);\n options.stream.on?.(\"error\", onStreamError);\n\n const waitForDrain = () => {\n if (!options.stream.once) return;\n pendingDrains += 1;\n options.stream.once(\"drain\", () => {\n pendingDrains -= 1;\n settleWaitersIfIdle();\n });\n };\n\n const removePending = (payload: string | Uint8Array) => {\n const index = pendingPayloads.indexOf(payload);\n if (index >= 0) pendingPayloads.splice(index, 1);\n };\n\n const writeNow = (payload: string | Uint8Array) => {\n if (closed) return;\n pendingPayloads.push(payload);\n pendingWrites += 1;\n try {\n const result = options.stream.write(payload, (error?: Error | null) => {\n removePending(payload);\n pendingWrites -= 1;\n if (error) recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n });\n if (result === false) waitForDrain();\n } catch (error) {\n removePending(payload);\n pendingWrites -= 1;\n recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n }\n };\n\n const flushBuffered = () => {\n if (buffer.length === 0) return;\n const payload = coalescePayloads(buffer.splice(0));\n bufferedBytes = 0;\n writeNow(payload);\n };\n\n const destination: NodeDestination = {\n write(payload, context) {\n if (closed) return;\n lastContext = context;\n if (minLength > 0) {\n buffer.push(payload);\n bufferedBytes += byteLength(payload);\n if (bufferedBytes >= minLength) flushBuffered();\n return;\n }\n writeNow(payload);\n },\n flush() {\n flushBuffered();\n if (pendingWrites + pendingDrains === 0) {\n const error = lastError;\n lastError = undefined;\n if (error) return Promise.reject(error);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n waiters.push({ resolve, reject });\n });\n },\n flushSync() {\n if (!options.syncWrite) {\n flushBuffered();\n return;\n }\n for (const payload of buffer.splice(0)) options.syncWrite(payload);\n bufferedBytes = 0;\n for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);\n },\n close() {\n return destination.flush().then(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!options.stream.end) {\n closed = true;\n offError();\n resolve();\n return;\n }\n options.stream.end((error?: Error | null) => {\n closed = true;\n offError();\n if (error && !(ignoreEpipe && isEpipe(error))) reject(error);\n else resolve();\n });\n }),\n (error: unknown) => {\n offError();\n return Promise.reject(error);\n },\n );\n },\n closeSync() {\n destination.flushSync();\n closed = true;\n offError();\n },\n };\n return destination;\n}\n\nexport function createNodeFileDestination(options: NodeFileDestinationOptions): NodeDestination {\n const flags = options.flags ?? (options.append === false ? \"w\" : \"a\");\n if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });\n\n let fd: number | undefined;\n const getFd = () => {\n fd ??= openSync(options.path, flags);\n return fd;\n };\n const syncWrite = (payload: string | Uint8Array) => {\n if (typeof payload === \"string\") writeSync(getFd(), payload);\n else writeSync(getFd(), payload);\n };\n\n if (options.sync) {\n let closed = false;\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n write(payload) {\n if (closed) return;\n syncWrite(payload);\n },\n flush() {\n return Promise.resolve();\n },\n flushSync() {},\n close() {\n releaseSync();\n closed = true;\n return Promise.resolve();\n },\n closeSync() {\n releaseSync();\n closed = true;\n },\n releaseSync,\n };\n }\n\n const stream = createWriteStream(options.path, { flags });\n const destination = createNodeStreamDestination({\n name: options.name,\n stream,\n minLength: options.minLength,\n syncWrite,\n });\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n ...destination,\n stream,\n close() {\n return destination.close().finally(releaseSync);\n },\n closeSync() {\n destination.closeSync();\n releaseSync();\n },\n releaseSync,\n };\n}\n","import { existsSync, renameSync, statSync, unlinkSync } from \"fs\";\nimport {\n ndjsonCodec,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface RotatingFileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n maxBytes?: number;\n maxFiles?: number;\n archivePath?: (path: string, index: number) => string;\n}\n\nexport interface RotatingFileTransport extends Transport {\n rotate: () => void;\n flushSync: () => void;\n currentBytes: () => number;\n}\n\nconst textEncoder = new TextEncoder();\n\nfunction payloadBytes(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? textEncoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction normalizePositiveInteger(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return fallback;\n return Math.floor(value);\n}\n\nfunction normalizeNonNegativeInteger(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value) || value < 0) return fallback;\n return Math.floor(value);\n}\n\nfunction defaultArchivePath(path: string, index: number): string {\n return `${path}.${index}`;\n}\n\nfunction fileSize(path: string): number {\n try {\n return statSync(path).size;\n } catch {\n return 0;\n }\n}\n\nexport function rotatingFileTransport(\n options: RotatingFileTransportOptions,\n): RotatingFileTransport {\n const codec = options.codec ?? ndjsonCodec();\n const maxBytes = normalizePositiveInteger(options.maxBytes, 10 * 1024 * 1024);\n const maxFiles = normalizeNonNegativeInteger(options.maxFiles, 5);\n const archivePath = options.archivePath ?? defaultArchivePath;\n const destination = createNodeFileDestination({\n name: options.name ?? \"rotating-file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: true,\n });\n let bytes = fileSize(options.path);\n\n const rotate = () => {\n destination.releaseSync?.();\n\n if (maxFiles === 0) {\n if (existsSync(options.path)) unlinkSync(options.path);\n bytes = 0;\n return;\n }\n\n const oldest = archivePath(options.path, maxFiles);\n if (existsSync(oldest)) unlinkSync(oldest);\n\n for (let index = maxFiles - 1; index >= 1; index -= 1) {\n const source = archivePath(options.path, index);\n if (existsSync(source)) renameSync(source, archivePath(options.path, index + 1));\n }\n\n if (existsSync(options.path)) renameSync(options.path, archivePath(options.path, 1));\n bytes = 0;\n };\n\n const writePayload = (payload: string | Uint8Array) => {\n const size = payloadBytes(payload);\n if (bytes > 0 && bytes + size > maxBytes) rotate();\n destination.write(payload);\n bytes += size;\n };\n\n const transport: RotatingFileTransport = {\n name: options.name ?? \"rotating-file\",\n minLevel: options.minLevel,\n log(event: LogEvent) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n writePayload(codec.encode(event));\n },\n logBatch(events: LogEvent[]) {\n for (const event of events) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel))\n continue;\n writePayload(codec.encode(event));\n }\n },\n flush() {\n return destination.flush();\n },\n flushSync: destination.flushSync,\n close() {\n return destination.close();\n },\n rotate,\n currentBytes: () => bytes,\n };\n\n return transport;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
//#region src/serverless-integration.ts
|
|
4
|
+
const defaultRandom = () => Math.random();
|
|
5
|
+
let coldStart = true;
|
|
6
|
+
function isPromiseLike(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
8
|
+
}
|
|
9
|
+
function defaultLevel(error) {
|
|
10
|
+
return error ? "error" : "info";
|
|
11
|
+
}
|
|
12
|
+
function defaultRequestId(event, context) {
|
|
13
|
+
const ctx = context;
|
|
14
|
+
const evt = event;
|
|
15
|
+
return ctx?.awsRequestId ?? evt?.requestContext?.requestId ?? evt?.headers?.["x-request-id"] ?? evt?.headers?.["X-Request-Id"];
|
|
16
|
+
}
|
|
17
|
+
function defaultOperation(event, context) {
|
|
18
|
+
const ctx = context;
|
|
19
|
+
const evt = event;
|
|
20
|
+
return evt?.routeKey ?? evt?.requestContext?.routeKey ?? (evt?.requestContext?.http?.method && evt.requestContext.http.path ? `${evt.requestContext.http.method} ${evt.requestContext.http.path}` : void 0) ?? (evt?.httpMethod && (evt.rawPath ?? evt.path) ? `${evt.httpMethod} ${evt.rawPath ?? evt.path}` : void 0) ?? ctx?.functionName;
|
|
21
|
+
}
|
|
22
|
+
function normalizeUnknown(value) {
|
|
23
|
+
return (0, _loggerjs_core.normalizeValue)(value, {
|
|
24
|
+
maxDepth: 5,
|
|
25
|
+
maxObjectKeys: 120
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function serverlessIntegration(logger, handler, options = {}) {
|
|
29
|
+
const name = options.name ?? "serverless";
|
|
30
|
+
const platform = options.platform ?? "serverless";
|
|
31
|
+
const captureSuccessful = options.captureSuccessful ?? options.captureAll ?? true;
|
|
32
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
33
|
+
const random = options.random ?? defaultRandom;
|
|
34
|
+
const bindContext = options.bindContext ?? true;
|
|
35
|
+
const levelFor = options.level ?? defaultLevel;
|
|
36
|
+
return (event, context, callback) => {
|
|
37
|
+
const started = Date.now();
|
|
38
|
+
const currentColdStart = coldStart;
|
|
39
|
+
coldStart = false;
|
|
40
|
+
const requestId = options.getRequestId?.(event, context) ?? defaultRequestId(event, context);
|
|
41
|
+
const operation = options.getOperation?.(event, context) ?? defaultOperation(event, context);
|
|
42
|
+
let captured = false;
|
|
43
|
+
const shouldCapture = (error) => {
|
|
44
|
+
if (error) return true;
|
|
45
|
+
if (!captureSuccessful) return false;
|
|
46
|
+
return sampleRate >= 1 || random() < sampleRate;
|
|
47
|
+
};
|
|
48
|
+
const capture = (error, result) => {
|
|
49
|
+
if (captured || !shouldCapture(error)) return;
|
|
50
|
+
captured = true;
|
|
51
|
+
const durationMs = Date.now() - started;
|
|
52
|
+
const info = {
|
|
53
|
+
context,
|
|
54
|
+
event,
|
|
55
|
+
operation,
|
|
56
|
+
requestId
|
|
57
|
+
};
|
|
58
|
+
logger.log(levelFor(error, durationMs, info), `Serverless ${operation ?? name}`, {
|
|
59
|
+
error,
|
|
60
|
+
serverless: {
|
|
61
|
+
kind: name,
|
|
62
|
+
platform,
|
|
63
|
+
operation,
|
|
64
|
+
requestId,
|
|
65
|
+
coldStart: currentColdStart,
|
|
66
|
+
durationMs,
|
|
67
|
+
event: options.captureEvent ? options.normalizeEvent?.(event) ?? normalizeUnknown(event) : void 0,
|
|
68
|
+
result: options.captureResult && result !== void 0 ? options.normalizeResult?.(result) ?? normalizeUnknown(result) : void 0
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
const wrappedCallback = callback ? (error, result) => {
|
|
73
|
+
capture(error, result);
|
|
74
|
+
callback(error, result);
|
|
75
|
+
} : void 0;
|
|
76
|
+
const invoke = () => {
|
|
77
|
+
try {
|
|
78
|
+
const result = handler(event, context, wrappedCallback);
|
|
79
|
+
if (isPromiseLike(result)) return result.then((value) => {
|
|
80
|
+
capture(void 0, value);
|
|
81
|
+
return value;
|
|
82
|
+
}, (error) => {
|
|
83
|
+
capture(error);
|
|
84
|
+
throw error;
|
|
85
|
+
});
|
|
86
|
+
if (result !== void 0 || !wrappedCallback) capture(void 0, result);
|
|
87
|
+
return result;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
capture(error);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
if (!bindContext) return invoke();
|
|
94
|
+
return (0, _loggerjs_core.withContext)({
|
|
95
|
+
functionName: context?.functionName,
|
|
96
|
+
requestId,
|
|
97
|
+
serverlessPlatform: platform
|
|
98
|
+
}, invoke);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
exports.serverlessIntegration = serverlessIntegration;
|
|
103
|
+
|
|
104
|
+
//# sourceMappingURL=serverless-integration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverless-integration.cjs","names":[],"sources":["../src/serverless-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n withContext,\n type LoggerLevel,\n type LoggerLike,\n type LogData,\n} from \"@loggerjs/core\";\n\nexport type ServerlessCallback<TResult> = (error?: unknown, result?: TResult) => void;\n\nexport type ServerlessHandler<TEvent, TContext, TResult> = (\n event: TEvent,\n context: TContext,\n callback?: ServerlessCallback<TResult>,\n) => TResult | Promise<TResult> | void;\n\nexport interface ServerlessContextLike {\n awsRequestId?: string;\n functionName?: string;\n functionVersion?: string;\n invokedFunctionArn?: string;\n [key: string]: unknown;\n}\n\nexport interface ServerlessEventLike {\n httpMethod?: string;\n path?: string;\n rawPath?: string;\n routeKey?: string;\n headers?: Record<string, string | undefined>;\n requestContext?: {\n requestId?: string;\n http?: {\n method?: string;\n path?: string;\n };\n routeKey?: string;\n };\n [key: string]: unknown;\n}\n\nexport interface ServerlessInvocationInfo<TEvent, TContext> {\n event: TEvent;\n context: TContext;\n requestId?: string;\n operation?: string;\n}\n\nexport interface ServerlessIntegrationOptions<TEvent, TContext, TResult> {\n name?: string;\n platform?: string;\n captureSuccessful?: boolean;\n captureAll?: boolean;\n sampleRate?: number;\n random?: () => number;\n captureEvent?: boolean;\n captureResult?: boolean;\n bindContext?: boolean;\n getRequestId?: (event: TEvent, context: TContext) => string | undefined;\n getOperation?: (event: TEvent, context: TContext) => string | undefined;\n level?: (\n error: unknown,\n durationMs: number,\n info: ServerlessInvocationInfo<TEvent, TContext>,\n ) => LoggerLevel;\n normalizeEvent?: (event: TEvent) => unknown;\n normalizeResult?: (result: TResult) => unknown;\n}\n\nconst defaultRandom = () => Math.random();\nlet coldStart = true;\n\nfunction isPromiseLike<TResult>(value: unknown): value is PromiseLike<TResult> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\nfunction defaultLevel(error: unknown): LoggerLevel {\n return error ? \"error\" : \"info\";\n}\n\nfunction defaultRequestId(event: unknown, context: unknown): string | undefined {\n const ctx = context as ServerlessContextLike | undefined;\n const evt = event as ServerlessEventLike | undefined;\n return (\n ctx?.awsRequestId ??\n evt?.requestContext?.requestId ??\n evt?.headers?.[\"x-request-id\"] ??\n evt?.headers?.[\"X-Request-Id\"]\n );\n}\n\nfunction defaultOperation(event: unknown, context: unknown): string | undefined {\n const ctx = context as ServerlessContextLike | undefined;\n const evt = event as ServerlessEventLike | undefined;\n return (\n evt?.routeKey ??\n evt?.requestContext?.routeKey ??\n (evt?.requestContext?.http?.method && evt.requestContext.http.path\n ? `${evt.requestContext.http.method} ${evt.requestContext.http.path}`\n : undefined) ??\n (evt?.httpMethod && (evt.rawPath ?? evt.path)\n ? `${evt.httpMethod} ${evt.rawPath ?? evt.path}`\n : undefined) ??\n ctx?.functionName\n );\n}\n\nfunction normalizeUnknown(value: unknown) {\n return normalizeValue(value, { maxDepth: 5, maxObjectKeys: 120 });\n}\n\nexport function serverlessIntegration<TEvent, TContext, TResult>(\n logger: LoggerLike,\n handler: ServerlessHandler<TEvent, TContext, TResult>,\n options: ServerlessIntegrationOptions<TEvent, TContext, TResult> = {},\n): ServerlessHandler<TEvent, TContext, TResult> {\n const name = options.name ?? \"serverless\";\n const platform = options.platform ?? \"serverless\";\n const captureSuccessful = options.captureSuccessful ?? options.captureAll ?? true;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const bindContext = options.bindContext ?? true;\n const levelFor = options.level ?? defaultLevel;\n\n return (event, context, callback) => {\n const started = Date.now();\n const currentColdStart = coldStart;\n coldStart = false;\n const requestId = options.getRequestId?.(event, context) ?? defaultRequestId(event, context);\n const operation = options.getOperation?.(event, context) ?? defaultOperation(event, context);\n let captured = false;\n\n const shouldCapture = (error: unknown) => {\n if (error) return true;\n if (!captureSuccessful) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n const capture = (error: unknown, result?: TResult) => {\n if (captured || !shouldCapture(error)) return;\n captured = true;\n const durationMs = Date.now() - started;\n const info: ServerlessInvocationInfo<TEvent, TContext> = {\n context,\n event,\n operation,\n requestId,\n };\n logger.log(levelFor(error, durationMs, info), `Serverless ${operation ?? name}`, {\n error,\n serverless: {\n kind: name,\n platform,\n operation,\n requestId,\n coldStart: currentColdStart,\n durationMs,\n event: options.captureEvent\n ? (options.normalizeEvent?.(event) ?? normalizeUnknown(event))\n : undefined,\n result:\n options.captureResult && result !== undefined\n ? (options.normalizeResult?.(result) ?? normalizeUnknown(result))\n : undefined,\n },\n } as LogData);\n };\n\n const wrappedCallback = callback\n ? (error?: unknown, result?: TResult) => {\n capture(error, result);\n callback(error, result);\n }\n : undefined;\n\n const invoke = () => {\n try {\n const result = handler(event, context, wrappedCallback);\n if (isPromiseLike<TResult>(result)) {\n return result.then(\n (value) => {\n capture(undefined, value);\n return value;\n },\n (error) => {\n capture(error);\n throw error;\n },\n );\n }\n if (result !== undefined || !wrappedCallback) capture(undefined, result as TResult);\n return result;\n } catch (error) {\n capture(error);\n throw error;\n }\n };\n\n if (!bindContext) return invoke();\n return withContext(\n {\n functionName: (context as ServerlessContextLike | undefined)?.functionName,\n requestId,\n serverlessPlatform: platform,\n },\n invoke,\n );\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { normalizeValue, withContext } from "@loggerjs/core";
|
|
2
|
+
//#region src/serverless-integration.ts
|
|
3
|
+
const defaultRandom = () => Math.random();
|
|
4
|
+
let coldStart = true;
|
|
5
|
+
function isPromiseLike(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
7
|
+
}
|
|
8
|
+
function defaultLevel(error) {
|
|
9
|
+
return error ? "error" : "info";
|
|
10
|
+
}
|
|
11
|
+
function defaultRequestId(event, context) {
|
|
12
|
+
const ctx = context;
|
|
13
|
+
const evt = event;
|
|
14
|
+
return ctx?.awsRequestId ?? evt?.requestContext?.requestId ?? evt?.headers?.["x-request-id"] ?? evt?.headers?.["X-Request-Id"];
|
|
15
|
+
}
|
|
16
|
+
function defaultOperation(event, context) {
|
|
17
|
+
const ctx = context;
|
|
18
|
+
const evt = event;
|
|
19
|
+
return evt?.routeKey ?? evt?.requestContext?.routeKey ?? (evt?.requestContext?.http?.method && evt.requestContext.http.path ? `${evt.requestContext.http.method} ${evt.requestContext.http.path}` : void 0) ?? (evt?.httpMethod && (evt.rawPath ?? evt.path) ? `${evt.httpMethod} ${evt.rawPath ?? evt.path}` : void 0) ?? ctx?.functionName;
|
|
20
|
+
}
|
|
21
|
+
function normalizeUnknown(value) {
|
|
22
|
+
return normalizeValue(value, {
|
|
23
|
+
maxDepth: 5,
|
|
24
|
+
maxObjectKeys: 120
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function serverlessIntegration(logger, handler, options = {}) {
|
|
28
|
+
const name = options.name ?? "serverless";
|
|
29
|
+
const platform = options.platform ?? "serverless";
|
|
30
|
+
const captureSuccessful = options.captureSuccessful ?? options.captureAll ?? true;
|
|
31
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
32
|
+
const random = options.random ?? defaultRandom;
|
|
33
|
+
const bindContext = options.bindContext ?? true;
|
|
34
|
+
const levelFor = options.level ?? defaultLevel;
|
|
35
|
+
return (event, context, callback) => {
|
|
36
|
+
const started = Date.now();
|
|
37
|
+
const currentColdStart = coldStart;
|
|
38
|
+
coldStart = false;
|
|
39
|
+
const requestId = options.getRequestId?.(event, context) ?? defaultRequestId(event, context);
|
|
40
|
+
const operation = options.getOperation?.(event, context) ?? defaultOperation(event, context);
|
|
41
|
+
let captured = false;
|
|
42
|
+
const shouldCapture = (error) => {
|
|
43
|
+
if (error) return true;
|
|
44
|
+
if (!captureSuccessful) return false;
|
|
45
|
+
return sampleRate >= 1 || random() < sampleRate;
|
|
46
|
+
};
|
|
47
|
+
const capture = (error, result) => {
|
|
48
|
+
if (captured || !shouldCapture(error)) return;
|
|
49
|
+
captured = true;
|
|
50
|
+
const durationMs = Date.now() - started;
|
|
51
|
+
const info = {
|
|
52
|
+
context,
|
|
53
|
+
event,
|
|
54
|
+
operation,
|
|
55
|
+
requestId
|
|
56
|
+
};
|
|
57
|
+
logger.log(levelFor(error, durationMs, info), `Serverless ${operation ?? name}`, {
|
|
58
|
+
error,
|
|
59
|
+
serverless: {
|
|
60
|
+
kind: name,
|
|
61
|
+
platform,
|
|
62
|
+
operation,
|
|
63
|
+
requestId,
|
|
64
|
+
coldStart: currentColdStart,
|
|
65
|
+
durationMs,
|
|
66
|
+
event: options.captureEvent ? options.normalizeEvent?.(event) ?? normalizeUnknown(event) : void 0,
|
|
67
|
+
result: options.captureResult && result !== void 0 ? options.normalizeResult?.(result) ?? normalizeUnknown(result) : void 0
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
const wrappedCallback = callback ? (error, result) => {
|
|
72
|
+
capture(error, result);
|
|
73
|
+
callback(error, result);
|
|
74
|
+
} : void 0;
|
|
75
|
+
const invoke = () => {
|
|
76
|
+
try {
|
|
77
|
+
const result = handler(event, context, wrappedCallback);
|
|
78
|
+
if (isPromiseLike(result)) return result.then((value) => {
|
|
79
|
+
capture(void 0, value);
|
|
80
|
+
return value;
|
|
81
|
+
}, (error) => {
|
|
82
|
+
capture(error);
|
|
83
|
+
throw error;
|
|
84
|
+
});
|
|
85
|
+
if (result !== void 0 || !wrappedCallback) capture(void 0, result);
|
|
86
|
+
return result;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
capture(error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
if (!bindContext) return invoke();
|
|
93
|
+
return withContext({
|
|
94
|
+
functionName: context?.functionName,
|
|
95
|
+
requestId,
|
|
96
|
+
serverlessPlatform: platform
|
|
97
|
+
}, invoke);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { serverlessIntegration };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=serverless-integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverless-integration.js","names":[],"sources":["../src/serverless-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n withContext,\n type LoggerLevel,\n type LoggerLike,\n type LogData,\n} from \"@loggerjs/core\";\n\nexport type ServerlessCallback<TResult> = (error?: unknown, result?: TResult) => void;\n\nexport type ServerlessHandler<TEvent, TContext, TResult> = (\n event: TEvent,\n context: TContext,\n callback?: ServerlessCallback<TResult>,\n) => TResult | Promise<TResult> | void;\n\nexport interface ServerlessContextLike {\n awsRequestId?: string;\n functionName?: string;\n functionVersion?: string;\n invokedFunctionArn?: string;\n [key: string]: unknown;\n}\n\nexport interface ServerlessEventLike {\n httpMethod?: string;\n path?: string;\n rawPath?: string;\n routeKey?: string;\n headers?: Record<string, string | undefined>;\n requestContext?: {\n requestId?: string;\n http?: {\n method?: string;\n path?: string;\n };\n routeKey?: string;\n };\n [key: string]: unknown;\n}\n\nexport interface ServerlessInvocationInfo<TEvent, TContext> {\n event: TEvent;\n context: TContext;\n requestId?: string;\n operation?: string;\n}\n\nexport interface ServerlessIntegrationOptions<TEvent, TContext, TResult> {\n name?: string;\n platform?: string;\n captureSuccessful?: boolean;\n captureAll?: boolean;\n sampleRate?: number;\n random?: () => number;\n captureEvent?: boolean;\n captureResult?: boolean;\n bindContext?: boolean;\n getRequestId?: (event: TEvent, context: TContext) => string | undefined;\n getOperation?: (event: TEvent, context: TContext) => string | undefined;\n level?: (\n error: unknown,\n durationMs: number,\n info: ServerlessInvocationInfo<TEvent, TContext>,\n ) => LoggerLevel;\n normalizeEvent?: (event: TEvent) => unknown;\n normalizeResult?: (result: TResult) => unknown;\n}\n\nconst defaultRandom = () => Math.random();\nlet coldStart = true;\n\nfunction isPromiseLike<TResult>(value: unknown): value is PromiseLike<TResult> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\nfunction defaultLevel(error: unknown): LoggerLevel {\n return error ? \"error\" : \"info\";\n}\n\nfunction defaultRequestId(event: unknown, context: unknown): string | undefined {\n const ctx = context as ServerlessContextLike | undefined;\n const evt = event as ServerlessEventLike | undefined;\n return (\n ctx?.awsRequestId ??\n evt?.requestContext?.requestId ??\n evt?.headers?.[\"x-request-id\"] ??\n evt?.headers?.[\"X-Request-Id\"]\n );\n}\n\nfunction defaultOperation(event: unknown, context: unknown): string | undefined {\n const ctx = context as ServerlessContextLike | undefined;\n const evt = event as ServerlessEventLike | undefined;\n return (\n evt?.routeKey ??\n evt?.requestContext?.routeKey ??\n (evt?.requestContext?.http?.method && evt.requestContext.http.path\n ? `${evt.requestContext.http.method} ${evt.requestContext.http.path}`\n : undefined) ??\n (evt?.httpMethod && (evt.rawPath ?? evt.path)\n ? `${evt.httpMethod} ${evt.rawPath ?? evt.path}`\n : undefined) ??\n ctx?.functionName\n );\n}\n\nfunction normalizeUnknown(value: unknown) {\n return normalizeValue(value, { maxDepth: 5, maxObjectKeys: 120 });\n}\n\nexport function serverlessIntegration<TEvent, TContext, TResult>(\n logger: LoggerLike,\n handler: ServerlessHandler<TEvent, TContext, TResult>,\n options: ServerlessIntegrationOptions<TEvent, TContext, TResult> = {},\n): ServerlessHandler<TEvent, TContext, TResult> {\n const name = options.name ?? \"serverless\";\n const platform = options.platform ?? \"serverless\";\n const captureSuccessful = options.captureSuccessful ?? options.captureAll ?? true;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? defaultRandom;\n const bindContext = options.bindContext ?? true;\n const levelFor = options.level ?? defaultLevel;\n\n return (event, context, callback) => {\n const started = Date.now();\n const currentColdStart = coldStart;\n coldStart = false;\n const requestId = options.getRequestId?.(event, context) ?? defaultRequestId(event, context);\n const operation = options.getOperation?.(event, context) ?? defaultOperation(event, context);\n let captured = false;\n\n const shouldCapture = (error: unknown) => {\n if (error) return true;\n if (!captureSuccessful) return false;\n return sampleRate >= 1 || random() < sampleRate;\n };\n\n const capture = (error: unknown, result?: TResult) => {\n if (captured || !shouldCapture(error)) return;\n captured = true;\n const durationMs = Date.now() - started;\n const info: ServerlessInvocationInfo<TEvent, TContext> = {\n context,\n event,\n operation,\n requestId,\n };\n logger.log(levelFor(error, durationMs, info), `Serverless ${operation ?? name}`, {\n error,\n serverless: {\n kind: name,\n platform,\n operation,\n requestId,\n coldStart: currentColdStart,\n durationMs,\n event: options.captureEvent\n ? (options.normalizeEvent?.(event) ?? normalizeUnknown(event))\n : undefined,\n result:\n options.captureResult && result !== undefined\n ? (options.normalizeResult?.(result) ?? normalizeUnknown(result))\n : undefined,\n },\n } as LogData);\n };\n\n const wrappedCallback = callback\n ? (error?: unknown, result?: TResult) => {\n capture(error, result);\n callback(error, result);\n }\n : undefined;\n\n const invoke = () => {\n try {\n const result = handler(event, context, wrappedCallback);\n if (isPromiseLike<TResult>(result)) {\n return result.then(\n (value) => {\n capture(undefined, value);\n return value;\n },\n (error) => {\n capture(error);\n throw error;\n },\n );\n }\n if (result !== undefined || !wrappedCallback) capture(undefined, result as TResult);\n return result;\n } catch (error) {\n capture(error);\n throw error;\n }\n };\n\n if (!bindContext) return invoke();\n return withContext(\n {\n functionName: (context as ServerlessContextLike | undefined)?.functionName,\n requestId,\n serverlessPlatform: platform,\n },\n invoke,\n );\n };\n}\n"],"mappings":"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"}
|