@bufferlog/sdk-node 1.0.0
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/LICENSE +21 -0
- package/README.md +194 -0
- package/dist/config.d.ts +97 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/context/async-context.d.ts +86 -0
- package/dist/context/async-context.d.ts.map +1 -0
- package/dist/context/async-context.js +90 -0
- package/dist/context/async-context.js.map +1 -0
- package/dist/control-plane/policy-fetcher.d.ts +73 -0
- package/dist/control-plane/policy-fetcher.d.ts.map +1 -0
- package/dist/control-plane/policy-fetcher.js +116 -0
- package/dist/control-plane/policy-fetcher.js.map +1 -0
- package/dist/control-plane/telemetry-reporter.d.ts +73 -0
- package/dist/control-plane/telemetry-reporter.d.ts.map +1 -0
- package/dist/control-plane/telemetry-reporter.js +133 -0
- package/dist/control-plane/telemetry-reporter.js.map +1 -0
- package/dist/core/buffer-manager.d.ts +83 -0
- package/dist/core/buffer-manager.d.ts.map +1 -0
- package/dist/core/buffer-manager.js +119 -0
- package/dist/core/buffer-manager.js.map +1 -0
- package/dist/core/log-event.d.ts +72 -0
- package/dist/core/log-event.d.ts.map +1 -0
- package/dist/core/log-event.js +78 -0
- package/dist/core/log-event.js.map +1 -0
- package/dist/core/ring-buffer.d.ts +60 -0
- package/dist/core/ring-buffer.d.ts.map +1 -0
- package/dist/core/ring-buffer.js +120 -0
- package/dist/core/ring-buffer.js.map +1 -0
- package/dist/flash/adapters/datadog.d.ts +40 -0
- package/dist/flash/adapters/datadog.d.ts.map +1 -0
- package/dist/flash/adapters/datadog.js +67 -0
- package/dist/flash/adapters/datadog.js.map +1 -0
- package/dist/flash/adapters/splunk.d.ts +46 -0
- package/dist/flash/adapters/splunk.d.ts.map +1 -0
- package/dist/flash/adapters/splunk.js +71 -0
- package/dist/flash/adapters/splunk.js.map +1 -0
- package/dist/flash/adapters/stdout.d.ts +25 -0
- package/dist/flash/adapters/stdout.d.ts.map +1 -0
- package/dist/flash/adapters/stdout.js +29 -0
- package/dist/flash/adapters/stdout.js.map +1 -0
- package/dist/flash/adapters/types.d.ts +25 -0
- package/dist/flash/adapters/types.d.ts.map +1 -0
- package/dist/flash/adapters/types.js +10 -0
- package/dist/flash/adapters/types.js.map +1 -0
- package/dist/flash/flash-controller.d.ts +78 -0
- package/dist/flash/flash-controller.d.ts.map +1 -0
- package/dist/flash/flash-controller.js +157 -0
- package/dist/flash/flash-controller.js.map +1 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +185 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/pino.d.ts +37 -0
- package/dist/integrations/pino.d.ts.map +1 -0
- package/dist/integrations/pino.js +86 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/integrations/winston.d.ts +61 -0
- package/dist/integrations/winston.d.ts.map +1 -0
- package/dist/integrations/winston.js +120 -0
- package/dist/integrations/winston.js.map +1 -0
- package/dist/middleware/express.d.ts +47 -0
- package/dist/middleware/express.d.ts.map +1 -0
- package/dist/middleware/express.js +71 -0
- package/dist/middleware/express.js.map +1 -0
- package/dist/middleware/fastify.d.ts +32 -0
- package/dist/middleware/fastify.d.ts.map +1 -0
- package/dist/middleware/fastify.js +91 -0
- package/dist/middleware/fastify.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pino Integration — BufferLog Destination Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Creates a Pino destination (writable stream) that intercepts log writes
|
|
5
|
+
* and routes them through BufferLog's buffer/flush pipeline.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import pino from 'pino';
|
|
10
|
+
* import { createBufferLogDestination } from '@bufferlog/sdk-node/pino';
|
|
11
|
+
*
|
|
12
|
+
* const logger = pino(
|
|
13
|
+
* { level: 'debug' },
|
|
14
|
+
* createBufferLogDestination({ flashController, fallbackDestination: pino.destination(1) })
|
|
15
|
+
* );
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { Writable } from 'node:stream';
|
|
19
|
+
import { BufferLogContext } from '../context/async-context.js';
|
|
20
|
+
import { LogLevel, createLogEvent } from '../core/log-event.js';
|
|
21
|
+
/**
|
|
22
|
+
* Pino numeric levels (same convention: lower = more severe):
|
|
23
|
+
* { fatal: 60, error: 50, warn: 40, info: 30, debug: 20, trace: 10 }
|
|
24
|
+
*
|
|
25
|
+
* Map to BufferLog's LogLevel enum.
|
|
26
|
+
*/
|
|
27
|
+
const PINO_LEVEL_MAP = {
|
|
28
|
+
10: LogLevel.TRACE,
|
|
29
|
+
20: LogLevel.DEBUG,
|
|
30
|
+
30: LogLevel.INFO,
|
|
31
|
+
40: LogLevel.WARN,
|
|
32
|
+
50: LogLevel.ERROR,
|
|
33
|
+
60: LogLevel.FATAL,
|
|
34
|
+
};
|
|
35
|
+
const PINO_FLUSH_LEVELS = new Set([50, 60]); // error, fatal
|
|
36
|
+
/**
|
|
37
|
+
* Create a Pino-compatible destination stream that routes logs through BufferLog.
|
|
38
|
+
*/
|
|
39
|
+
export function createBufferLogDestination(options) {
|
|
40
|
+
const flashController = options.flashController;
|
|
41
|
+
const fallback = options.fallbackDestination ?? process.stdout;
|
|
42
|
+
const flushLevels = new Set(options.flushOnLevels ?? PINO_FLUSH_LEVELS);
|
|
43
|
+
const scrubber = options.scrubber;
|
|
44
|
+
return new Writable({
|
|
45
|
+
write(chunk, _encoding, callback) {
|
|
46
|
+
try {
|
|
47
|
+
const raw = typeof chunk === 'string' ? chunk : chunk.toString();
|
|
48
|
+
// Pino writes newline-delimited JSON
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
const pinoLevel = parsed.level ?? 30;
|
|
51
|
+
const ctx = BufferLogContext.current();
|
|
52
|
+
// No active context → fail-open
|
|
53
|
+
if (!ctx) {
|
|
54
|
+
fallback.write(chunk);
|
|
55
|
+
callback();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Extract fields
|
|
59
|
+
let message = parsed.msg ?? parsed.message ?? '';
|
|
60
|
+
const { level: _l, msg: _m, message: _msg, time: _t, pid: _p, hostname: _h, ...rest } = parsed;
|
|
61
|
+
let metadata = Object.keys(rest).length > 0 ? rest : undefined;
|
|
62
|
+
// Apply scrubber
|
|
63
|
+
if (scrubber) {
|
|
64
|
+
const scrubbed = scrubber(message, metadata);
|
|
65
|
+
message = scrubbed.message;
|
|
66
|
+
metadata = scrubbed.metadata;
|
|
67
|
+
}
|
|
68
|
+
const bufferLogLevel = PINO_LEVEL_MAP[pinoLevel] ?? LogLevel.INFO;
|
|
69
|
+
const logEvent = createLogEvent(bufferLogLevel, message, ctx.contextId, metadata);
|
|
70
|
+
if (flushLevels.has(pinoLevel)) {
|
|
71
|
+
flashController.trigger(ctx, logEvent);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
ctx.buffer.push(logEvent);
|
|
75
|
+
}
|
|
76
|
+
callback();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
// Parse failure or unexpected error → fail-open
|
|
80
|
+
fallback.write(chunk);
|
|
81
|
+
callback();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=pino.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pino.js","sourceRoot":"","sources":["../../src/integrations/pino.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Winston Integration — Custom BufferLog Transport
|
|
3
|
+
*
|
|
4
|
+
* Intercepts all Winston log calls and routes them through BufferLog:
|
|
5
|
+
* - Levels below ERROR → pushed to the request's ring buffer (buffered)
|
|
6
|
+
* - ERROR and above → triggers the flash controller to flush the entire buffer
|
|
7
|
+
* - No active context → fail-open, forward to fallback transport
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* import winston from 'winston';
|
|
12
|
+
* import { BufferLogTransport } from '@bufferlog/sdk-node/winston';
|
|
13
|
+
*
|
|
14
|
+
* const logger = winston.createLogger({
|
|
15
|
+
* transports: [
|
|
16
|
+
* new BufferLogTransport({
|
|
17
|
+
* flashController,
|
|
18
|
+
* fallbackTransport: new winston.transports.Console(),
|
|
19
|
+
* }),
|
|
20
|
+
* ],
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import Transport from 'winston-transport';
|
|
25
|
+
import type { FlashController } from '../flash/flash-controller.js';
|
|
26
|
+
import type { ResolvedConfig } from '../config.js';
|
|
27
|
+
export interface BufferLogTransportOptions extends Transport.TransportStreamOptions {
|
|
28
|
+
/** The flash controller to use for error-triggered flushes */
|
|
29
|
+
flashController: FlashController;
|
|
30
|
+
/** Fallback transport used when no BufferLog context is active */
|
|
31
|
+
fallbackTransport?: Transport;
|
|
32
|
+
/** Resolved BufferLog config. If not provided, defaults are used. */
|
|
33
|
+
config?: ResolvedConfig;
|
|
34
|
+
/** PII scrubber function */
|
|
35
|
+
scrubber?: (message: string, metadata?: Record<string, unknown>) => {
|
|
36
|
+
message: string;
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare class BufferLogTransport extends Transport {
|
|
41
|
+
private readonly flashController;
|
|
42
|
+
private readonly fallbackTransport?;
|
|
43
|
+
private readonly scrubber?;
|
|
44
|
+
private readonly flushOnLevels;
|
|
45
|
+
private _buffered;
|
|
46
|
+
private _flushed;
|
|
47
|
+
private _passedThrough;
|
|
48
|
+
constructor(options: BufferLogTransportOptions);
|
|
49
|
+
/**
|
|
50
|
+
* Winston calls this for every log statement.
|
|
51
|
+
* This is the hot path — must be as fast as possible.
|
|
52
|
+
*/
|
|
53
|
+
log(info: Record<string, unknown>, callback: () => void): void;
|
|
54
|
+
/** Number of log events buffered (success path) */
|
|
55
|
+
get bufferedCount(): number;
|
|
56
|
+
/** Number of flush triggers */
|
|
57
|
+
get flushedCount(): number;
|
|
58
|
+
/** Number of log events passed through (no context) */
|
|
59
|
+
get passedThroughCount(): number;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=winston.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"winston.d.ts","sourceRoot":"","sources":["../../src/integrations/winston.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAkBnD,MAAM,WAAW,yBAA0B,SAAQ,SAAS,CAAC,sBAAsB;IACjF,8DAA8D;IAC9D,eAAe,EAAE,eAAe,CAAC;IAEjC,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAE9B,qEAAqE;IACrE,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;QAClE,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;CACH;AAED,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAY;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAwC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IAGpD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,cAAc,CAAK;gBAEf,OAAO,EAAE,yBAAyB;IAQ9C;;;OAGG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IA0D9D,mDAAmD;IACnD,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,+BAA+B;IAC/B,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,uDAAuD;IACvD,IAAI,kBAAkB,IAAI,MAAM,CAE/B;CACF"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Winston Integration — Custom BufferLog Transport
|
|
3
|
+
*
|
|
4
|
+
* Intercepts all Winston log calls and routes them through BufferLog:
|
|
5
|
+
* - Levels below ERROR → pushed to the request's ring buffer (buffered)
|
|
6
|
+
* - ERROR and above → triggers the flash controller to flush the entire buffer
|
|
7
|
+
* - No active context → fail-open, forward to fallback transport
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* import winston from 'winston';
|
|
12
|
+
* import { BufferLogTransport } from '@bufferlog/sdk-node/winston';
|
|
13
|
+
*
|
|
14
|
+
* const logger = winston.createLogger({
|
|
15
|
+
* transports: [
|
|
16
|
+
* new BufferLogTransport({
|
|
17
|
+
* flashController,
|
|
18
|
+
* fallbackTransport: new winston.transports.Console(),
|
|
19
|
+
* }),
|
|
20
|
+
* ],
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import Transport from 'winston-transport';
|
|
25
|
+
import { BufferLogContext } from '../context/async-context.js';
|
|
26
|
+
import { LogLevel, LOG_LEVEL_FROM_STRING, createLogEvent } from '../core/log-event.js';
|
|
27
|
+
/**
|
|
28
|
+
* Winston uses its own numeric level system (lower = more severe):
|
|
29
|
+
* { error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6 }
|
|
30
|
+
*
|
|
31
|
+
* We map to BufferLog's LogLevel enum.
|
|
32
|
+
*/
|
|
33
|
+
const WINSTON_LEVEL_MAP = {
|
|
34
|
+
error: LogLevel.ERROR,
|
|
35
|
+
warn: LogLevel.WARN,
|
|
36
|
+
info: LogLevel.INFO,
|
|
37
|
+
http: LogLevel.INFO,
|
|
38
|
+
verbose: LogLevel.DEBUG,
|
|
39
|
+
debug: LogLevel.DEBUG,
|
|
40
|
+
silly: LogLevel.TRACE,
|
|
41
|
+
};
|
|
42
|
+
export class BufferLogTransport extends Transport {
|
|
43
|
+
flashController;
|
|
44
|
+
fallbackTransport;
|
|
45
|
+
scrubber;
|
|
46
|
+
flushOnLevels;
|
|
47
|
+
// Metrics
|
|
48
|
+
_buffered = 0;
|
|
49
|
+
_flushed = 0;
|
|
50
|
+
_passedThrough = 0;
|
|
51
|
+
constructor(options) {
|
|
52
|
+
super(options);
|
|
53
|
+
this.flashController = options.flashController;
|
|
54
|
+
this.fallbackTransport = options.fallbackTransport;
|
|
55
|
+
this.scrubber = options.scrubber ?? options.config?.scrubber;
|
|
56
|
+
this.flushOnLevels = options.config?.flushOnLevels ?? new Set(['error', 'fatal']);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Winston calls this for every log statement.
|
|
60
|
+
* This is the hot path — must be as fast as possible.
|
|
61
|
+
*/
|
|
62
|
+
log(info, callback) {
|
|
63
|
+
// Extract Winston's level string
|
|
64
|
+
const winstonLevel = (info.level ?? '').toLowerCase();
|
|
65
|
+
// Remove ANSI color codes if present (Winston colorize format adds these)
|
|
66
|
+
const cleanLevel = winstonLevel.replace(/\u001b\[\d+m/g, '');
|
|
67
|
+
const ctx = BufferLogContext.current();
|
|
68
|
+
// --- No active context: fail-open ---
|
|
69
|
+
if (!ctx) {
|
|
70
|
+
this._passedThrough++;
|
|
71
|
+
if (this.fallbackTransport) {
|
|
72
|
+
this.fallbackTransport.log(info, callback);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
callback();
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Map Winston level to BufferLog level
|
|
80
|
+
const bufferLogLevel = WINSTON_LEVEL_MAP[cleanLevel]
|
|
81
|
+
?? LOG_LEVEL_FROM_STRING[cleanLevel]
|
|
82
|
+
?? LogLevel.INFO;
|
|
83
|
+
// Extract message and metadata
|
|
84
|
+
let message = info.message ?? '';
|
|
85
|
+
const { level: _level, message: _msg, ...rest } = info;
|
|
86
|
+
let metadata = Object.keys(rest).length > 0 ? rest : undefined;
|
|
87
|
+
// Apply PII scrubber if configured
|
|
88
|
+
if (this.scrubber) {
|
|
89
|
+
const scrubbed = this.scrubber(message, metadata);
|
|
90
|
+
message = scrubbed.message;
|
|
91
|
+
metadata = scrubbed.metadata;
|
|
92
|
+
}
|
|
93
|
+
// Create the internal log event
|
|
94
|
+
const logEvent = createLogEvent(bufferLogLevel, message, ctx.contextId, metadata);
|
|
95
|
+
// --- Check if this level triggers a flush ---
|
|
96
|
+
if (this.flushOnLevels.has(cleanLevel)) {
|
|
97
|
+
this._flushed++;
|
|
98
|
+
this.flashController.trigger(ctx, logEvent);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// Normal path: buffer it
|
|
102
|
+
this._buffered++;
|
|
103
|
+
ctx.buffer.push(logEvent);
|
|
104
|
+
}
|
|
105
|
+
callback();
|
|
106
|
+
}
|
|
107
|
+
/** Number of log events buffered (success path) */
|
|
108
|
+
get bufferedCount() {
|
|
109
|
+
return this._buffered;
|
|
110
|
+
}
|
|
111
|
+
/** Number of flush triggers */
|
|
112
|
+
get flushedCount() {
|
|
113
|
+
return this._flushed;
|
|
114
|
+
}
|
|
115
|
+
/** Number of log events passed through (no context) */
|
|
116
|
+
get passedThroughCount() {
|
|
117
|
+
return this._passedThrough;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=winston.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"winston.js","sourceRoot":"","sources":["../../src/integrations/winston.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express Middleware — Wraps each request in a BufferLog context.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Generate a unique context ID for each request
|
|
6
|
+
* 2. Create a ring buffer for the request
|
|
7
|
+
* 3. Run the request handler inside an AsyncLocalStorage scope
|
|
8
|
+
* 4. On response finish:
|
|
9
|
+
* - If status >= 500 → flush the buffer (error path)
|
|
10
|
+
* - Otherwise → discard the buffer (success path, saves money)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```ts
|
|
14
|
+
* import express from 'express';
|
|
15
|
+
* import { bufferLogMiddleware } from '@bufferlog/sdk-node/express';
|
|
16
|
+
*
|
|
17
|
+
* const app = express();
|
|
18
|
+
* app.use(bufferLogMiddleware({ bufferManager, flashController, config }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import type { Request, RequestHandler } from 'express';
|
|
22
|
+
import type { BufferManager } from '../core/buffer-manager.js';
|
|
23
|
+
import type { FlashController } from '../flash/flash-controller.js';
|
|
24
|
+
import type { ResolvedConfig } from '../config.js';
|
|
25
|
+
export interface ExpressMiddlewareOptions {
|
|
26
|
+
/** Buffer manager instance */
|
|
27
|
+
bufferManager: BufferManager;
|
|
28
|
+
/** Flash controller instance */
|
|
29
|
+
flashController: FlashController;
|
|
30
|
+
/** Resolved BufferLog configuration */
|
|
31
|
+
config: ResolvedConfig;
|
|
32
|
+
/**
|
|
33
|
+
* Custom context ID generator.
|
|
34
|
+
* Defaults to nanoid(). Override if you want to use trace IDs, request IDs, etc.
|
|
35
|
+
*/
|
|
36
|
+
contextIdGenerator?: (req: Request) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Custom tags extractor.
|
|
39
|
+
* Returns key-value pairs to attach to the request context (e.g., userId, route).
|
|
40
|
+
*/
|
|
41
|
+
tagsExtractor?: (req: Request) => Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create Express middleware that wraps each request in a BufferLog context.
|
|
45
|
+
*/
|
|
46
|
+
export declare function bufferLogMiddleware(options: ExpressMiddlewareOptions): RequestHandler;
|
|
47
|
+
//# sourceMappingURL=express.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAA0B,cAAc,EAAE,MAAM,SAAS,CAAC;AAG/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,MAAM,WAAW,wBAAwB;IACvC,8BAA8B;IAC9B,aAAa,EAAE,aAAa,CAAC;IAE7B,gCAAgC;IAChC,eAAe,EAAE,eAAe,CAAC;IAEjC,uCAAuC;IACvC,MAAM,EAAE,cAAc,CAAC;IAEvB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IAE9C;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,wBAAwB,GAAG,cAAc,CA8DrF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express Middleware — Wraps each request in a BufferLog context.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Generate a unique context ID for each request
|
|
6
|
+
* 2. Create a ring buffer for the request
|
|
7
|
+
* 3. Run the request handler inside an AsyncLocalStorage scope
|
|
8
|
+
* 4. On response finish:
|
|
9
|
+
* - If status >= 500 → flush the buffer (error path)
|
|
10
|
+
* - Otherwise → discard the buffer (success path, saves money)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```ts
|
|
14
|
+
* import express from 'express';
|
|
15
|
+
* import { bufferLogMiddleware } from '@bufferlog/sdk-node/express';
|
|
16
|
+
*
|
|
17
|
+
* const app = express();
|
|
18
|
+
* app.use(bufferLogMiddleware({ bufferManager, flashController, config }));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import { nanoid } from 'nanoid';
|
|
22
|
+
import { BufferLogContext } from '../context/async-context.js';
|
|
23
|
+
import { LogLevel, createLogEvent } from '../core/log-event.js';
|
|
24
|
+
/**
|
|
25
|
+
* Create Express middleware that wraps each request in a BufferLog context.
|
|
26
|
+
*/
|
|
27
|
+
export function bufferLogMiddleware(options) {
|
|
28
|
+
const { bufferManager, flashController, config, contextIdGenerator, tagsExtractor, } = options;
|
|
29
|
+
return (req, res, next) => {
|
|
30
|
+
// Skip if BufferLog is disabled
|
|
31
|
+
if (!config.enabled) {
|
|
32
|
+
next();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const contextId = contextIdGenerator
|
|
36
|
+
? contextIdGenerator(req)
|
|
37
|
+
: nanoid();
|
|
38
|
+
const buffer = bufferManager.createBuffer(contextId, config.bufferCapacity);
|
|
39
|
+
const tags = tagsExtractor ? tagsExtractor(req) : undefined;
|
|
40
|
+
// Run the rest of the middleware chain inside the BufferLog context
|
|
41
|
+
BufferLogContext.run(contextId, buffer, () => {
|
|
42
|
+
// Listen for response completion
|
|
43
|
+
res.on('finish', () => {
|
|
44
|
+
if (config.flushOnStatusCodes.has(res.statusCode)) {
|
|
45
|
+
// Error path: create a synthetic error event with request context
|
|
46
|
+
const errorEvent = createLogEvent(LogLevel.ERROR, `HTTP ${res.statusCode} ${req.method} ${req.originalUrl}`, contextId, {
|
|
47
|
+
httpMethod: req.method,
|
|
48
|
+
httpUrl: req.originalUrl,
|
|
49
|
+
httpStatusCode: res.statusCode,
|
|
50
|
+
...(tags ?? {}),
|
|
51
|
+
});
|
|
52
|
+
flashController.trigger(BufferLogContext.current() ?? { contextId, buffer, startTime: Date.now() }, errorEvent);
|
|
53
|
+
bufferManager.discardBuffer(contextId);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Success path: discard the buffer (this is where we save money!)
|
|
57
|
+
bufferManager.discardBuffer(contextId);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
// Handle unexpected connection close (request aborted)
|
|
61
|
+
res.on('close', () => {
|
|
62
|
+
if (!res.writableFinished) {
|
|
63
|
+
// Request was aborted before finishing — clean up the buffer
|
|
64
|
+
bufferManager.discardBuffer(contextId);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
next();
|
|
68
|
+
}, tags);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAI/D,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAyBhE;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAiC;IACnE,MAAM,EACJ,aAAa,EACb,eAAe,EACf,MAAM,EACN,kBAAkB,EAClB,aAAa,GACd,GAAG,OAAO,CAAC;IAEZ,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,gCAAgC;QAChC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,kBAAkB;YAClC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC;YACzB,CAAC,CAAC,MAAM,EAAE,CAAC;QAEb,MAAM,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE5D,oEAAoE;QACpE,gBAAgB,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE;YAC3C,iCAAiC;YACjC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACpB,IAAI,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAClD,kEAAkE;oBAClE,MAAM,UAAU,GAAG,cAAc,CAC/B,QAAQ,CAAC,KAAK,EACd,QAAQ,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,EACzD,SAAS,EACT;wBACE,UAAU,EAAE,GAAG,CAAC,MAAM;wBACtB,OAAO,EAAE,GAAG,CAAC,WAAW;wBACxB,cAAc,EAAE,GAAG,CAAC,UAAU;wBAC9B,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;qBAChB,CACF,CAAC;oBACF,eAAe,CAAC,OAAO,CACrB,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAC1E,UAAU,CACX,CAAC;oBACF,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzC,CAAC;qBAAM,CAAC;oBACN,kEAAkE;oBAClE,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,uDAAuD;YACvD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACnB,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;oBAC1B,6DAA6D;oBAC7D,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,EAAE,CAAC;QACT,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify Plugin — Wraps each request in a BufferLog context.
|
|
3
|
+
*
|
|
4
|
+
* Uses Fastify's hook system instead of Express-style middleware.
|
|
5
|
+
* Hooks into `onRequest` (start context), `onResponse` (discard/flush), and
|
|
6
|
+
* `onError` (trigger flush on unhandled errors).
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* import Fastify from 'fastify';
|
|
11
|
+
* import { bufferLogPlugin } from '@bufferlog/sdk-node/fastify';
|
|
12
|
+
*
|
|
13
|
+
* const app = Fastify();
|
|
14
|
+
* app.register(bufferLogPlugin, { bufferManager, flashController, config });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import type { FastifyRequest, FastifyPluginCallback } from 'fastify';
|
|
18
|
+
import type { BufferManager } from '../core/buffer-manager.js';
|
|
19
|
+
import type { FlashController } from '../flash/flash-controller.js';
|
|
20
|
+
import type { ResolvedConfig } from '../config.js';
|
|
21
|
+
export interface FastifyPluginOptions {
|
|
22
|
+
bufferManager: BufferManager;
|
|
23
|
+
flashController: FlashController;
|
|
24
|
+
config: ResolvedConfig;
|
|
25
|
+
contextIdGenerator?: (req: FastifyRequest) => string;
|
|
26
|
+
tagsExtractor?: (req: FastifyRequest) => Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fastify plugin that wraps each request in a BufferLog context.
|
|
30
|
+
*/
|
|
31
|
+
export declare const bufferLogPlugin: FastifyPluginCallback<FastifyPluginOptions>;
|
|
32
|
+
//# sourceMappingURL=fastify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAmB,cAAc,EAAgB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGpG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjE;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,qBAAqB,CAAC,oBAAoB,CAwGvE,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify Plugin — Wraps each request in a BufferLog context.
|
|
3
|
+
*
|
|
4
|
+
* Uses Fastify's hook system instead of Express-style middleware.
|
|
5
|
+
* Hooks into `onRequest` (start context), `onResponse` (discard/flush), and
|
|
6
|
+
* `onError` (trigger flush on unhandled errors).
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* import Fastify from 'fastify';
|
|
11
|
+
* import { bufferLogPlugin } from '@bufferlog/sdk-node/fastify';
|
|
12
|
+
*
|
|
13
|
+
* const app = Fastify();
|
|
14
|
+
* app.register(bufferLogPlugin, { bufferManager, flashController, config });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import { nanoid } from 'nanoid';
|
|
18
|
+
import { BufferLogContext } from '../context/async-context.js';
|
|
19
|
+
import { LogLevel, createLogEvent } from '../core/log-event.js';
|
|
20
|
+
/**
|
|
21
|
+
* Fastify plugin that wraps each request in a BufferLog context.
|
|
22
|
+
*/
|
|
23
|
+
export const bufferLogPlugin = (fastify, options, done) => {
|
|
24
|
+
const { bufferManager, flashController, config, contextIdGenerator, tagsExtractor, } = options;
|
|
25
|
+
// Use Fastify's `onRequest` hook to start the BufferLog context
|
|
26
|
+
fastify.addHook('onRequest', (request, _reply, hookDone) => {
|
|
27
|
+
if (!config.enabled) {
|
|
28
|
+
hookDone();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const contextId = contextIdGenerator
|
|
32
|
+
? contextIdGenerator(request)
|
|
33
|
+
: nanoid();
|
|
34
|
+
const buffer = bufferManager.createBuffer(contextId, config.bufferCapacity);
|
|
35
|
+
const tags = tagsExtractor ? tagsExtractor(request) : undefined;
|
|
36
|
+
// Store contextId on the request for later hooks
|
|
37
|
+
request.__bufferlog_ctx_id = contextId;
|
|
38
|
+
request.__bufferlog_tags = tags;
|
|
39
|
+
// Run subsequent hooks within the BufferLog context
|
|
40
|
+
BufferLogContext.run(contextId, buffer, () => {
|
|
41
|
+
hookDone();
|
|
42
|
+
}, tags);
|
|
43
|
+
});
|
|
44
|
+
// Use `onResponse` to handle the success/error path
|
|
45
|
+
fastify.addHook('onResponse', (request, reply, hookDone) => {
|
|
46
|
+
const contextId = request.__bufferlog_ctx_id;
|
|
47
|
+
if (!contextId) {
|
|
48
|
+
hookDone();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (config.flushOnStatusCodes.has(reply.statusCode)) {
|
|
52
|
+
const tags = request.__bufferlog_tags;
|
|
53
|
+
const buffer = bufferManager.getBuffer(contextId);
|
|
54
|
+
if (buffer) {
|
|
55
|
+
const errorEvent = createLogEvent(LogLevel.ERROR, `HTTP ${reply.statusCode} ${request.method} ${request.url}`, contextId, {
|
|
56
|
+
httpMethod: request.method,
|
|
57
|
+
httpUrl: request.url,
|
|
58
|
+
httpStatusCode: reply.statusCode,
|
|
59
|
+
...(tags ?? {}),
|
|
60
|
+
});
|
|
61
|
+
flashController.trigger({ contextId, buffer, startTime: Date.now(), tags }, errorEvent);
|
|
62
|
+
}
|
|
63
|
+
bufferManager.discardBuffer(contextId);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
bufferManager.discardBuffer(contextId);
|
|
67
|
+
}
|
|
68
|
+
hookDone();
|
|
69
|
+
});
|
|
70
|
+
// Use `onError` to flush on unhandled exceptions
|
|
71
|
+
fastify.addHook('onError', (request, _reply, error, hookDone) => {
|
|
72
|
+
const contextId = request.__bufferlog_ctx_id;
|
|
73
|
+
if (!contextId) {
|
|
74
|
+
hookDone();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const tags = request.__bufferlog_tags;
|
|
78
|
+
const buffer = bufferManager.getBuffer(contextId);
|
|
79
|
+
if (buffer) {
|
|
80
|
+
const errorEvent = createLogEvent(LogLevel.ERROR, `Unhandled error: ${error.message}`, contextId, {
|
|
81
|
+
errorName: error.name,
|
|
82
|
+
errorStack: error.stack,
|
|
83
|
+
...(tags ?? {}),
|
|
84
|
+
});
|
|
85
|
+
flashController.trigger({ contextId, buffer, startTime: Date.now(), tags }, errorEvent);
|
|
86
|
+
}
|
|
87
|
+
hookDone();
|
|
88
|
+
});
|
|
89
|
+
done();
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bufferlog/sdk-node",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "BufferLog.io Node.js SDK — Buffer logs in memory, flush only on errors",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./winston": {
|
|
14
|
+
"import": "./dist/integrations/winston.js",
|
|
15
|
+
"types": "./dist/integrations/winston.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./pino": {
|
|
18
|
+
"import": "./dist/integrations/pino.js",
|
|
19
|
+
"types": "./dist/integrations/pino.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./express": {
|
|
22
|
+
"import": "./dist/middleware/express.js",
|
|
23
|
+
"types": "./dist/middleware/express.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./fastify": {
|
|
26
|
+
"import": "./dist/middleware/fastify.js",
|
|
27
|
+
"types": "./dist/middleware/fastify.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"bench": "tsx benchmarks/ring-buffer.bench.ts",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/lehan0328/bufferlog.git",
|
|
45
|
+
"directory": "packages/sdk-node"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/lehan0328/bufferlog/tree/main/packages/sdk-node#readme",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/lehan0328/bufferlog/issues"
|
|
50
|
+
},
|
|
51
|
+
"keywords": ["logging", "apm", "buffer", "datadog", "splunk", "observability", "cost-reduction"],
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"nanoid": "^5.0.9"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^22.0.0",
|
|
61
|
+
"@types/express": "^5.0.0",
|
|
62
|
+
"typescript": "^5.7.0",
|
|
63
|
+
"vitest": "^3.0.0",
|
|
64
|
+
"tsx": "^4.19.0",
|
|
65
|
+
"winston": "^3.17.0",
|
|
66
|
+
"pino": "^9.6.0",
|
|
67
|
+
"express": "^4.21.0",
|
|
68
|
+
"fastify": "^5.2.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"winston": "^3.0.0",
|
|
72
|
+
"pino": "^8.0.0 || ^9.0.0",
|
|
73
|
+
"express": "^4.0.0 || ^5.0.0",
|
|
74
|
+
"fastify": "^4.0.0 || ^5.0.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"winston": { "optional": true },
|
|
78
|
+
"pino": { "optional": true },
|
|
79
|
+
"express": { "optional": true },
|
|
80
|
+
"fastify": { "optional": true }
|
|
81
|
+
}
|
|
82
|
+
}
|