tpaga-logger 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +30 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +29 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
createLogger: () => createLogger,
|
|
36
36
|
getLog: () => getLog,
|
|
37
37
|
serializeError: () => serializeError,
|
|
38
|
+
tpagaExpressErrorLogger: () => tpagaExpressErrorLogger,
|
|
38
39
|
withLogger: () => withLogger,
|
|
39
40
|
withTpagaExpressLogger: () => withTpagaExpressLogger
|
|
40
41
|
});
|
|
@@ -43,12 +44,16 @@ module.exports = __toCommonJS(index_exports);
|
|
|
43
44
|
// src/logger.ts
|
|
44
45
|
var import_crypto = require("crypto");
|
|
45
46
|
var import_pino = __toESM(require("pino"), 1);
|
|
46
|
-
var serializeError = (err) =>
|
|
47
|
-
type: err
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
var serializeError = (err) => {
|
|
48
|
+
if (!(err instanceof Error)) return { type: "UnknownError", message: String(err) };
|
|
49
|
+
const details = err.issues;
|
|
50
|
+
return {
|
|
51
|
+
type: err.name,
|
|
52
|
+
message: details != null ? "Validation failed" : err.message,
|
|
53
|
+
code: err.code,
|
|
54
|
+
details
|
|
55
|
+
};
|
|
56
|
+
};
|
|
52
57
|
var createWideEventBuilder = (base, log) => {
|
|
53
58
|
const ctx = { ...base };
|
|
54
59
|
return {
|
|
@@ -80,28 +85,25 @@ var resolveCorrelationId = (headers = {}) => {
|
|
|
80
85
|
return h["x-correlation-id"] ?? h["x-request-id"] ?? (0, import_crypto.randomUUID)();
|
|
81
86
|
};
|
|
82
87
|
var EXPRESS_LOG_KEY = "tpagaLog";
|
|
83
|
-
var withTpagaExpressLogger = (logger) => {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
statusCode: res.statusCode
|
|
96
|
-
});
|
|
88
|
+
var withTpagaExpressLogger = (logger) => (req, res, next) => {
|
|
89
|
+
const start = Date.now();
|
|
90
|
+
const correlationId = resolveCorrelationId(req.headers);
|
|
91
|
+
const log = logger.startOperation(req.path, { correlationId, method: req.method });
|
|
92
|
+
req.log = log;
|
|
93
|
+
res.log = log;
|
|
94
|
+
res.locals[EXPRESS_LOG_KEY] = log;
|
|
95
|
+
res.on("finish", () => {
|
|
96
|
+
log.emit("info", "request completed", {
|
|
97
|
+
outcome: res.statusCode < 400 ? "success" : "error",
|
|
98
|
+
durationMs: Date.now() - start,
|
|
99
|
+
statusCode: res.statusCode
|
|
97
100
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return [requestMiddleware, errorMiddleware];
|
|
101
|
+
});
|
|
102
|
+
next();
|
|
103
|
+
};
|
|
104
|
+
var tpagaExpressErrorLogger = (err, req, _res, next) => {
|
|
105
|
+
req.log.with({ error: serializeError(err) });
|
|
106
|
+
next(err);
|
|
105
107
|
};
|
|
106
108
|
var getLog = (res) => res.locals[EXPRESS_LOG_KEY];
|
|
107
109
|
var withLogger = (logger, operationName, handler) => async (event, ..._rest) => {
|
|
@@ -145,6 +147,7 @@ var OUTCOMES = [
|
|
|
145
147
|
createLogger,
|
|
146
148
|
getLog,
|
|
147
149
|
serializeError,
|
|
150
|
+
tpagaExpressErrorLogger,
|
|
148
151
|
withLogger,
|
|
149
152
|
withTpagaExpressLogger
|
|
150
153
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/constants.ts"],"sourcesContent":["export { createLogger, serializeError, withLogger, withTpagaExpressLogger, getLog } from './logger.js';\nexport { LOG_LEVELS, OUTCOMES } from './constants.js';\nexport type {\n Logger,\n LoggerConfig,\n LogLevel,\n Outcome,\n SerializedError,\n TerminalFields,\n WideEventBuilder,\n} from './types.js';\n","import { randomUUID } from 'crypto';\nimport pino from 'pino';\nimport type { NextFunction, Request, Response } from 'express';\nimport type { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\ndeclare global {\n namespace Express {\n interface Request {\n log: WideEventBuilder;\n }\n interface Response {\n log: WideEventBuilder;\n }\n }\n}\n\nexport const serializeError = (err: unknown): SerializedError
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/constants.ts"],"sourcesContent":["export { createLogger, serializeError, withLogger, withTpagaExpressLogger, tpagaExpressErrorLogger, getLog } from './logger.js';\nexport { LOG_LEVELS, OUTCOMES } from './constants.js';\nexport type {\n Logger,\n LoggerConfig,\n LogLevel,\n Outcome,\n SerializedError,\n TerminalFields,\n WideEventBuilder,\n} from './types.js';\n","import { randomUUID } from 'crypto';\nimport pino from 'pino';\nimport type { NextFunction, Request, Response } from 'express';\nimport type { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\ndeclare global {\n namespace Express {\n interface Request {\n log: WideEventBuilder;\n }\n interface Response {\n log: WideEventBuilder;\n }\n }\n}\n\nexport const serializeError = (err: unknown): SerializedError => {\n if (!(err instanceof Error)) return { type: 'UnknownError', message: String(err) };\n const details = (err as { issues?: unknown }).issues;\n return {\n type: err.name,\n message: details != null ? 'Validation failed' : err.message,\n code: (err as { code?: string }).code,\n details,\n };\n};\n\nconst createWideEventBuilder = (\n base: Record<string, unknown>,\n log: pino.Logger,\n): WideEventBuilder => {\n const ctx = { ...base };\n return {\n with: (fields) => Object.assign(ctx, fields),\n emit: (level, message, terminal: TerminalFields) => log[level]({ ...ctx, ...terminal }, message),\n };\n};\n\nexport const createLogger = (config: LoggerConfig): Logger => {\n const pretty = process.env.LOG_PRETTY === 'true';\n const log = pino({\n level: process.env.LOG_LEVEL ?? 'info',\n base: { service: config.service, environment: config.environment },\n formatters: {\n level: (label) => ({ level: label }),\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n redact: {\n paths: (config.redactKeys as string[]) ?? [],\n censor: '[REDACTED]',\n },\n ...(pretty ? { transport: { target: 'pino-pretty', options: { colorize: true } } } : {}),\n });\n\n return {\n startOperation: (functionName, base = {}) =>\n createWideEventBuilder({ function: functionName, ...base }, log),\n };\n};\n\ntype EventWithHeaders = { headers?: Record<string, string | undefined> };\ntype HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;\n\nconst resolveCorrelationId = (headers: Record<string, string | undefined> = {}): string => {\n const h = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));\n return h['x-correlation-id'] ?? h['x-request-id'] ?? randomUUID();\n};\n\nconst EXPRESS_LOG_KEY = 'tpagaLog';\n\nexport const withTpagaExpressLogger = (logger: Logger) =>\n (req: Request, res: Response, next: NextFunction): void => {\n const start = Date.now();\n const correlationId = resolveCorrelationId(req.headers as Record<string, string | undefined>);\n const log = logger.startOperation(req.path, { correlationId, method: req.method });\n\n req.log = log;\n res.log = log;\n res.locals[EXPRESS_LOG_KEY] = log;\n\n res.on('finish', () => {\n log.emit('info', 'request completed', {\n outcome: res.statusCode < 400 ? 'success' : 'error',\n durationMs: Date.now() - start,\n statusCode: res.statusCode,\n });\n });\n\n next();\n };\n\nexport const tpagaExpressErrorLogger = (err: unknown, req: Request, _res: Response, next: NextFunction): void => {\n req.log.with({ error: serializeError(err) });\n next(err);\n};\n\nexport const getLog = (res: Response): WideEventBuilder =>\n res.locals[EXPRESS_LOG_KEY] as WideEventBuilder;\n\nexport const withLogger = <TEvent extends EventWithHeaders>(\n logger: Logger,\n operationName: string,\n handler: HandlerWithBuilder<TEvent>,\n) =>\n async (event: TEvent, ..._rest: unknown[]): Promise<unknown> => {\n const start = Date.now();\n const correlationId = resolveCorrelationId(event.headers);\n const builder = logger.startOperation(operationName, { correlationId });\n\n try {\n const result = await handler(event, builder);\n const statusCode =\n result != null &&\n typeof result === 'object' &&\n 'statusCode' in result &&\n typeof (result as { statusCode: unknown }).statusCode === 'number'\n ? (result as { statusCode: number }).statusCode\n : undefined;\n builder.emit('info', `${operationName} completed`, {\n outcome: 'success',\n durationMs: Date.now() - start,\n ...(statusCode !== undefined ? { statusCode } : {}),\n });\n return result;\n } catch (err) {\n builder.emit('error', `${operationName} failed`, {\n outcome: 'error',\n durationMs: Date.now() - start,\n error: serializeError(err),\n });\n throw err;\n }\n };\n","export const LOG_LEVELS = ['info', 'warn', 'error', 'debug'] as const;\n\nexport const OUTCOMES = [\n 'success',\n 'error',\n 'validation_failed',\n 'not_found',\n 'conflict',\n 'timeout',\n 'skipped',\n] as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA2B;AAC3B,kBAAiB;AAeV,IAAM,iBAAiB,CAAC,QAAkC;AAC/D,MAAI,EAAE,eAAe,OAAQ,QAAO,EAAE,MAAM,gBAAgB,SAAS,OAAO,GAAG,EAAE;AACjF,QAAM,UAAW,IAA6B;AAC9C,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,SAAS,WAAW,OAAO,sBAAsB,IAAI;AAAA,IACrD,MAAO,IAA0B;AAAA,IACjC;AAAA,EACF;AACF;AAEA,IAAM,yBAAyB,CAC7B,MACA,QACqB;AACrB,QAAM,MAAM,EAAE,GAAG,KAAK;AACtB,SAAO;AAAA,IACL,MAAM,CAAC,WAAW,OAAO,OAAO,KAAK,MAAM;AAAA,IAC3C,MAAM,CAAC,OAAO,SAAS,aAA6B,IAAI,KAAK,EAAE,EAAE,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO;AAAA,EACjG;AACF;AAEO,IAAM,eAAe,CAAC,WAAiC;AAC5D,QAAM,SAAS,QAAQ,IAAI,eAAe;AAC1C,QAAM,UAAM,YAAAA,SAAK;AAAA,IACf,OAAO,QAAQ,IAAI,aAAa;AAAA,IAChC,MAAM,EAAE,SAAS,OAAO,SAAS,aAAa,OAAO,YAAY;AAAA,IACjE,YAAY;AAAA,MACV,OAAO,CAAC,WAAW,EAAE,OAAO,MAAM;AAAA,IACpC;AAAA,IACA,WAAW,YAAAA,QAAK,iBAAiB;AAAA,IACjC,QAAQ;AAAA,MACN,OAAQ,OAAO,cAA2B,CAAC;AAAA,MAC3C,QAAQ;AAAA,IACV;AAAA,IACA,GAAI,SAAS,EAAE,WAAW,EAAE,QAAQ,eAAe,SAAS,EAAE,UAAU,KAAK,EAAE,EAAE,IAAI,CAAC;AAAA,EACxF,CAAC;AAED,SAAO;AAAA,IACL,gBAAgB,CAAC,cAAc,OAAO,CAAC,MACrC,uBAAuB,EAAE,UAAU,cAAc,GAAG,KAAK,GAAG,GAAG;AAAA,EACnE;AACF;AAKA,IAAM,uBAAuB,CAAC,UAA8C,CAAC,MAAc;AACzF,QAAM,IAAI,OAAO,YAAY,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC;AAC1F,SAAO,EAAE,kBAAkB,KAAK,EAAE,cAAc,SAAK,0BAAW;AAClE;AAEA,IAAM,kBAAkB;AAEjB,IAAM,yBAAyB,CAAC,WACrC,CAAC,KAAc,KAAe,SAA6B;AACzD,QAAM,QAAQ,KAAK,IAAI;AACvB,QAAM,gBAAgB,qBAAqB,IAAI,OAA6C;AAC5F,QAAM,MAAM,OAAO,eAAe,IAAI,MAAM,EAAE,eAAe,QAAQ,IAAI,OAAO,CAAC;AAEjF,MAAI,MAAM;AACV,MAAI,MAAM;AACV,MAAI,OAAO,eAAe,IAAI;AAE9B,MAAI,GAAG,UAAU,MAAM;AACrB,QAAI,KAAK,QAAQ,qBAAqB;AAAA,MACpC,SAAS,IAAI,aAAa,MAAM,YAAY;AAAA,MAC5C,YAAY,KAAK,IAAI,IAAI;AAAA,MACzB,YAAY,IAAI;AAAA,IAClB,CAAC;AAAA,EACH,CAAC;AAED,OAAK;AACP;AAEK,IAAM,0BAA0B,CAAC,KAAc,KAAc,MAAgB,SAA6B;AAC/G,MAAI,IAAI,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,CAAC;AAC3C,OAAK,GAAG;AACV;AAEO,IAAM,SAAS,CAAC,QACrB,IAAI,OAAO,eAAe;AAErB,IAAM,aAAa,CACxB,QACA,eACA,YAEA,OAAO,UAAkB,UAAuC;AAC9D,QAAM,QAAQ,KAAK,IAAI;AACvB,QAAM,gBAAgB,qBAAqB,MAAM,OAAO;AACxD,QAAM,UAAU,OAAO,eAAe,eAAe,EAAE,cAAc,CAAC;AAEtE,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,OAAO,OAAO;AAC3C,UAAM,aACJ,UAAU,QACV,OAAO,WAAW,YAClB,gBAAgB,UAChB,OAAQ,OAAmC,eAAe,WACrD,OAAkC,aACnC;AACN,YAAQ,KAAK,QAAQ,GAAG,aAAa,cAAc;AAAA,MACjD,SAAS;AAAA,MACT,YAAY,KAAK,IAAI,IAAI;AAAA,MACzB,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,IACnD,CAAC;AACD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,KAAK,SAAS,GAAG,aAAa,WAAW;AAAA,MAC/C,SAAS;AAAA,MACT,YAAY,KAAK,IAAI,IAAI;AAAA,MACzB,OAAO,eAAe,GAAG;AAAA,IAC3B,CAAC;AACD,UAAM;AAAA,EACR;AACF;;;ACpIK,IAAM,aAAa,CAAC,QAAQ,QAAQ,SAAS,OAAO;AAEpD,IAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":["pino"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -14,7 +14,7 @@ type SerializedError = {
|
|
|
14
14
|
type: string;
|
|
15
15
|
message: string;
|
|
16
16
|
code?: string;
|
|
17
|
-
|
|
17
|
+
details?: unknown;
|
|
18
18
|
};
|
|
19
19
|
type TerminalFields = {
|
|
20
20
|
outcome: Outcome | string;
|
|
@@ -46,10 +46,9 @@ type EventWithHeaders = {
|
|
|
46
46
|
headers?: Record<string, string | undefined>;
|
|
47
47
|
};
|
|
48
48
|
type HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
declare const withTpagaExpressLogger: (logger: Logger) => [RequestMiddleware, ErrorMiddleware];
|
|
49
|
+
declare const withTpagaExpressLogger: (logger: Logger) => (req: Request, res: Response, next: NextFunction) => void;
|
|
50
|
+
declare const tpagaExpressErrorLogger: (err: unknown, req: Request, _res: Response, next: NextFunction) => void;
|
|
52
51
|
declare const getLog: (res: Response) => WideEventBuilder;
|
|
53
52
|
declare const withLogger: <TEvent extends EventWithHeaders>(logger: Logger, operationName: string, handler: HandlerWithBuilder<TEvent>) => (event: TEvent, ..._rest: unknown[]) => Promise<unknown>;
|
|
54
53
|
|
|
55
|
-
export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, withLogger, withTpagaExpressLogger };
|
|
54
|
+
export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, tpagaExpressErrorLogger, withLogger, withTpagaExpressLogger };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ type SerializedError = {
|
|
|
14
14
|
type: string;
|
|
15
15
|
message: string;
|
|
16
16
|
code?: string;
|
|
17
|
-
|
|
17
|
+
details?: unknown;
|
|
18
18
|
};
|
|
19
19
|
type TerminalFields = {
|
|
20
20
|
outcome: Outcome | string;
|
|
@@ -46,10 +46,9 @@ type EventWithHeaders = {
|
|
|
46
46
|
headers?: Record<string, string | undefined>;
|
|
47
47
|
};
|
|
48
48
|
type HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
declare const withTpagaExpressLogger: (logger: Logger) => [RequestMiddleware, ErrorMiddleware];
|
|
49
|
+
declare const withTpagaExpressLogger: (logger: Logger) => (req: Request, res: Response, next: NextFunction) => void;
|
|
50
|
+
declare const tpagaExpressErrorLogger: (err: unknown, req: Request, _res: Response, next: NextFunction) => void;
|
|
52
51
|
declare const getLog: (res: Response) => WideEventBuilder;
|
|
53
52
|
declare const withLogger: <TEvent extends EventWithHeaders>(logger: Logger, operationName: string, handler: HandlerWithBuilder<TEvent>) => (event: TEvent, ..._rest: unknown[]) => Promise<unknown>;
|
|
54
53
|
|
|
55
|
-
export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, withLogger, withTpagaExpressLogger };
|
|
54
|
+
export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, tpagaExpressErrorLogger, withLogger, withTpagaExpressLogger };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
// src/logger.ts
|
|
2
2
|
import { randomUUID } from "crypto";
|
|
3
3
|
import pino from "pino";
|
|
4
|
-
var serializeError = (err) =>
|
|
5
|
-
type: err
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
var serializeError = (err) => {
|
|
5
|
+
if (!(err instanceof Error)) return { type: "UnknownError", message: String(err) };
|
|
6
|
+
const details = err.issues;
|
|
7
|
+
return {
|
|
8
|
+
type: err.name,
|
|
9
|
+
message: details != null ? "Validation failed" : err.message,
|
|
10
|
+
code: err.code,
|
|
11
|
+
details
|
|
12
|
+
};
|
|
13
|
+
};
|
|
10
14
|
var createWideEventBuilder = (base, log) => {
|
|
11
15
|
const ctx = { ...base };
|
|
12
16
|
return {
|
|
@@ -38,28 +42,25 @@ var resolveCorrelationId = (headers = {}) => {
|
|
|
38
42
|
return h["x-correlation-id"] ?? h["x-request-id"] ?? randomUUID();
|
|
39
43
|
};
|
|
40
44
|
var EXPRESS_LOG_KEY = "tpagaLog";
|
|
41
|
-
var withTpagaExpressLogger = (logger) => {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
statusCode: res.statusCode
|
|
54
|
-
});
|
|
45
|
+
var withTpagaExpressLogger = (logger) => (req, res, next) => {
|
|
46
|
+
const start = Date.now();
|
|
47
|
+
const correlationId = resolveCorrelationId(req.headers);
|
|
48
|
+
const log = logger.startOperation(req.path, { correlationId, method: req.method });
|
|
49
|
+
req.log = log;
|
|
50
|
+
res.log = log;
|
|
51
|
+
res.locals[EXPRESS_LOG_KEY] = log;
|
|
52
|
+
res.on("finish", () => {
|
|
53
|
+
log.emit("info", "request completed", {
|
|
54
|
+
outcome: res.statusCode < 400 ? "success" : "error",
|
|
55
|
+
durationMs: Date.now() - start,
|
|
56
|
+
statusCode: res.statusCode
|
|
55
57
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return [requestMiddleware, errorMiddleware];
|
|
58
|
+
});
|
|
59
|
+
next();
|
|
60
|
+
};
|
|
61
|
+
var tpagaExpressErrorLogger = (err, req, _res, next) => {
|
|
62
|
+
req.log.with({ error: serializeError(err) });
|
|
63
|
+
next(err);
|
|
63
64
|
};
|
|
64
65
|
var getLog = (res) => res.locals[EXPRESS_LOG_KEY];
|
|
65
66
|
var withLogger = (logger, operationName, handler) => async (event, ..._rest) => {
|
|
@@ -102,6 +103,7 @@ export {
|
|
|
102
103
|
createLogger,
|
|
103
104
|
getLog,
|
|
104
105
|
serializeError,
|
|
106
|
+
tpagaExpressErrorLogger,
|
|
105
107
|
withLogger,
|
|
106
108
|
withTpagaExpressLogger
|
|
107
109
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logger.ts","../src/constants.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport pino from 'pino';\nimport type { NextFunction, Request, Response } from 'express';\nimport type { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\ndeclare global {\n namespace Express {\n interface Request {\n log: WideEventBuilder;\n }\n interface Response {\n log: WideEventBuilder;\n }\n }\n}\n\nexport const serializeError = (err: unknown): SerializedError
|
|
1
|
+
{"version":3,"sources":["../src/logger.ts","../src/constants.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport pino from 'pino';\nimport type { NextFunction, Request, Response } from 'express';\nimport type { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\ndeclare global {\n namespace Express {\n interface Request {\n log: WideEventBuilder;\n }\n interface Response {\n log: WideEventBuilder;\n }\n }\n}\n\nexport const serializeError = (err: unknown): SerializedError => {\n if (!(err instanceof Error)) return { type: 'UnknownError', message: String(err) };\n const details = (err as { issues?: unknown }).issues;\n return {\n type: err.name,\n message: details != null ? 'Validation failed' : err.message,\n code: (err as { code?: string }).code,\n details,\n };\n};\n\nconst createWideEventBuilder = (\n base: Record<string, unknown>,\n log: pino.Logger,\n): WideEventBuilder => {\n const ctx = { ...base };\n return {\n with: (fields) => Object.assign(ctx, fields),\n emit: (level, message, terminal: TerminalFields) => log[level]({ ...ctx, ...terminal }, message),\n };\n};\n\nexport const createLogger = (config: LoggerConfig): Logger => {\n const pretty = process.env.LOG_PRETTY === 'true';\n const log = pino({\n level: process.env.LOG_LEVEL ?? 'info',\n base: { service: config.service, environment: config.environment },\n formatters: {\n level: (label) => ({ level: label }),\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n redact: {\n paths: (config.redactKeys as string[]) ?? [],\n censor: '[REDACTED]',\n },\n ...(pretty ? { transport: { target: 'pino-pretty', options: { colorize: true } } } : {}),\n });\n\n return {\n startOperation: (functionName, base = {}) =>\n createWideEventBuilder({ function: functionName, ...base }, log),\n };\n};\n\ntype EventWithHeaders = { headers?: Record<string, string | undefined> };\ntype HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;\n\nconst resolveCorrelationId = (headers: Record<string, string | undefined> = {}): string => {\n const h = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));\n return h['x-correlation-id'] ?? h['x-request-id'] ?? randomUUID();\n};\n\nconst EXPRESS_LOG_KEY = 'tpagaLog';\n\nexport const withTpagaExpressLogger = (logger: Logger) =>\n (req: Request, res: Response, next: NextFunction): void => {\n const start = Date.now();\n const correlationId = resolveCorrelationId(req.headers as Record<string, string | undefined>);\n const log = logger.startOperation(req.path, { correlationId, method: req.method });\n\n req.log = log;\n res.log = log;\n res.locals[EXPRESS_LOG_KEY] = log;\n\n res.on('finish', () => {\n log.emit('info', 'request completed', {\n outcome: res.statusCode < 400 ? 'success' : 'error',\n durationMs: Date.now() - start,\n statusCode: res.statusCode,\n });\n });\n\n next();\n };\n\nexport const tpagaExpressErrorLogger = (err: unknown, req: Request, _res: Response, next: NextFunction): void => {\n req.log.with({ error: serializeError(err) });\n next(err);\n};\n\nexport const getLog = (res: Response): WideEventBuilder =>\n res.locals[EXPRESS_LOG_KEY] as WideEventBuilder;\n\nexport const withLogger = <TEvent extends EventWithHeaders>(\n logger: Logger,\n operationName: string,\n handler: HandlerWithBuilder<TEvent>,\n) =>\n async (event: TEvent, ..._rest: unknown[]): Promise<unknown> => {\n const start = Date.now();\n const correlationId = resolveCorrelationId(event.headers);\n const builder = logger.startOperation(operationName, { correlationId });\n\n try {\n const result = await handler(event, builder);\n const statusCode =\n result != null &&\n typeof result === 'object' &&\n 'statusCode' in result &&\n typeof (result as { statusCode: unknown }).statusCode === 'number'\n ? (result as { statusCode: number }).statusCode\n : undefined;\n builder.emit('info', `${operationName} completed`, {\n outcome: 'success',\n durationMs: Date.now() - start,\n ...(statusCode !== undefined ? { statusCode } : {}),\n });\n return result;\n } catch (err) {\n builder.emit('error', `${operationName} failed`, {\n outcome: 'error',\n durationMs: Date.now() - start,\n error: serializeError(err),\n });\n throw err;\n }\n };\n","export const LOG_LEVELS = ['info', 'warn', 'error', 'debug'] as const;\n\nexport const OUTCOMES = [\n 'success',\n 'error',\n 'validation_failed',\n 'not_found',\n 'conflict',\n 'timeout',\n 'skipped',\n] as const;\n"],"mappings":"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","names":[]}
|