tpaga-logger 0.0.2 → 0.0.3

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 CHANGED
@@ -1,22 +1,138 @@
1
- # @tpaga/logger
1
+ # tpaga-logger
2
2
 
3
3
  Structured logging SDK for Tpaga Node.js microservices. Emits **wide-event JSON** (canonical log line) to stdout for **AWS CloudWatch Logs Insights**, following [loggingsucks.com](https://loggingsucks.com/).
4
4
 
5
- ## Status
5
+ ## Installation
6
6
 
7
- | Fase | Estado | Rama |
8
- |------|--------|------|
9
- | 1 — Contrato de logs (SERF-5797) | Completada | `scaffolding` |
10
- | 2 — Scaffold build (tsup, vitest, CI) | En revisión | `scaffolding` |
11
- | 3 — Implementación SDK (SERF-5915) | Pendiente | — |
12
- | 4 — Piloto CloudWatch (SERF-5916) | Pendiente | — |
7
+ ```bash
8
+ pnpm add tpaga-logger
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### AWS Lambda
14
+
15
+ Use `withLogger` to wrap a Lambda handler. It automatically handles timing, `correlationId` extraction from headers, and emits the terminal log event on success or error.
16
+
17
+ ```typescript
18
+ import { createLogger, withLogger } from 'tpaga-logger';
19
+
20
+ const logger = createLogger({
21
+ service: 'my-service',
22
+ environment: process.env.STAGE ?? 'dev',
23
+ });
24
+
25
+ export const handler = withLogger(logger, 'createCharge', async (event, log) => {
26
+ log.with({ orderId: event.body.orderId, amount: event.body.amount });
27
+ const result = await chargeService.create(event.body);
28
+ return { statusCode: 200, body: JSON.stringify(result) };
29
+ });
30
+ ```
31
+
32
+ **What `withLogger` does automatically:**
33
+ - Extracts `correlationId` from `x-correlation-id` or `x-request-id` headers (generates a UUID if absent)
34
+ - Starts a timer and calculates `durationMs`
35
+ - Emits `outcome: "success"` with `statusCode` on completion
36
+ - Emits `outcome: "error"` with serialized error on failure, then re-throws
37
+
38
+ ---
39
+
40
+ ### Express
41
+
42
+ Use `withTpagaExpressLogger` as a global middleware and `getLog` to access the log context inside route handlers.
43
+
44
+ ```typescript
45
+ import express from 'express';
46
+ import { createLogger, withTpagaExpressLogger, getLog } from 'tpaga-logger';
47
+
48
+ const logger = createLogger({
49
+ service: 'url-signer-service',
50
+ environment: process.env.NODE_ENV ?? 'dev',
51
+ });
52
+
53
+ const app = express();
54
+ app.use(express.json());
55
+ app.use(withTpagaExpressLogger(logger)); // register once, covers all routes
56
+
57
+ app.post('/api/v1/sign', (req, res) => {
58
+ req.log.with({ userId: req.body.userId, resource: req.body.resource });
59
+
60
+ const url = signUrl(req.body);
61
+ res.json({ url });
62
+ // terminal log is emitted automatically on res.finish
63
+ });
64
+ ```
65
+
66
+ **What `withTpagaExpressLogger` does automatically:**
67
+ - Extracts `correlationId` from headers (generates a UUID if absent)
68
+ - Attaches a typed `WideEventBuilder` to `req.log` (available in all route handlers)
69
+ - Emits `outcome: "success"` for `statusCode < 400`, `outcome: "error"` otherwise
70
+ - Calculates `durationMs` from when the request entered the middleware
71
+
72
+ ---
73
+
74
+ ## API
13
75
 
14
- ## Documentación
76
+ | Export | Description |
77
+ |--------|-------------|
78
+ | `createLogger(config)` | Creates a logger instance for a service |
79
+ | `withLogger(logger, name, handler)` | Lambda handler wrapper |
80
+ | `withTpagaExpressLogger(logger)` | Express middleware (register with `app.use`) |
81
+ | `getLog(res)` | Gets the `WideEventBuilder` from an Express response |
82
+ | `serializeError(err)` | Serializes an unknown error to a structured object |
83
+ | `LOG_LEVELS` | `['info', 'warn', 'error', 'debug']` |
84
+ | `OUTCOMES` | `['success', 'error', 'validation_failed', ...]` |
15
85
 
16
- - Contrato: [`.agents/docs/SERF-5797_LOG_STRUCTURE_CONTRACT.md`](.agents/docs/SERF-5797_LOG_STRUCTURE_CONTRACT.md)
17
- - Plan: [`.agents/docs/SERF-5796_TPAGA_LOGGER_IMPLEMENTATION_PLAN.md`](.agents/docs/SERF-5796_TPAGA_LOGGER_IMPLEMENTATION_PLAN.md)
86
+ ### `LoggerConfig`
18
87
 
19
- ## Desarrollo
88
+ ```typescript
89
+ type LoggerConfig = {
90
+ service: string;
91
+ environment?: string;
92
+ redactKeys?: readonly string[]; // paths redacted with '[REDACTED]'
93
+ };
94
+ ```
95
+
96
+ ### `WideEventBuilder` (`log`)
97
+
98
+ ```typescript
99
+ type WideEventBuilder = {
100
+ with: (fields: Record<string, unknown>) => void; // add context fields
101
+ emit: (level: LogLevel, message: string, terminal: TerminalFields) => void; // send the log line
102
+ };
103
+ ```
104
+
105
+ > `emit` is called automatically by `withLogger` and `withTpagaExpressLogger`. Call it manually only when using `startOperation` directly.
106
+
107
+ ---
108
+
109
+ ## Local development (pretty logs)
110
+
111
+ `pino-pretty` is bundled in the library — no extra install needed in your service. Just start with `LOG_PRETTY=true`:
112
+
113
+ ```bash
114
+ LOG_PRETTY=true node dist/index.js
115
+ # or for Lambda local testing:
116
+ LOG_PRETTY=true npx ts-node src/handler.ts
117
+ ```
118
+
119
+ Output in the console:
120
+
121
+ ```
122
+ [09:11:00.142] INFO: createCharge completed
123
+ service: "cash-in-manager"
124
+ correlationId: "abc-123"
125
+ orderId: "ORD-456"
126
+ amount: 50000
127
+ outcome: "success"
128
+ durationMs: 142
129
+ ```
130
+
131
+ In production, leave `LOG_PRETTY` unset — raw JSON goes to stdout and CloudWatch Logs Insights queries it natively.
132
+
133
+ ---
134
+
135
+ ## Development
20
136
 
21
137
  ```bash
22
138
  pnpm install
@@ -26,15 +142,10 @@ pnpm test
26
142
  pnpm build
27
143
  ```
28
144
 
29
- **Fase 2:** `createLogger`, `withWideEvent`, y correlación son stubs que lanzan hasta Fase 3. `serializeError`, `safeStringify`, `write`, y `redact` (passthrough) están listos para tests.
30
-
31
- ## Instalación (cuando se publique)
32
-
33
- ```bash
34
- pnpm add @tpaga/logger
35
- ```
145
+ ## Docs
36
146
 
37
- Ver [`.npmrc.example`](.npmrc.example) para registry interno (TBD).
147
+ - Log contract: [`.agents/docs/SERF-5797_LOG_STRUCTURE_CONTRACT.md`](.agents/docs/SERF-5797_LOG_STRUCTURE_CONTRACT.md)
148
+ - Implementation plan: [`.agents/docs/SERF-5796_TPAGA_LOGGER_IMPLEMENTATION_PLAN.md`](.agents/docs/SERF-5796_TPAGA_LOGGER_IMPLEMENTATION_PLAN.md)
38
149
 
39
150
  ## Repo
40
151
 
package/dist/index.cjs CHANGED
@@ -33,8 +33,10 @@ __export(index_exports, {
33
33
  LOG_LEVELS: () => LOG_LEVELS,
34
34
  OUTCOMES: () => OUTCOMES,
35
35
  createLogger: () => createLogger,
36
+ getLog: () => getLog,
36
37
  serializeError: () => serializeError,
37
- withLogger: () => withLogger
38
+ withLogger: () => withLogger,
39
+ withTpagaExpressLogger: () => withTpagaExpressLogger
38
40
  });
39
41
  module.exports = __toCommonJS(index_exports);
40
42
 
@@ -50,11 +52,12 @@ var serializeError = (err) => err instanceof Error ? {
50
52
  var createWideEventBuilder = (base, log) => {
51
53
  const ctx = { ...base };
52
54
  return {
53
- enrich: (fields) => Object.assign(ctx, fields),
55
+ with: (fields) => Object.assign(ctx, fields),
54
56
  emit: (level, message, terminal) => log[level]({ ...ctx, ...terminal }, message)
55
57
  };
56
58
  };
57
59
  var createLogger = (config) => {
60
+ const pretty = process.env.LOG_PRETTY === "true";
58
61
  const log = (0, import_pino.default)({
59
62
  level: process.env.LOG_LEVEL ?? "info",
60
63
  base: { service: config.service, environment: config.environment },
@@ -65,7 +68,8 @@ var createLogger = (config) => {
65
68
  redact: {
66
69
  paths: config.redactKeys ?? [],
67
70
  censor: "[REDACTED]"
68
- }
71
+ },
72
+ ...pretty ? { transport: { target: "pino-pretty", options: { colorize: true } } } : {}
69
73
  });
70
74
  return {
71
75
  startOperation: (functionName, base = {}) => createWideEventBuilder({ function: functionName, ...base }, log)
@@ -75,6 +79,23 @@ var resolveCorrelationId = (headers = {}) => {
75
79
  const h = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
76
80
  return h["x-correlation-id"] ?? h["x-request-id"] ?? (0, import_crypto.randomUUID)();
77
81
  };
82
+ var EXPRESS_LOG_KEY = "tpagaLog";
83
+ var withTpagaExpressLogger = (logger) => (req, res, next) => {
84
+ const start = Date.now();
85
+ const correlationId = resolveCorrelationId(req.headers);
86
+ const log = logger.startOperation(req.path, { correlationId, method: req.method });
87
+ req.log = log;
88
+ res.locals[EXPRESS_LOG_KEY] = log;
89
+ res.on("finish", () => {
90
+ log.emit("info", "request completed", {
91
+ outcome: res.statusCode < 400 ? "success" : "error",
92
+ durationMs: Date.now() - start,
93
+ statusCode: res.statusCode
94
+ });
95
+ });
96
+ next();
97
+ };
98
+ var getLog = (res) => res.locals[EXPRESS_LOG_KEY];
78
99
  var withLogger = (logger, operationName, handler) => async (event, ..._rest) => {
79
100
  const start = Date.now();
80
101
  const correlationId = resolveCorrelationId(event.headers);
@@ -114,7 +135,9 @@ var OUTCOMES = [
114
135
  LOG_LEVELS,
115
136
  OUTCOMES,
116
137
  createLogger,
138
+ getLog,
117
139
  serializeError,
118
- withLogger
140
+ withLogger,
141
+ withTpagaExpressLogger
119
142
  });
120
143
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/constants.ts"],"sourcesContent":["export { createLogger, serializeError, withLogger } 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 { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\nexport const serializeError = (err: unknown): SerializedError =>\n err instanceof Error\n ? {\n type: err.name,\n message: err.message,\n code: (err as { code?: string }).code,\n stack: err.stack,\n }\n : { type: 'UnknownError', message: String(err) };\n\nconst createWideEventBuilder = (\n base: Record<string, unknown>,\n log: pino.Logger,\n): WideEventBuilder => {\n const ctx = { ...base };\n return {\n enrich: (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 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 });\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\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;;;ACAA,oBAA2B;AAC3B,kBAAiB;AAGV,IAAM,iBAAiB,CAAC,QAC7B,eAAe,QACX;AAAA,EACE,MAAM,IAAI;AAAA,EACV,SAAS,IAAI;AAAA,EACb,MAAO,IAA0B;AAAA,EACjC,OAAO,IAAI;AACb,IACA,EAAE,MAAM,gBAAgB,SAAS,OAAO,GAAG,EAAE;AAEnD,IAAM,yBAAyB,CAC7B,MACA,QACqB;AACrB,QAAM,MAAM,EAAE,GAAG,KAAK;AACtB,SAAO;AAAA,IACL,QAAQ,CAAC,WAAW,OAAO,OAAO,KAAK,MAAM;AAAA,IAC7C,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,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,EACF,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;AAEO,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;;;ACtFK,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"]}
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 }\n}\n\nexport const serializeError = (err: unknown): SerializedError =>\n err instanceof Error\n ? {\n type: err.name,\n message: err.message,\n code: (err as { code?: string }).code,\n stack: err.stack,\n }\n : { type: 'UnknownError', message: String(err) };\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.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 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":["pino"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Response, Request, NextFunction } from 'express';
2
+
1
3
  declare const LOG_LEVELS: readonly ["info", "warn", "error", "debug"];
2
4
  declare const OUTCOMES: readonly ["success", "error", "validation_failed", "not_found", "conflict", "timeout", "skipped"];
3
5
 
@@ -21,19 +23,28 @@ type TerminalFields = {
21
23
  error?: SerializedError;
22
24
  };
23
25
  type WideEventBuilder = {
24
- enrich: (fields: Record<string, unknown>) => void;
26
+ with: (fields: Record<string, unknown>) => void;
25
27
  emit: (level: LogLevel, message: string, terminal: TerminalFields) => void;
26
28
  };
27
29
  type Logger = {
28
30
  startOperation: (functionName: string, base?: Record<string, unknown>) => WideEventBuilder;
29
31
  };
30
32
 
33
+ declare global {
34
+ namespace Express {
35
+ interface Request {
36
+ log: WideEventBuilder;
37
+ }
38
+ }
39
+ }
31
40
  declare const serializeError: (err: unknown) => SerializedError;
32
41
  declare const createLogger: (config: LoggerConfig) => Logger;
33
42
  type EventWithHeaders = {
34
43
  headers?: Record<string, string | undefined>;
35
44
  };
36
45
  type HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;
46
+ declare const withTpagaExpressLogger: (logger: Logger) => (req: Request, res: Response, next: NextFunction) => void;
47
+ declare const getLog: (res: Response) => WideEventBuilder;
37
48
  declare const withLogger: <TEvent extends EventWithHeaders>(logger: Logger, operationName: string, handler: HandlerWithBuilder<TEvent>) => (event: TEvent, ..._rest: unknown[]) => Promise<unknown>;
38
49
 
39
- export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, serializeError, withLogger };
50
+ export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, withLogger, withTpagaExpressLogger };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Response, Request, NextFunction } from 'express';
2
+
1
3
  declare const LOG_LEVELS: readonly ["info", "warn", "error", "debug"];
2
4
  declare const OUTCOMES: readonly ["success", "error", "validation_failed", "not_found", "conflict", "timeout", "skipped"];
3
5
 
@@ -21,19 +23,28 @@ type TerminalFields = {
21
23
  error?: SerializedError;
22
24
  };
23
25
  type WideEventBuilder = {
24
- enrich: (fields: Record<string, unknown>) => void;
26
+ with: (fields: Record<string, unknown>) => void;
25
27
  emit: (level: LogLevel, message: string, terminal: TerminalFields) => void;
26
28
  };
27
29
  type Logger = {
28
30
  startOperation: (functionName: string, base?: Record<string, unknown>) => WideEventBuilder;
29
31
  };
30
32
 
33
+ declare global {
34
+ namespace Express {
35
+ interface Request {
36
+ log: WideEventBuilder;
37
+ }
38
+ }
39
+ }
31
40
  declare const serializeError: (err: unknown) => SerializedError;
32
41
  declare const createLogger: (config: LoggerConfig) => Logger;
33
42
  type EventWithHeaders = {
34
43
  headers?: Record<string, string | undefined>;
35
44
  };
36
45
  type HandlerWithBuilder<TEvent> = (event: TEvent, builder: WideEventBuilder) => Promise<unknown>;
46
+ declare const withTpagaExpressLogger: (logger: Logger) => (req: Request, res: Response, next: NextFunction) => void;
47
+ declare const getLog: (res: Response) => WideEventBuilder;
37
48
  declare const withLogger: <TEvent extends EventWithHeaders>(logger: Logger, operationName: string, handler: HandlerWithBuilder<TEvent>) => (event: TEvent, ..._rest: unknown[]) => Promise<unknown>;
38
49
 
39
- export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, serializeError, withLogger };
50
+ export { LOG_LEVELS, type LogLevel, type Logger, type LoggerConfig, OUTCOMES, type Outcome, type SerializedError, type TerminalFields, type WideEventBuilder, createLogger, getLog, serializeError, withLogger, withTpagaExpressLogger };
package/dist/index.js CHANGED
@@ -10,11 +10,12 @@ var serializeError = (err) => err instanceof Error ? {
10
10
  var createWideEventBuilder = (base, log) => {
11
11
  const ctx = { ...base };
12
12
  return {
13
- enrich: (fields) => Object.assign(ctx, fields),
13
+ with: (fields) => Object.assign(ctx, fields),
14
14
  emit: (level, message, terminal) => log[level]({ ...ctx, ...terminal }, message)
15
15
  };
16
16
  };
17
17
  var createLogger = (config) => {
18
+ const pretty = process.env.LOG_PRETTY === "true";
18
19
  const log = pino({
19
20
  level: process.env.LOG_LEVEL ?? "info",
20
21
  base: { service: config.service, environment: config.environment },
@@ -25,7 +26,8 @@ var createLogger = (config) => {
25
26
  redact: {
26
27
  paths: config.redactKeys ?? [],
27
28
  censor: "[REDACTED]"
28
- }
29
+ },
30
+ ...pretty ? { transport: { target: "pino-pretty", options: { colorize: true } } } : {}
29
31
  });
30
32
  return {
31
33
  startOperation: (functionName, base = {}) => createWideEventBuilder({ function: functionName, ...base }, log)
@@ -35,6 +37,23 @@ var resolveCorrelationId = (headers = {}) => {
35
37
  const h = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
36
38
  return h["x-correlation-id"] ?? h["x-request-id"] ?? randomUUID();
37
39
  };
40
+ var EXPRESS_LOG_KEY = "tpagaLog";
41
+ var withTpagaExpressLogger = (logger) => (req, res, next) => {
42
+ const start = Date.now();
43
+ const correlationId = resolveCorrelationId(req.headers);
44
+ const log = logger.startOperation(req.path, { correlationId, method: req.method });
45
+ req.log = log;
46
+ res.locals[EXPRESS_LOG_KEY] = log;
47
+ res.on("finish", () => {
48
+ log.emit("info", "request completed", {
49
+ outcome: res.statusCode < 400 ? "success" : "error",
50
+ durationMs: Date.now() - start,
51
+ statusCode: res.statusCode
52
+ });
53
+ });
54
+ next();
55
+ };
56
+ var getLog = (res) => res.locals[EXPRESS_LOG_KEY];
38
57
  var withLogger = (logger, operationName, handler) => async (event, ..._rest) => {
39
58
  const start = Date.now();
40
59
  const correlationId = resolveCorrelationId(event.headers);
@@ -73,7 +92,9 @@ export {
73
92
  LOG_LEVELS,
74
93
  OUTCOMES,
75
94
  createLogger,
95
+ getLog,
76
96
  serializeError,
77
- withLogger
97
+ withLogger,
98
+ withTpagaExpressLogger
78
99
  };
79
100
  //# sourceMappingURL=index.js.map
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 { Logger, LoggerConfig, SerializedError, TerminalFields, WideEventBuilder } from './types.js';\n\nexport const serializeError = (err: unknown): SerializedError =>\n err instanceof Error\n ? {\n type: err.name,\n message: err.message,\n code: (err as { code?: string }).code,\n stack: err.stack,\n }\n : { type: 'UnknownError', message: String(err) };\n\nconst createWideEventBuilder = (\n base: Record<string, unknown>,\n log: pino.Logger,\n): WideEventBuilder => {\n const ctx = { ...base };\n return {\n enrich: (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 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 });\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\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,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AAGV,IAAM,iBAAiB,CAAC,QAC7B,eAAe,QACX;AAAA,EACE,MAAM,IAAI;AAAA,EACV,SAAS,IAAI;AAAA,EACb,MAAO,IAA0B;AAAA,EACjC,OAAO,IAAI;AACb,IACA,EAAE,MAAM,gBAAgB,SAAS,OAAO,GAAG,EAAE;AAEnD,IAAM,yBAAyB,CAC7B,MACA,QACqB;AACrB,QAAM,MAAM,EAAE,GAAG,KAAK;AACtB,SAAO;AAAA,IACL,QAAQ,CAAC,WAAW,OAAO,OAAO,KAAK,MAAM;AAAA,IAC7C,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,MAAM,KAAK;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,KAAK,iBAAiB;AAAA,IACjC,QAAQ;AAAA,MACN,OAAQ,OAAO,cAA2B,CAAC;AAAA,MAC3C,QAAQ;AAAA,IACV;AAAA,EACF,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,KAAK,WAAW;AAClE;AAEO,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;;;ACtFK,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":[]}
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 }\n}\n\nexport const serializeError = (err: unknown): SerializedError =>\n err instanceof Error\n ? {\n type: err.name,\n message: err.message,\n code: (err as { code?: string }).code,\n stack: err.stack,\n }\n : { type: 'UnknownError', message: String(err) };\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.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 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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tpaga-logger",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Structured logging SDK for Tpaga microservices (wide events → CloudWatch)",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -19,14 +19,24 @@
19
19
  "files": [
20
20
  "dist"
21
21
  ],
22
- "engines": {
22
+ "engmake sines": {
23
23
  "node": ">=20"
24
24
  },
25
25
  "dependencies": {
26
- "pino": "^10.3.1"
26
+ "pino": "^10.3.1",
27
+ "pino-pretty": "^13.1.3"
28
+ },
29
+ "peerDependencies": {
30
+ "express": ">=4"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "express": {
34
+ "optional": true
35
+ }
27
36
  },
28
37
  "devDependencies": {
29
38
  "@eslint/js": "^9.28.0",
39
+ "@types/express": "^5.0.6",
30
40
  "@types/node": "^22.15.0",
31
41
  "eslint": "^9.28.0",
32
42
  "tsup": "^8.5.0",