@prath/observability-sdk 0.1.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/README.md +70 -0
- package/dist/index.d.mts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +144 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @prath/observability-sdk
|
|
2
|
+
|
|
3
|
+
A minimal, dependency-light client for sending metrics and logs to a network-observer
|
|
4
|
+
ingestion endpoint. Batches events in memory and flushes them off your app's hot path —
|
|
5
|
+
this package is never the reason your service runs out of memory or slows down.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @prath/observability-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { ObservabilityClient } from "@prath/observability-sdk";
|
|
17
|
+
|
|
18
|
+
const client = new ObservabilityClient({
|
|
19
|
+
apiKey: process.env.OBS_API_KEY!,
|
|
20
|
+
endpoint: "https://your-backend.com/ingest",
|
|
21
|
+
flushIntervalMs: 5000,
|
|
22
|
+
maxBatchSize: 100,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
client.track("checkout.duration_ms", 245, { region: "us-east" });
|
|
26
|
+
client.log("error", "Payment failed", { orderId: "123" });
|
|
27
|
+
|
|
28
|
+
process.on("SIGTERM", () => client.flush());
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API reference
|
|
32
|
+
|
|
33
|
+
### `new ObservabilityClient(options)`
|
|
34
|
+
|
|
35
|
+
| Option | Type | Default | Description |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| `apiKey` | `string` | required | Per-service API key sent as a bearer token. |
|
|
38
|
+
| `endpoint` | `string` | required | Ingestion endpoint URL, e.g. `https://host/ingest`. |
|
|
39
|
+
| `flushIntervalMs` | `number` | `5000` | Flush the batch on this interval regardless of size. |
|
|
40
|
+
| `maxBatchSize` | `number` | `100` | Flush immediately once this many events are buffered. |
|
|
41
|
+
| `maxQueueSize` | `number` | `1000` | Upper bound on buffered events; oldest are dropped past this. |
|
|
42
|
+
| `maxRetries` | `number` | `3` | Retry attempts per flush before dropping that batch. |
|
|
43
|
+
| `retryBaseDelayMs` | `number` | `500` | Base backoff delay between retries (doubles each attempt). |
|
|
44
|
+
| `onDrop` | `(dropped, reason) => void` | — | Called when events are dropped (`"queue-full"` or `"flush-failed"`). |
|
|
45
|
+
| `onError` | `(error) => void` | — | Called on unexpected flush errors. |
|
|
46
|
+
|
|
47
|
+
### `client.track(metricName, value, tags?)`
|
|
48
|
+
|
|
49
|
+
Records a numeric metric point, e.g. `client.track("checkout.duration_ms", 245, { region: "us-east" })`.
|
|
50
|
+
|
|
51
|
+
### `client.log(level, message, meta?)`
|
|
52
|
+
|
|
53
|
+
Records a log line. `level` is one of `"debug" | "info" | "warn" | "error"`.
|
|
54
|
+
|
|
55
|
+
### `client.flush(): Promise<void>`
|
|
56
|
+
|
|
57
|
+
Forces an immediate flush of buffered events. Call this on shutdown (e.g. `SIGTERM`) to
|
|
58
|
+
avoid losing the last partial batch.
|
|
59
|
+
|
|
60
|
+
### `client.stop()`
|
|
61
|
+
|
|
62
|
+
Stops the internal flush timer. Useful in tests.
|
|
63
|
+
|
|
64
|
+
## Why this exists
|
|
65
|
+
|
|
66
|
+
Instrumenting a service shouldn't require the instrumented service to take on network
|
|
67
|
+
latency, unbounded memory growth, or crash risk. This SDK batches and bounds everything
|
|
68
|
+
client-side so that if the ingestion endpoint is slow or down, the host app degrades not
|
|
69
|
+
at all — it just stops getting new data reflected on the dashboard until the endpoint
|
|
70
|
+
recovers.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
interface MetricEvent {
|
|
3
|
+
type: "metric";
|
|
4
|
+
name: string;
|
|
5
|
+
value: number;
|
|
6
|
+
tags?: Record<string, string>;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
}
|
|
9
|
+
interface LogEvent {
|
|
10
|
+
type: "log";
|
|
11
|
+
level: LogLevel;
|
|
12
|
+
message: string;
|
|
13
|
+
meta?: Record<string, unknown>;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
}
|
|
16
|
+
type ObservabilityEvent = MetricEvent | LogEvent;
|
|
17
|
+
interface ObservabilityClientOptions {
|
|
18
|
+
/** Per-service API key, sent as `Authorization: Bearer <apiKey>`. */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Base URL of the ingestion endpoint, e.g. https://your-backend.com/ingest */
|
|
21
|
+
endpoint: string;
|
|
22
|
+
/** Flush the batch on this interval, regardless of size. Default 5000ms. */
|
|
23
|
+
flushIntervalMs?: number;
|
|
24
|
+
/** Flush immediately once the batch reaches this many events. Default 100. */
|
|
25
|
+
maxBatchSize?: number;
|
|
26
|
+
/** Upper bound on events held in memory if the endpoint is unreachable. Oldest events are dropped past this. Default 1000. */
|
|
27
|
+
maxQueueSize?: number;
|
|
28
|
+
/** Max retry attempts per flush before giving up on that batch. Default 3. */
|
|
29
|
+
maxRetries?: number;
|
|
30
|
+
/** Base backoff delay in ms between retries (doubles each attempt). Default 500ms. */
|
|
31
|
+
retryBaseDelayMs?: number;
|
|
32
|
+
/** Called when events are dropped due to a full queue or exhausted retries. Never throws from inside the client. */
|
|
33
|
+
onDrop?: (dropped: ObservabilityEvent[], reason: "queue-full" | "flush-failed") => void;
|
|
34
|
+
/** Called on unexpected flush errors, for host-app diagnostics. */
|
|
35
|
+
onError?: (error: unknown) => void;
|
|
36
|
+
/** Injectable fetch implementation, mainly for testing. Defaults to global fetch. */
|
|
37
|
+
fetchImpl?: typeof fetch;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Client SDK for the network-observer ingestion endpoint.
|
|
42
|
+
*
|
|
43
|
+
* Every network call is fire-and-forget from the host app's perspective:
|
|
44
|
+
* flush() never throws and never blocks the caller. On sustained failure,
|
|
45
|
+
* the oldest buffered events are dropped rather than growing the queue
|
|
46
|
+
* without bound.
|
|
47
|
+
*/
|
|
48
|
+
declare class ObservabilityClient {
|
|
49
|
+
private readonly options;
|
|
50
|
+
private readonly batcher;
|
|
51
|
+
private readonly fetchImpl;
|
|
52
|
+
private inFlight;
|
|
53
|
+
constructor(options: ObservabilityClientOptions);
|
|
54
|
+
track(metricName: string, value: number, tags?: Record<string, string>): void;
|
|
55
|
+
log(level: LogLevel, message: string, meta?: Record<string, unknown>): void;
|
|
56
|
+
/** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */
|
|
57
|
+
flush(): Promise<void>;
|
|
58
|
+
stop(): void;
|
|
59
|
+
private sendBatch;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { type LogEvent, type LogLevel, type MetricEvent, ObservabilityClient, type ObservabilityClientOptions, type ObservabilityEvent };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
interface MetricEvent {
|
|
3
|
+
type: "metric";
|
|
4
|
+
name: string;
|
|
5
|
+
value: number;
|
|
6
|
+
tags?: Record<string, string>;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
}
|
|
9
|
+
interface LogEvent {
|
|
10
|
+
type: "log";
|
|
11
|
+
level: LogLevel;
|
|
12
|
+
message: string;
|
|
13
|
+
meta?: Record<string, unknown>;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
}
|
|
16
|
+
type ObservabilityEvent = MetricEvent | LogEvent;
|
|
17
|
+
interface ObservabilityClientOptions {
|
|
18
|
+
/** Per-service API key, sent as `Authorization: Bearer <apiKey>`. */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Base URL of the ingestion endpoint, e.g. https://your-backend.com/ingest */
|
|
21
|
+
endpoint: string;
|
|
22
|
+
/** Flush the batch on this interval, regardless of size. Default 5000ms. */
|
|
23
|
+
flushIntervalMs?: number;
|
|
24
|
+
/** Flush immediately once the batch reaches this many events. Default 100. */
|
|
25
|
+
maxBatchSize?: number;
|
|
26
|
+
/** Upper bound on events held in memory if the endpoint is unreachable. Oldest events are dropped past this. Default 1000. */
|
|
27
|
+
maxQueueSize?: number;
|
|
28
|
+
/** Max retry attempts per flush before giving up on that batch. Default 3. */
|
|
29
|
+
maxRetries?: number;
|
|
30
|
+
/** Base backoff delay in ms between retries (doubles each attempt). Default 500ms. */
|
|
31
|
+
retryBaseDelayMs?: number;
|
|
32
|
+
/** Called when events are dropped due to a full queue or exhausted retries. Never throws from inside the client. */
|
|
33
|
+
onDrop?: (dropped: ObservabilityEvent[], reason: "queue-full" | "flush-failed") => void;
|
|
34
|
+
/** Called on unexpected flush errors, for host-app diagnostics. */
|
|
35
|
+
onError?: (error: unknown) => void;
|
|
36
|
+
/** Injectable fetch implementation, mainly for testing. Defaults to global fetch. */
|
|
37
|
+
fetchImpl?: typeof fetch;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Client SDK for the network-observer ingestion endpoint.
|
|
42
|
+
*
|
|
43
|
+
* Every network call is fire-and-forget from the host app's perspective:
|
|
44
|
+
* flush() never throws and never blocks the caller. On sustained failure,
|
|
45
|
+
* the oldest buffered events are dropped rather than growing the queue
|
|
46
|
+
* without bound.
|
|
47
|
+
*/
|
|
48
|
+
declare class ObservabilityClient {
|
|
49
|
+
private readonly options;
|
|
50
|
+
private readonly batcher;
|
|
51
|
+
private readonly fetchImpl;
|
|
52
|
+
private inFlight;
|
|
53
|
+
constructor(options: ObservabilityClientOptions);
|
|
54
|
+
track(metricName: string, value: number, tags?: Record<string, string>): void;
|
|
55
|
+
log(level: LogLevel, message: string, meta?: Record<string, unknown>): void;
|
|
56
|
+
/** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */
|
|
57
|
+
flush(): Promise<void>;
|
|
58
|
+
stop(): void;
|
|
59
|
+
private sendBatch;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { type LogEvent, type LogLevel, type MetricEvent, ObservabilityClient, type ObservabilityClientOptions, type ObservabilityEvent };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ObservabilityClient: () => ObservabilityClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/batcher.ts
|
|
28
|
+
var EventBatcher = class {
|
|
29
|
+
constructor(maxBatchSize, maxQueueSize, flushIntervalMs, onFlush, onDrop) {
|
|
30
|
+
this.maxBatchSize = maxBatchSize;
|
|
31
|
+
this.maxQueueSize = maxQueueSize;
|
|
32
|
+
this.flushIntervalMs = flushIntervalMs;
|
|
33
|
+
this.onFlush = onFlush;
|
|
34
|
+
this.onDrop = onDrop;
|
|
35
|
+
this.buffer = [];
|
|
36
|
+
this.timer = null;
|
|
37
|
+
}
|
|
38
|
+
start() {
|
|
39
|
+
if (this.timer) return;
|
|
40
|
+
this.timer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
41
|
+
this.timer.unref?.();
|
|
42
|
+
}
|
|
43
|
+
stop() {
|
|
44
|
+
if (this.timer) {
|
|
45
|
+
clearInterval(this.timer);
|
|
46
|
+
this.timer = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
push(event) {
|
|
50
|
+
this.buffer.push(event);
|
|
51
|
+
if (this.buffer.length > this.maxQueueSize) {
|
|
52
|
+
const overflow = this.buffer.length - this.maxQueueSize;
|
|
53
|
+
const dropped = this.buffer.splice(0, overflow);
|
|
54
|
+
this.onDrop(dropped);
|
|
55
|
+
}
|
|
56
|
+
if (this.buffer.length >= this.maxBatchSize) {
|
|
57
|
+
this.flush();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
flush() {
|
|
61
|
+
if (this.buffer.length === 0) return;
|
|
62
|
+
const batch = this.buffer;
|
|
63
|
+
this.buffer = [];
|
|
64
|
+
this.onFlush(batch);
|
|
65
|
+
}
|
|
66
|
+
/** Re-queue events after a failed flush, respecting the size bound. */
|
|
67
|
+
requeueFront(events) {
|
|
68
|
+
this.buffer = [...events, ...this.buffer];
|
|
69
|
+
if (this.buffer.length > this.maxQueueSize) {
|
|
70
|
+
const overflow = this.buffer.length - this.maxQueueSize;
|
|
71
|
+
const dropped = this.buffer.splice(0, overflow);
|
|
72
|
+
this.onDrop(dropped);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
size() {
|
|
76
|
+
return this.buffer.length;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/client.ts
|
|
81
|
+
var DEFAULTS = {
|
|
82
|
+
flushIntervalMs: 5e3,
|
|
83
|
+
maxBatchSize: 100,
|
|
84
|
+
maxQueueSize: 1e3,
|
|
85
|
+
maxRetries: 3,
|
|
86
|
+
retryBaseDelayMs: 500
|
|
87
|
+
};
|
|
88
|
+
var ObservabilityClient = class {
|
|
89
|
+
constructor(options) {
|
|
90
|
+
this.options = options;
|
|
91
|
+
this.inFlight = false;
|
|
92
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
93
|
+
this.batcher = new EventBatcher(
|
|
94
|
+
options.maxBatchSize ?? DEFAULTS.maxBatchSize,
|
|
95
|
+
options.maxQueueSize ?? DEFAULTS.maxQueueSize,
|
|
96
|
+
options.flushIntervalMs ?? DEFAULTS.flushIntervalMs,
|
|
97
|
+
(events) => this.sendBatch(events),
|
|
98
|
+
(dropped) => this.options.onDrop?.(dropped, "queue-full")
|
|
99
|
+
);
|
|
100
|
+
this.batcher.start();
|
|
101
|
+
}
|
|
102
|
+
track(metricName, value, tags) {
|
|
103
|
+
const event = {
|
|
104
|
+
type: "metric",
|
|
105
|
+
name: metricName,
|
|
106
|
+
value,
|
|
107
|
+
tags,
|
|
108
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
109
|
+
};
|
|
110
|
+
this.batcher.push(event);
|
|
111
|
+
}
|
|
112
|
+
log(level, message, meta) {
|
|
113
|
+
const event = {
|
|
114
|
+
type: "log",
|
|
115
|
+
level,
|
|
116
|
+
message,
|
|
117
|
+
meta,
|
|
118
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
119
|
+
};
|
|
120
|
+
this.batcher.push(event);
|
|
121
|
+
}
|
|
122
|
+
/** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */
|
|
123
|
+
async flush() {
|
|
124
|
+
this.batcher.flush();
|
|
125
|
+
for (let i = 0; i < 20 && this.inFlight; i++) {
|
|
126
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
stop() {
|
|
130
|
+
this.batcher.stop();
|
|
131
|
+
}
|
|
132
|
+
async sendBatch(events) {
|
|
133
|
+
this.inFlight = true;
|
|
134
|
+
const maxRetries = this.options.maxRetries ?? DEFAULTS.maxRetries;
|
|
135
|
+
const baseDelay = this.options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelayMs;
|
|
136
|
+
try {
|
|
137
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
138
|
+
try {
|
|
139
|
+
const res = await this.fetchImpl(this.options.endpoint, {
|
|
140
|
+
method: "POST",
|
|
141
|
+
headers: {
|
|
142
|
+
"Content-Type": "application/json",
|
|
143
|
+
Authorization: `Bearer ${this.options.apiKey}`
|
|
144
|
+
},
|
|
145
|
+
body: JSON.stringify({ events })
|
|
146
|
+
});
|
|
147
|
+
if (res.ok) return;
|
|
148
|
+
if (res.status >= 400 && res.status < 500) {
|
|
149
|
+
this.options.onDrop?.(events, "flush-failed");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (attempt === maxRetries) {
|
|
154
|
+
this.options.onError?.(err);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (attempt < maxRetries) {
|
|
158
|
+
await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
this.options.onDrop?.(events, "flush-failed");
|
|
162
|
+
} finally {
|
|
163
|
+
this.inFlight = false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
168
|
+
0 && (module.exports = {
|
|
169
|
+
ObservabilityClient
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/batcher.ts","../src/client.ts"],"sourcesContent":["export { ObservabilityClient } from \"./client.js\";\nexport type {\n LogEvent,\n LogLevel,\n MetricEvent,\n ObservabilityClientOptions,\n ObservabilityEvent,\n} from \"./types.js\";\n","import type { ObservabilityEvent } from \"./types.js\";\n\n/**\n * Bounded in-memory buffer with timer/size-triggered flush.\n * Never grows past maxQueueSize — the oldest events are dropped first,\n * because the monitoring client must never be the reason the host app\n * runs out of memory.\n */\nexport class EventBatcher {\n private buffer: ObservabilityEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n private readonly maxBatchSize: number,\n private readonly maxQueueSize: number,\n private readonly flushIntervalMs: number,\n private readonly onFlush: (events: ObservabilityEvent[]) => void,\n private readonly onDrop: (dropped: ObservabilityEvent[]) => void,\n ) {}\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.flush(), this.flushIntervalMs);\n // Don't let this timer keep a Node process alive on its own.\n this.timer.unref?.();\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n push(event: ObservabilityEvent): void {\n this.buffer.push(event);\n\n if (this.buffer.length > this.maxQueueSize) {\n const overflow = this.buffer.length - this.maxQueueSize;\n const dropped = this.buffer.splice(0, overflow);\n this.onDrop(dropped);\n }\n\n if (this.buffer.length >= this.maxBatchSize) {\n this.flush();\n }\n }\n\n flush(): void {\n if (this.buffer.length === 0) return;\n const batch = this.buffer;\n this.buffer = [];\n this.onFlush(batch);\n }\n\n /** Re-queue events after a failed flush, respecting the size bound. */\n requeueFront(events: ObservabilityEvent[]): void {\n this.buffer = [...events, ...this.buffer];\n if (this.buffer.length > this.maxQueueSize) {\n const overflow = this.buffer.length - this.maxQueueSize;\n const dropped = this.buffer.splice(0, overflow);\n this.onDrop(dropped);\n }\n }\n\n size(): number {\n return this.buffer.length;\n }\n}\n","import { EventBatcher } from \"./batcher.js\";\nimport type {\n LogEvent,\n LogLevel,\n MetricEvent,\n ObservabilityClientOptions,\n ObservabilityEvent,\n} from \"./types.js\";\n\nconst DEFAULTS = {\n flushIntervalMs: 5000,\n maxBatchSize: 100,\n maxQueueSize: 1000,\n maxRetries: 3,\n retryBaseDelayMs: 500,\n} as const;\n\n/**\n * Client SDK for the network-observer ingestion endpoint.\n *\n * Every network call is fire-and-forget from the host app's perspective:\n * flush() never throws and never blocks the caller. On sustained failure,\n * the oldest buffered events are dropped rather than growing the queue\n * without bound.\n */\nexport class ObservabilityClient {\n private readonly batcher: EventBatcher;\n private readonly fetchImpl: typeof fetch;\n private inFlight = false;\n\n constructor(private readonly options: ObservabilityClientOptions) {\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.batcher = new EventBatcher(\n options.maxBatchSize ?? DEFAULTS.maxBatchSize,\n options.maxQueueSize ?? DEFAULTS.maxQueueSize,\n options.flushIntervalMs ?? DEFAULTS.flushIntervalMs,\n (events) => this.sendBatch(events),\n (dropped) => this.options.onDrop?.(dropped, \"queue-full\"),\n );\n this.batcher.start();\n }\n\n track(metricName: string, value: number, tags?: Record<string, string>): void {\n const event: MetricEvent = {\n type: \"metric\",\n name: metricName,\n value,\n tags,\n timestamp: new Date().toISOString(),\n };\n this.batcher.push(event);\n }\n\n log(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n const event: LogEvent = {\n type: \"log\",\n level,\n message,\n meta,\n timestamp: new Date().toISOString(),\n };\n this.batcher.push(event);\n }\n\n /** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */\n async flush(): Promise<void> {\n this.batcher.flush();\n // Give the in-flight send a moment to land during shutdown.\n for (let i = 0; i < 20 && this.inFlight; i++) {\n await new Promise((r) => setTimeout(r, 50));\n }\n }\n\n stop(): void {\n this.batcher.stop();\n }\n\n private async sendBatch(events: ObservabilityEvent[]): Promise<void> {\n this.inFlight = true;\n const maxRetries = this.options.maxRetries ?? DEFAULTS.maxRetries;\n const baseDelay = this.options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelayMs;\n\n try {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const res = await this.fetchImpl(this.options.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify({ events }),\n });\n if (res.ok) return;\n if (res.status >= 400 && res.status < 500) {\n // Not retryable — bad key or malformed payload.\n this.options.onDrop?.(events, \"flush-failed\");\n return;\n }\n } catch (err) {\n if (attempt === maxRetries) {\n this.options.onError?.(err);\n }\n }\n if (attempt < maxRetries) {\n await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));\n }\n }\n // Exhausted retries: drop this batch rather than requeueing it forever.\n this.options.onDrop?.(events, \"flush-failed\");\n } finally {\n this.inFlight = false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/batcher.ts
|
|
2
|
+
var EventBatcher = class {
|
|
3
|
+
constructor(maxBatchSize, maxQueueSize, flushIntervalMs, onFlush, onDrop) {
|
|
4
|
+
this.maxBatchSize = maxBatchSize;
|
|
5
|
+
this.maxQueueSize = maxQueueSize;
|
|
6
|
+
this.flushIntervalMs = flushIntervalMs;
|
|
7
|
+
this.onFlush = onFlush;
|
|
8
|
+
this.onDrop = onDrop;
|
|
9
|
+
this.buffer = [];
|
|
10
|
+
this.timer = null;
|
|
11
|
+
}
|
|
12
|
+
start() {
|
|
13
|
+
if (this.timer) return;
|
|
14
|
+
this.timer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
15
|
+
this.timer.unref?.();
|
|
16
|
+
}
|
|
17
|
+
stop() {
|
|
18
|
+
if (this.timer) {
|
|
19
|
+
clearInterval(this.timer);
|
|
20
|
+
this.timer = null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
push(event) {
|
|
24
|
+
this.buffer.push(event);
|
|
25
|
+
if (this.buffer.length > this.maxQueueSize) {
|
|
26
|
+
const overflow = this.buffer.length - this.maxQueueSize;
|
|
27
|
+
const dropped = this.buffer.splice(0, overflow);
|
|
28
|
+
this.onDrop(dropped);
|
|
29
|
+
}
|
|
30
|
+
if (this.buffer.length >= this.maxBatchSize) {
|
|
31
|
+
this.flush();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
flush() {
|
|
35
|
+
if (this.buffer.length === 0) return;
|
|
36
|
+
const batch = this.buffer;
|
|
37
|
+
this.buffer = [];
|
|
38
|
+
this.onFlush(batch);
|
|
39
|
+
}
|
|
40
|
+
/** Re-queue events after a failed flush, respecting the size bound. */
|
|
41
|
+
requeueFront(events) {
|
|
42
|
+
this.buffer = [...events, ...this.buffer];
|
|
43
|
+
if (this.buffer.length > this.maxQueueSize) {
|
|
44
|
+
const overflow = this.buffer.length - this.maxQueueSize;
|
|
45
|
+
const dropped = this.buffer.splice(0, overflow);
|
|
46
|
+
this.onDrop(dropped);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
size() {
|
|
50
|
+
return this.buffer.length;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/client.ts
|
|
55
|
+
var DEFAULTS = {
|
|
56
|
+
flushIntervalMs: 5e3,
|
|
57
|
+
maxBatchSize: 100,
|
|
58
|
+
maxQueueSize: 1e3,
|
|
59
|
+
maxRetries: 3,
|
|
60
|
+
retryBaseDelayMs: 500
|
|
61
|
+
};
|
|
62
|
+
var ObservabilityClient = class {
|
|
63
|
+
constructor(options) {
|
|
64
|
+
this.options = options;
|
|
65
|
+
this.inFlight = false;
|
|
66
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
67
|
+
this.batcher = new EventBatcher(
|
|
68
|
+
options.maxBatchSize ?? DEFAULTS.maxBatchSize,
|
|
69
|
+
options.maxQueueSize ?? DEFAULTS.maxQueueSize,
|
|
70
|
+
options.flushIntervalMs ?? DEFAULTS.flushIntervalMs,
|
|
71
|
+
(events) => this.sendBatch(events),
|
|
72
|
+
(dropped) => this.options.onDrop?.(dropped, "queue-full")
|
|
73
|
+
);
|
|
74
|
+
this.batcher.start();
|
|
75
|
+
}
|
|
76
|
+
track(metricName, value, tags) {
|
|
77
|
+
const event = {
|
|
78
|
+
type: "metric",
|
|
79
|
+
name: metricName,
|
|
80
|
+
value,
|
|
81
|
+
tags,
|
|
82
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
83
|
+
};
|
|
84
|
+
this.batcher.push(event);
|
|
85
|
+
}
|
|
86
|
+
log(level, message, meta) {
|
|
87
|
+
const event = {
|
|
88
|
+
type: "log",
|
|
89
|
+
level,
|
|
90
|
+
message,
|
|
91
|
+
meta,
|
|
92
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
|
+
};
|
|
94
|
+
this.batcher.push(event);
|
|
95
|
+
}
|
|
96
|
+
/** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */
|
|
97
|
+
async flush() {
|
|
98
|
+
this.batcher.flush();
|
|
99
|
+
for (let i = 0; i < 20 && this.inFlight; i++) {
|
|
100
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
stop() {
|
|
104
|
+
this.batcher.stop();
|
|
105
|
+
}
|
|
106
|
+
async sendBatch(events) {
|
|
107
|
+
this.inFlight = true;
|
|
108
|
+
const maxRetries = this.options.maxRetries ?? DEFAULTS.maxRetries;
|
|
109
|
+
const baseDelay = this.options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelayMs;
|
|
110
|
+
try {
|
|
111
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
112
|
+
try {
|
|
113
|
+
const res = await this.fetchImpl(this.options.endpoint, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
Authorization: `Bearer ${this.options.apiKey}`
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({ events })
|
|
120
|
+
});
|
|
121
|
+
if (res.ok) return;
|
|
122
|
+
if (res.status >= 400 && res.status < 500) {
|
|
123
|
+
this.options.onDrop?.(events, "flush-failed");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
if (attempt === maxRetries) {
|
|
128
|
+
this.options.onError?.(err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (attempt < maxRetries) {
|
|
132
|
+
await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
this.options.onDrop?.(events, "flush-failed");
|
|
136
|
+
} finally {
|
|
137
|
+
this.inFlight = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
export {
|
|
142
|
+
ObservabilityClient
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/batcher.ts","../src/client.ts"],"sourcesContent":["import type { ObservabilityEvent } from \"./types.js\";\n\n/**\n * Bounded in-memory buffer with timer/size-triggered flush.\n * Never grows past maxQueueSize — the oldest events are dropped first,\n * because the monitoring client must never be the reason the host app\n * runs out of memory.\n */\nexport class EventBatcher {\n private buffer: ObservabilityEvent[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n private readonly maxBatchSize: number,\n private readonly maxQueueSize: number,\n private readonly flushIntervalMs: number,\n private readonly onFlush: (events: ObservabilityEvent[]) => void,\n private readonly onDrop: (dropped: ObservabilityEvent[]) => void,\n ) {}\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.flush(), this.flushIntervalMs);\n // Don't let this timer keep a Node process alive on its own.\n this.timer.unref?.();\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n push(event: ObservabilityEvent): void {\n this.buffer.push(event);\n\n if (this.buffer.length > this.maxQueueSize) {\n const overflow = this.buffer.length - this.maxQueueSize;\n const dropped = this.buffer.splice(0, overflow);\n this.onDrop(dropped);\n }\n\n if (this.buffer.length >= this.maxBatchSize) {\n this.flush();\n }\n }\n\n flush(): void {\n if (this.buffer.length === 0) return;\n const batch = this.buffer;\n this.buffer = [];\n this.onFlush(batch);\n }\n\n /** Re-queue events after a failed flush, respecting the size bound. */\n requeueFront(events: ObservabilityEvent[]): void {\n this.buffer = [...events, ...this.buffer];\n if (this.buffer.length > this.maxQueueSize) {\n const overflow = this.buffer.length - this.maxQueueSize;\n const dropped = this.buffer.splice(0, overflow);\n this.onDrop(dropped);\n }\n }\n\n size(): number {\n return this.buffer.length;\n }\n}\n","import { EventBatcher } from \"./batcher.js\";\nimport type {\n LogEvent,\n LogLevel,\n MetricEvent,\n ObservabilityClientOptions,\n ObservabilityEvent,\n} from \"./types.js\";\n\nconst DEFAULTS = {\n flushIntervalMs: 5000,\n maxBatchSize: 100,\n maxQueueSize: 1000,\n maxRetries: 3,\n retryBaseDelayMs: 500,\n} as const;\n\n/**\n * Client SDK for the network-observer ingestion endpoint.\n *\n * Every network call is fire-and-forget from the host app's perspective:\n * flush() never throws and never blocks the caller. On sustained failure,\n * the oldest buffered events are dropped rather than growing the queue\n * without bound.\n */\nexport class ObservabilityClient {\n private readonly batcher: EventBatcher;\n private readonly fetchImpl: typeof fetch;\n private inFlight = false;\n\n constructor(private readonly options: ObservabilityClientOptions) {\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.batcher = new EventBatcher(\n options.maxBatchSize ?? DEFAULTS.maxBatchSize,\n options.maxQueueSize ?? DEFAULTS.maxQueueSize,\n options.flushIntervalMs ?? DEFAULTS.flushIntervalMs,\n (events) => this.sendBatch(events),\n (dropped) => this.options.onDrop?.(dropped, \"queue-full\"),\n );\n this.batcher.start();\n }\n\n track(metricName: string, value: number, tags?: Record<string, string>): void {\n const event: MetricEvent = {\n type: \"metric\",\n name: metricName,\n value,\n tags,\n timestamp: new Date().toISOString(),\n };\n this.batcher.push(event);\n }\n\n log(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n const event: LogEvent = {\n type: \"log\",\n level,\n message,\n meta,\n timestamp: new Date().toISOString(),\n };\n this.batcher.push(event);\n }\n\n /** Force an immediate flush — call on process shutdown (SIGTERM/beforeExit). */\n async flush(): Promise<void> {\n this.batcher.flush();\n // Give the in-flight send a moment to land during shutdown.\n for (let i = 0; i < 20 && this.inFlight; i++) {\n await new Promise((r) => setTimeout(r, 50));\n }\n }\n\n stop(): void {\n this.batcher.stop();\n }\n\n private async sendBatch(events: ObservabilityEvent[]): Promise<void> {\n this.inFlight = true;\n const maxRetries = this.options.maxRetries ?? DEFAULTS.maxRetries;\n const baseDelay = this.options.retryBaseDelayMs ?? DEFAULTS.retryBaseDelayMs;\n\n try {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const res = await this.fetchImpl(this.options.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.options.apiKey}`,\n },\n body: JSON.stringify({ events }),\n });\n if (res.ok) return;\n if (res.status >= 400 && res.status < 500) {\n // Not retryable — bad key or malformed payload.\n this.options.onDrop?.(events, \"flush-failed\");\n return;\n }\n } catch (err) {\n if (attempt === maxRetries) {\n this.options.onError?.(err);\n }\n }\n if (attempt < maxRetries) {\n await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));\n }\n }\n // Exhausted retries: drop this batch rather than requeueing it forever.\n this.options.onDrop?.(events, \"flush-failed\");\n } finally {\n this.inFlight = false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prath/observability-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tiny client for the network-observer observability service: batches metrics and logs client-side and flushes them off the host app's hot path.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup",
|
|
13
|
+
"dev": "tsup --watch",
|
|
14
|
+
"prepublishOnly": "npm run build",
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"keywords": ["observability", "metrics", "logging", "monitoring", "sdk"],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "^8.2.4",
|
|
21
|
+
"typescript": "^5.5.4"
|
|
22
|
+
}
|
|
23
|
+
}
|