@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,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy Fetcher — Periodically polls the BufferLog Control Plane
|
|
3
|
+
* for dynamic configuration updates.
|
|
4
|
+
*
|
|
5
|
+
* The SDK calls GET /api/v1/policy every `intervalMs` (default 60s).
|
|
6
|
+
* If the server returns updated policies, the fetcher invokes the
|
|
7
|
+
* `onUpdate` callback so the BufferLog instance can apply changes
|
|
8
|
+
* without requiring a redeploy.
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Fail-safe: if the control plane is unreachable, the SDK continues
|
|
12
|
+
* operating with its last known config. No logs are lost.
|
|
13
|
+
* - Uses AbortController for clean shutdown.
|
|
14
|
+
* - Sends SDK version and runtime info in headers for server-side analytics.
|
|
15
|
+
*/
|
|
16
|
+
export class PolicyFetcher {
|
|
17
|
+
url;
|
|
18
|
+
apiKey;
|
|
19
|
+
intervalMs;
|
|
20
|
+
onUpdate;
|
|
21
|
+
onError;
|
|
22
|
+
timer = null;
|
|
23
|
+
abortController = null;
|
|
24
|
+
_lastPolicy = null;
|
|
25
|
+
_fetchCount = 0;
|
|
26
|
+
_errorCount = 0;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
const base = options.controlPlaneUrl.replace(/\/+$/, '');
|
|
29
|
+
this.url = `${base}/api/v1/policy`;
|
|
30
|
+
this.apiKey = options.apiKey;
|
|
31
|
+
this.intervalMs = options.intervalMs ?? 60_000;
|
|
32
|
+
this.onUpdate = options.onUpdate;
|
|
33
|
+
this.onError = options.onError;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Start polling. Fetches immediately, then every `intervalMs`.
|
|
37
|
+
*/
|
|
38
|
+
start() {
|
|
39
|
+
if (this.timer)
|
|
40
|
+
return; // Already running
|
|
41
|
+
// Fetch immediately on start
|
|
42
|
+
this.fetch();
|
|
43
|
+
this.timer = setInterval(() => this.fetch(), this.intervalMs);
|
|
44
|
+
// Ensure the timer doesn't prevent process exit
|
|
45
|
+
if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {
|
|
46
|
+
this.timer.unref();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Stop polling and cancel any in-flight request.
|
|
51
|
+
*/
|
|
52
|
+
stop() {
|
|
53
|
+
if (this.timer) {
|
|
54
|
+
clearInterval(this.timer);
|
|
55
|
+
this.timer = null;
|
|
56
|
+
}
|
|
57
|
+
if (this.abortController) {
|
|
58
|
+
this.abortController.abort();
|
|
59
|
+
this.abortController = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Perform a single fetch. Can be called manually to force a refresh.
|
|
64
|
+
*/
|
|
65
|
+
async fetch() {
|
|
66
|
+
this.abortController = new AbortController();
|
|
67
|
+
const timeout = setTimeout(() => this.abortController?.abort(), 10_000);
|
|
68
|
+
try {
|
|
69
|
+
const response = await fetch(this.url, {
|
|
70
|
+
method: 'GET',
|
|
71
|
+
headers: {
|
|
72
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
73
|
+
'User-Agent': `bufferlog-sdk-node/0.1.0 (node/${process.version})`,
|
|
74
|
+
},
|
|
75
|
+
signal: this.abortController.signal,
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new Error(`Policy fetch returned ${response.status}`);
|
|
79
|
+
}
|
|
80
|
+
const policy = (await response.json());
|
|
81
|
+
this._fetchCount++;
|
|
82
|
+
this._lastPolicy = policy;
|
|
83
|
+
this.onUpdate?.(policy);
|
|
84
|
+
return policy;
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
this._errorCount++;
|
|
88
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
89
|
+
// Don't report abort errors (expected during shutdown)
|
|
90
|
+
if (error.name !== 'AbortError') {
|
|
91
|
+
this.onError?.(error);
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
clearTimeout(timeout);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Last successfully fetched policy */
|
|
100
|
+
get lastPolicy() {
|
|
101
|
+
return this._lastPolicy;
|
|
102
|
+
}
|
|
103
|
+
/** Total successful fetches */
|
|
104
|
+
get fetchCount() {
|
|
105
|
+
return this._fetchCount;
|
|
106
|
+
}
|
|
107
|
+
/** Total fetch errors */
|
|
108
|
+
get errorCount() {
|
|
109
|
+
return this._errorCount;
|
|
110
|
+
}
|
|
111
|
+
/** Whether the fetcher is currently running */
|
|
112
|
+
get isRunning() {
|
|
113
|
+
return this.timer !== null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=policy-fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-fetcher.js","sourceRoot":"","sources":["../../src/control-plane/policy-fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry Reporter — Periodically pushes SDK metrics to the
|
|
3
|
+
* BufferLog Control Plane.
|
|
4
|
+
*
|
|
5
|
+
* The SDK calls POST /api/v1/telemetry every `intervalMs` (default 60s)
|
|
6
|
+
* with counters only — never actual log data.
|
|
7
|
+
*
|
|
8
|
+
* Metrics sent:
|
|
9
|
+
* - logs_discarded: total log lines discarded (success path)
|
|
10
|
+
* - logs_flushed: total log lines shipped to APMs (error path)
|
|
11
|
+
* - requests_success: successful requests processed
|
|
12
|
+
* - requests_error: error requests processed
|
|
13
|
+
* - buffers_active: currently in-flight request buffers
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - Fire-and-forget: telemetry failures are silently ignored.
|
|
17
|
+
* - Uses AbortController for clean shutdown.
|
|
18
|
+
* - Timer is unref'd so it doesn't prevent process exit.
|
|
19
|
+
*/
|
|
20
|
+
import type { BufferManagerMetrics } from '../core/buffer-manager.js';
|
|
21
|
+
export interface TelemetryReporterOptions {
|
|
22
|
+
/** Control plane base URL */
|
|
23
|
+
controlPlaneUrl: string;
|
|
24
|
+
/** API key for authentication */
|
|
25
|
+
apiKey: string;
|
|
26
|
+
/** Reporting interval in milliseconds. @default 60000 */
|
|
27
|
+
intervalMs?: number;
|
|
28
|
+
/** Function that returns the current metrics snapshot */
|
|
29
|
+
metricsProvider: () => {
|
|
30
|
+
buffers: BufferManagerMetrics;
|
|
31
|
+
flash: {
|
|
32
|
+
flushCount: number;
|
|
33
|
+
eventsFlushed: number;
|
|
34
|
+
adapterErrors: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/** Callback invoked on send errors (optional, for debugging) */
|
|
38
|
+
onError?: (error: Error) => void;
|
|
39
|
+
}
|
|
40
|
+
export declare class TelemetryReporter {
|
|
41
|
+
private readonly url;
|
|
42
|
+
private readonly apiKey;
|
|
43
|
+
private readonly intervalMs;
|
|
44
|
+
private readonly metricsProvider;
|
|
45
|
+
private readonly onError?;
|
|
46
|
+
private timer;
|
|
47
|
+
private _sendCount;
|
|
48
|
+
private _errorCount;
|
|
49
|
+
private prevDiscarded;
|
|
50
|
+
private prevFlushed;
|
|
51
|
+
private prevSuccess;
|
|
52
|
+
private prevError;
|
|
53
|
+
constructor(options: TelemetryReporterOptions);
|
|
54
|
+
/**
|
|
55
|
+
* Start reporting. Sends the first report after one interval.
|
|
56
|
+
*/
|
|
57
|
+
start(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Stop reporting.
|
|
60
|
+
*/
|
|
61
|
+
stop(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Send a single telemetry snapshot. Can be called manually (e.g. on shutdown).
|
|
64
|
+
*/
|
|
65
|
+
send(): Promise<boolean>;
|
|
66
|
+
/** Total successful sends */
|
|
67
|
+
get sendCount(): number;
|
|
68
|
+
/** Total send errors */
|
|
69
|
+
get errorCount(): number;
|
|
70
|
+
/** Whether the reporter is currently running */
|
|
71
|
+
get isRunning(): boolean;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=telemetry-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-reporter.d.ts","sourceRoot":"","sources":["../../src/control-plane/telemetry-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,MAAM,WAAW,wBAAwB;IACvC,6BAA6B;IAC7B,eAAe,EAAE,MAAM,CAAC;IAExB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,yDAAyD;IACzD,eAAe,EAAE,MAAM;QACrB,OAAO,EAAE,oBAAoB,CAAC;QAC9B,KAAK,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7E,CAAC;IAEF,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA8C;IAC9E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAyB;IAElD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAK;IAGxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAK;gBAEV,OAAO,EAAE,wBAAwB;IAS7C;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IA6D9B,6BAA6B;IAC7B,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,wBAAwB;IACxB,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,gDAAgD;IAChD,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry Reporter — Periodically pushes SDK metrics to the
|
|
3
|
+
* BufferLog Control Plane.
|
|
4
|
+
*
|
|
5
|
+
* The SDK calls POST /api/v1/telemetry every `intervalMs` (default 60s)
|
|
6
|
+
* with counters only — never actual log data.
|
|
7
|
+
*
|
|
8
|
+
* Metrics sent:
|
|
9
|
+
* - logs_discarded: total log lines discarded (success path)
|
|
10
|
+
* - logs_flushed: total log lines shipped to APMs (error path)
|
|
11
|
+
* - requests_success: successful requests processed
|
|
12
|
+
* - requests_error: error requests processed
|
|
13
|
+
* - buffers_active: currently in-flight request buffers
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - Fire-and-forget: telemetry failures are silently ignored.
|
|
17
|
+
* - Uses AbortController for clean shutdown.
|
|
18
|
+
* - Timer is unref'd so it doesn't prevent process exit.
|
|
19
|
+
*/
|
|
20
|
+
export class TelemetryReporter {
|
|
21
|
+
url;
|
|
22
|
+
apiKey;
|
|
23
|
+
intervalMs;
|
|
24
|
+
metricsProvider;
|
|
25
|
+
onError;
|
|
26
|
+
timer = null;
|
|
27
|
+
_sendCount = 0;
|
|
28
|
+
_errorCount = 0;
|
|
29
|
+
// Track previous metrics to send deltas
|
|
30
|
+
prevDiscarded = 0;
|
|
31
|
+
prevFlushed = 0;
|
|
32
|
+
prevSuccess = 0;
|
|
33
|
+
prevError = 0;
|
|
34
|
+
constructor(options) {
|
|
35
|
+
const base = options.controlPlaneUrl.replace(/\/+$/, '');
|
|
36
|
+
this.url = `${base}/api/v1/telemetry`;
|
|
37
|
+
this.apiKey = options.apiKey;
|
|
38
|
+
this.intervalMs = options.intervalMs ?? 60_000;
|
|
39
|
+
this.metricsProvider = options.metricsProvider;
|
|
40
|
+
this.onError = options.onError;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Start reporting. Sends the first report after one interval.
|
|
44
|
+
*/
|
|
45
|
+
start() {
|
|
46
|
+
if (this.timer)
|
|
47
|
+
return;
|
|
48
|
+
this.timer = setInterval(() => this.send(), this.intervalMs);
|
|
49
|
+
if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {
|
|
50
|
+
this.timer.unref();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stop reporting.
|
|
55
|
+
*/
|
|
56
|
+
stop() {
|
|
57
|
+
if (this.timer) {
|
|
58
|
+
clearInterval(this.timer);
|
|
59
|
+
this.timer = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Send a single telemetry snapshot. Can be called manually (e.g. on shutdown).
|
|
64
|
+
*/
|
|
65
|
+
async send() {
|
|
66
|
+
try {
|
|
67
|
+
const metrics = this.metricsProvider();
|
|
68
|
+
// Calculate deltas since last send
|
|
69
|
+
const currentDiscarded = metrics.flash.eventsFlushed; // flushed events
|
|
70
|
+
const bufMetrics = metrics.buffers;
|
|
71
|
+
const payload = {
|
|
72
|
+
sdkVersion: '0.1.0',
|
|
73
|
+
runtime: 'node',
|
|
74
|
+
runtimeVersion: process.version.replace('v', ''),
|
|
75
|
+
metrics: {
|
|
76
|
+
logs_discarded: bufMetrics.discarded - this.prevDiscarded + this.prevDiscarded,
|
|
77
|
+
logs_flushed: metrics.flash.eventsFlushed,
|
|
78
|
+
requests_success: bufMetrics.discarded,
|
|
79
|
+
requests_error: bufMetrics.flushed,
|
|
80
|
+
buffers_active: bufMetrics.active,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
// Update prev counters
|
|
84
|
+
this.prevDiscarded = bufMetrics.discarded;
|
|
85
|
+
this.prevFlushed = metrics.flash.eventsFlushed;
|
|
86
|
+
this.prevSuccess = bufMetrics.discarded;
|
|
87
|
+
this.prevError = bufMetrics.flushed;
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(this.url, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: {
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
96
|
+
'User-Agent': `bufferlog-sdk-node/0.1.0 (node/${process.version})`,
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify(payload),
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`Telemetry push returned ${response.status}`);
|
|
103
|
+
}
|
|
104
|
+
this._sendCount++;
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
clearTimeout(timeout);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
this._errorCount++;
|
|
113
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
114
|
+
if (error.name !== 'AbortError') {
|
|
115
|
+
this.onError?.(error);
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Total successful sends */
|
|
121
|
+
get sendCount() {
|
|
122
|
+
return this._sendCount;
|
|
123
|
+
}
|
|
124
|
+
/** Total send errors */
|
|
125
|
+
get errorCount() {
|
|
126
|
+
return this._errorCount;
|
|
127
|
+
}
|
|
128
|
+
/** Whether the reporter is currently running */
|
|
129
|
+
get isRunning() {
|
|
130
|
+
return this.timer !== null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=telemetry-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-reporter.js","sourceRoot":"","sources":["../../src/control-plane/telemetry-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buffer Manager — Lifecycle manager for per-request ring buffers.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Create a new ring buffer when a request starts
|
|
6
|
+
* - Retrieve the buffer for a given context ID
|
|
7
|
+
* - Discard (GC) the buffer on success (HTTP 2xx)
|
|
8
|
+
* - Flush (drain) the buffer on error (HTTP 5xx or log.error())
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Uses a Map<string, RingBuffer<LogEvent>> for O(1) lookups
|
|
12
|
+
* - Fail-open: if contextId is missing, operations return gracefully
|
|
13
|
+
* - Tracks metrics (created, discarded, flushed) for the ROI dashboard
|
|
14
|
+
*/
|
|
15
|
+
import { RingBuffer } from './ring-buffer.js';
|
|
16
|
+
import type { LogEvent } from './log-event.js';
|
|
17
|
+
export interface BufferManagerMetrics {
|
|
18
|
+
/** Total buffers created */
|
|
19
|
+
created: number;
|
|
20
|
+
/** Total buffers discarded (success path) */
|
|
21
|
+
discarded: number;
|
|
22
|
+
/** Total buffers flushed (error path) */
|
|
23
|
+
flushed: number;
|
|
24
|
+
/** Currently active buffers */
|
|
25
|
+
active: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class BufferManager {
|
|
28
|
+
private readonly defaultCapacity;
|
|
29
|
+
private readonly buffers;
|
|
30
|
+
private readonly metrics;
|
|
31
|
+
/**
|
|
32
|
+
* @param defaultCapacity Default ring buffer capacity for new buffers
|
|
33
|
+
*/
|
|
34
|
+
constructor(defaultCapacity?: number);
|
|
35
|
+
/**
|
|
36
|
+
* Create a new ring buffer for a request context.
|
|
37
|
+
*
|
|
38
|
+
* @param contextId Unique identifier for the request
|
|
39
|
+
* @param capacity Optional override for buffer capacity
|
|
40
|
+
* @returns The newly created ring buffer
|
|
41
|
+
*/
|
|
42
|
+
createBuffer(contextId: string, capacity?: number): RingBuffer<LogEvent>;
|
|
43
|
+
/**
|
|
44
|
+
* Retrieve the ring buffer for a given context ID.
|
|
45
|
+
* Returns undefined if no buffer exists (e.g., outside request scope).
|
|
46
|
+
*/
|
|
47
|
+
getBuffer(contextId: string): RingBuffer<LogEvent> | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a buffer exists for the given context ID.
|
|
50
|
+
*/
|
|
51
|
+
hasBuffer(contextId: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Discard a buffer — the SUCCESS path.
|
|
54
|
+
* The buffer is removed from the map and becomes eligible for GC.
|
|
55
|
+
* No logs are emitted. This is the money-saving operation.
|
|
56
|
+
*
|
|
57
|
+
* @param contextId The request context to discard
|
|
58
|
+
* @returns true if a buffer was found and discarded, false if not found
|
|
59
|
+
*/
|
|
60
|
+
discardBuffer(contextId: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Flush a buffer — the ERROR path.
|
|
63
|
+
* Drains all buffered log events and removes the buffer from the map.
|
|
64
|
+
*
|
|
65
|
+
* @param contextId The request context to flush
|
|
66
|
+
* @returns Array of log events in chronological order, or empty array if not found
|
|
67
|
+
*/
|
|
68
|
+
flushBuffer(contextId: string): LogEvent[];
|
|
69
|
+
/**
|
|
70
|
+
* Get a snapshot of current metrics.
|
|
71
|
+
* Used by the ROI dashboard and telemetry.
|
|
72
|
+
*/
|
|
73
|
+
getMetrics(): Readonly<BufferManagerMetrics>;
|
|
74
|
+
/**
|
|
75
|
+
* Reset all metrics counters. Useful for testing.
|
|
76
|
+
*/
|
|
77
|
+
resetMetrics(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Get the number of currently active buffers.
|
|
80
|
+
*/
|
|
81
|
+
get activeCount(): number;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=buffer-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer-manager.d.ts","sourceRoot":"","sources":["../../src/core/buffer-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IAYZ,OAAO,CAAC,QAAQ,CAAC,eAAe;IAX5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAKtB;IAEF;;OAEG;gBAC0B,eAAe,GAAE,MAAY;IAE1D;;;;;;OAMG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;IAQxE;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS;IAI9D;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;;;;OAOG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAczC;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE;IAa1C;;;OAGG;IACH,UAAU,IAAI,QAAQ,CAAC,oBAAoB,CAAC;IAI5C;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;CACF"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buffer Manager — Lifecycle manager for per-request ring buffers.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Create a new ring buffer when a request starts
|
|
6
|
+
* - Retrieve the buffer for a given context ID
|
|
7
|
+
* - Discard (GC) the buffer on success (HTTP 2xx)
|
|
8
|
+
* - Flush (drain) the buffer on error (HTTP 5xx or log.error())
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - Uses a Map<string, RingBuffer<LogEvent>> for O(1) lookups
|
|
12
|
+
* - Fail-open: if contextId is missing, operations return gracefully
|
|
13
|
+
* - Tracks metrics (created, discarded, flushed) for the ROI dashboard
|
|
14
|
+
*/
|
|
15
|
+
import { RingBuffer } from './ring-buffer.js';
|
|
16
|
+
export class BufferManager {
|
|
17
|
+
defaultCapacity;
|
|
18
|
+
buffers = new Map();
|
|
19
|
+
metrics = {
|
|
20
|
+
created: 0,
|
|
21
|
+
discarded: 0,
|
|
22
|
+
flushed: 0,
|
|
23
|
+
active: 0,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* @param defaultCapacity Default ring buffer capacity for new buffers
|
|
27
|
+
*/
|
|
28
|
+
constructor(defaultCapacity = 100) {
|
|
29
|
+
this.defaultCapacity = defaultCapacity;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a new ring buffer for a request context.
|
|
33
|
+
*
|
|
34
|
+
* @param contextId Unique identifier for the request
|
|
35
|
+
* @param capacity Optional override for buffer capacity
|
|
36
|
+
* @returns The newly created ring buffer
|
|
37
|
+
*/
|
|
38
|
+
createBuffer(contextId, capacity) {
|
|
39
|
+
const buffer = new RingBuffer(capacity ?? this.defaultCapacity);
|
|
40
|
+
this.buffers.set(contextId, buffer);
|
|
41
|
+
this.metrics.created++;
|
|
42
|
+
this.metrics.active++;
|
|
43
|
+
return buffer;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Retrieve the ring buffer for a given context ID.
|
|
47
|
+
* Returns undefined if no buffer exists (e.g., outside request scope).
|
|
48
|
+
*/
|
|
49
|
+
getBuffer(contextId) {
|
|
50
|
+
return this.buffers.get(contextId);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if a buffer exists for the given context ID.
|
|
54
|
+
*/
|
|
55
|
+
hasBuffer(contextId) {
|
|
56
|
+
return this.buffers.has(contextId);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Discard a buffer — the SUCCESS path.
|
|
60
|
+
* The buffer is removed from the map and becomes eligible for GC.
|
|
61
|
+
* No logs are emitted. This is the money-saving operation.
|
|
62
|
+
*
|
|
63
|
+
* @param contextId The request context to discard
|
|
64
|
+
* @returns true if a buffer was found and discarded, false if not found
|
|
65
|
+
*/
|
|
66
|
+
discardBuffer(contextId) {
|
|
67
|
+
const buffer = this.buffers.get(contextId);
|
|
68
|
+
if (!buffer) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Clear references to allow GC of log events
|
|
72
|
+
buffer.clearFull();
|
|
73
|
+
this.buffers.delete(contextId);
|
|
74
|
+
this.metrics.discarded++;
|
|
75
|
+
this.metrics.active--;
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Flush a buffer — the ERROR path.
|
|
80
|
+
* Drains all buffered log events and removes the buffer from the map.
|
|
81
|
+
*
|
|
82
|
+
* @param contextId The request context to flush
|
|
83
|
+
* @returns Array of log events in chronological order, or empty array if not found
|
|
84
|
+
*/
|
|
85
|
+
flushBuffer(contextId) {
|
|
86
|
+
const buffer = this.buffers.get(contextId);
|
|
87
|
+
if (!buffer) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const events = buffer.drain();
|
|
91
|
+
this.buffers.delete(contextId);
|
|
92
|
+
this.metrics.flushed++;
|
|
93
|
+
this.metrics.active--;
|
|
94
|
+
return events;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get a snapshot of current metrics.
|
|
98
|
+
* Used by the ROI dashboard and telemetry.
|
|
99
|
+
*/
|
|
100
|
+
getMetrics() {
|
|
101
|
+
return { ...this.metrics };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Reset all metrics counters. Useful for testing.
|
|
105
|
+
*/
|
|
106
|
+
resetMetrics() {
|
|
107
|
+
this.metrics.created = 0;
|
|
108
|
+
this.metrics.discarded = 0;
|
|
109
|
+
this.metrics.flushed = 0;
|
|
110
|
+
this.metrics.active = this.buffers.size;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the number of currently active buffers.
|
|
114
|
+
*/
|
|
115
|
+
get activeCount() {
|
|
116
|
+
return this.buffers.size;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=buffer-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer-manager.js","sourceRoot":"","sources":["../../src/core/buffer-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAc9C,MAAM,OAAO,aAAa;IAYK;IAXZ,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IAClD,OAAO,GAAyB;QAC/C,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC;KACV,CAAC;IAEF;;OAEG;IACH,YAA6B,kBAA0B,GAAG;QAA7B,oBAAe,GAAf,eAAe,CAAc;IAAG,CAAC;IAE9D;;;;;;OAMG;IACH,YAAY,CAAC,SAAiB,EAAE,QAAiB;QAC/C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAW,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;QAC1E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,SAAiB;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,KAAK,CAAC;QACf,CAAC;QAED,6CAA6C;QAC7C,MAAM,CAAC,SAAS,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,SAAiB;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,YAAY;QACV,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BufferLog Log Event Schema
|
|
3
|
+
*
|
|
4
|
+
* Lightweight internal representation of a log event.
|
|
5
|
+
* Designed for minimal allocation in the hot path:
|
|
6
|
+
* - Numeric timestamp (not ISO string)
|
|
7
|
+
* - Numeric enum for level (fast comparison)
|
|
8
|
+
* - Optional metadata to avoid empty object allocation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Log severity levels as numeric enum for fast comparison.
|
|
12
|
+
* Usage: `if (event.level >= LogLevel.ERROR)` triggers a flush.
|
|
13
|
+
*/
|
|
14
|
+
export declare enum LogLevel {
|
|
15
|
+
TRACE = 0,
|
|
16
|
+
DEBUG = 10,
|
|
17
|
+
INFO = 20,
|
|
18
|
+
WARN = 30,
|
|
19
|
+
ERROR = 40,
|
|
20
|
+
FATAL = 50
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Human-readable label map for serialization.
|
|
24
|
+
*/
|
|
25
|
+
export declare const LOG_LEVEL_LABELS: Record<LogLevel, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Reverse lookup: string label → LogLevel.
|
|
28
|
+
* Used when parsing levels from external logging libraries (e.g., Winston's 'info' → LogLevel.INFO).
|
|
29
|
+
*/
|
|
30
|
+
export declare const LOG_LEVEL_FROM_STRING: Record<string, LogLevel>;
|
|
31
|
+
/**
|
|
32
|
+
* Internal log event — the unit stored in ring buffers.
|
|
33
|
+
*
|
|
34
|
+
* Design notes:
|
|
35
|
+
* - `timestamp` is `Date.now()` (ms since epoch) to avoid string allocation
|
|
36
|
+
* - `metadata` is optional; only allocate when the caller provides extra fields
|
|
37
|
+
* - `contextId` links this event to its owning request buffer
|
|
38
|
+
*/
|
|
39
|
+
export interface LogEvent {
|
|
40
|
+
/** Milliseconds since Unix epoch (Date.now()) */
|
|
41
|
+
readonly timestamp: number;
|
|
42
|
+
/** Severity level */
|
|
43
|
+
readonly level: LogLevel;
|
|
44
|
+
/** Log message — already formatted by the caller */
|
|
45
|
+
readonly message: string;
|
|
46
|
+
/** Optional structured metadata (e.g., userId, traceId, query params) */
|
|
47
|
+
readonly metadata?: Record<string, unknown>;
|
|
48
|
+
/** ID of the request context that owns this event */
|
|
49
|
+
readonly contextId: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Serialized form for downstream adapters (Datadog, Splunk, stdout).
|
|
53
|
+
*/
|
|
54
|
+
export interface SerializedLogEvent {
|
|
55
|
+
timestamp: string;
|
|
56
|
+
level: string;
|
|
57
|
+
message: string;
|
|
58
|
+
metadata?: Record<string, unknown>;
|
|
59
|
+
contextId: string;
|
|
60
|
+
source: 'bufferlog';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert an internal LogEvent to its serialized downstream format.
|
|
64
|
+
* Called only on the flush path (not hot path), so string allocation is acceptable.
|
|
65
|
+
*/
|
|
66
|
+
export declare function serializeLogEvent(event: LogEvent): SerializedLogEvent;
|
|
67
|
+
/**
|
|
68
|
+
* Factory for creating LogEvents with minimal ceremony.
|
|
69
|
+
* Captures timestamp at call time.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createLogEvent(level: LogLevel, message: string, contextId: string, metadata?: Record<string, unknown>): LogEvent;
|
|
72
|
+
//# sourceMappingURL=log-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-event.d.ts","sourceRoot":"","sources":["../../src/core/log-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,KAAK,KAAK;IACV,IAAI,KAAK;IACT,IAAI,KAAK;IACT,KAAK,KAAK;IACV,KAAK,KAAK;CACX;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAOrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAY1D,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,qBAAqB;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAEzB,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE5C,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,GAAG,kBAAkB,CASrE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,QAAQ,CAQV"}
|