@trace-stack/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/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # @trace-stack/node
2
+
3
+ Official Node.js SDK for [TraceStack](https://tracestack.dev) — a multi-tenant observability and log monitoring platform.
4
+
5
+ **Zero dependencies** · Batching · Exponential backoff retry · Graceful shutdown · TypeScript-first
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @trace-stack/node
13
+ ```
14
+
15
+ > **Requires Node.js 18+** (uses native `fetch` API)
16
+
17
+ ## Quick Start
18
+
19
+ ```ts
20
+ import { TraceStack } from "@trace-stack/node";
21
+
22
+ const logger = new TraceStack({
23
+ apiKey: "ts_live_xxxx",
24
+ serviceName: "payment-service",
25
+ });
26
+
27
+ // Log at different severity levels
28
+ logger.debug("Debugging payment flow", { step: "init" });
29
+ logger.info("User logged in", { userId: "u_123" });
30
+ logger.warn("High memory usage", { memoryMB: 450 });
31
+ logger.error("Payment failed", { orderId: "ord_456", amount: 999 });
32
+ logger.fatal("Database connection lost", { host: "db-primary" });
33
+
34
+ // Graceful shutdown (flushes remaining logs)
35
+ process.on("SIGTERM", async () => {
36
+ await logger.destroy();
37
+ process.exit(0);
38
+ });
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ | Option | Type | Default | Description |
44
+ |--------|------|---------|-------------|
45
+ | `apiKey` | `string` | **required** | Your TraceStack API key (must start with `ts_`) |
46
+ | `serviceName` | `string` | `"default"` | Identifies the sending service |
47
+ | `endpoint` | `string` | `"http://localhost:5000"` | Ingestion API URL |
48
+ | `batchSize` | `number` | `50` | Logs to buffer before auto-flush |
49
+ | `flushInterval` | `number` | `5000` | Auto-flush interval in ms |
50
+ | `maxRetries` | `number` | `3` | Max retry attempts on failure |
51
+ | `timeout` | `number` | `10000` | HTTP request timeout in ms |
52
+ | `debug` | `boolean` | `false` | Log SDK internals to console |
53
+
54
+ ## Features
55
+
56
+ ### Batching
57
+
58
+ Logs are buffered in memory and flushed in batches for efficiency. Flushes happen when:
59
+ - The buffer reaches `batchSize` (default: 50 logs)
60
+ - The `flushInterval` timer fires (default: every 5 seconds)
61
+ - You call `logger.flush()` manually
62
+
63
+ ```ts
64
+ // Manual flush before a critical operation
65
+ await logger.flush();
66
+ ```
67
+
68
+ ### Retry with Exponential Backoff
69
+
70
+ Failed HTTP requests are retried up to `maxRetries` times with exponential backoff:
71
+ - Attempt 1: immediate
72
+ - Retry 1: wait 1s
73
+ - Retry 2: wait 2s
74
+ - Retry 3: wait 4s
75
+
76
+ Rate-limited requests (HTTP 429) respect the `Retry-After` header. Client errors (4xx) are **not** retried.
77
+
78
+ ### Auto-Metadata
79
+
80
+ Every log entry automatically includes:
81
+ - `hostname` — machine hostname
82
+ - `pid` — Node.js process ID
83
+ - `nodeVersion` — Node.js runtime version
84
+
85
+ Custom metadata is merged with system metadata:
86
+
87
+ ```ts
88
+ logger.info("Order placed", { orderId: "123", amount: 49.99 });
89
+ // metadata = { hostname: "...", pid: 1234, nodeVersion: "v20.0.0", orderId: "123", amount: 49.99 }
90
+ ```
91
+
92
+ ### Graceful Shutdown
93
+
94
+ The SDK registers `SIGTERM`, `SIGINT`, and `beforeExit` handlers to flush remaining logs before the process exits.
95
+
96
+ You can also manually trigger shutdown:
97
+
98
+ ```ts
99
+ await logger.destroy();
100
+ ```
101
+
102
+ After `destroy()`, no new logs are accepted.
103
+
104
+ ## API Reference
105
+
106
+ ### `new TraceStack(config: TraceStackConfig)`
107
+
108
+ Creates a new TraceStack logger instance.
109
+
110
+ ### `logger.debug(message, metadata?)`
111
+ ### `logger.info(message, metadata?)`
112
+ ### `logger.warn(message, metadata?)`
113
+ ### `logger.error(message, metadata?)`
114
+ ### `logger.fatal(message, metadata?)`
115
+
116
+ Log a message at the specified severity level.
117
+
118
+ - `message: string` — Log message (required)
119
+ - `metadata?: Record<string, unknown>` — Optional structured data
120
+
121
+ ### `logger.flush(): Promise<void>`
122
+
123
+ Manually flush all buffered logs to the ingestion API.
124
+
125
+ ### `logger.destroy(): Promise<void>`
126
+
127
+ Gracefully shut down the SDK. Flushes remaining logs and stops all timers.
128
+
129
+ ## Log Levels
130
+
131
+ | Level | When to use |
132
+ |-------|-------------|
133
+ | `debug` | Detailed diagnostic information |
134
+ | `info` | General operational events |
135
+ | `warn` | Potential issues that aren't errors |
136
+ | `error` | Error events that might still allow the app to continue |
137
+ | `fatal` | Critical errors that require immediate attention |
138
+
139
+ ## License
140
+
141
+ MIT
@@ -0,0 +1,51 @@
1
+ import type { LogEntry } from "./types";
2
+ import { Transport } from "./transport";
3
+ /**
4
+ * In-memory log buffer that accumulates entries and
5
+ * flushes them in batches via the Transport layer.
6
+ *
7
+ * Auto-flushes when:
8
+ * - Buffer reaches `batchSize` threshold
9
+ * - `flushInterval` timer fires
10
+ *
11
+ * Provides a mutex to prevent concurrent flushes.
12
+ */
13
+ export declare class Batcher {
14
+ private buffer;
15
+ private flushTimer;
16
+ private flushing;
17
+ private destroyed;
18
+ private readonly batchSize;
19
+ private readonly flushInterval;
20
+ private readonly transport;
21
+ private readonly debug;
22
+ constructor(options: {
23
+ transport: Transport;
24
+ batchSize?: number;
25
+ flushInterval?: number;
26
+ debug?: boolean;
27
+ });
28
+ /**
29
+ * Add a log entry to the buffer.
30
+ * Triggers an immediate flush if the buffer reaches batchSize.
31
+ */
32
+ add(entry: LogEntry): void;
33
+ /**
34
+ * Flush all buffered logs to the transport.
35
+ * Thread-safe: only one flush can run at a time.
36
+ */
37
+ flush(): Promise<void>;
38
+ /**
39
+ * Destroy the batcher: stop the timer and flush remaining logs.
40
+ * After destroy(), no new logs can be added.
41
+ */
42
+ destroy(): Promise<void>;
43
+ /**
44
+ * Returns the current number of buffered logs.
45
+ */
46
+ get size(): number;
47
+ private startTimer;
48
+ private stopTimer;
49
+ private log;
50
+ }
51
+ //# sourceMappingURL=batcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batcher.d.ts","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AASxC;;;;;;;;;GASG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;gBAEpB,OAAO,EAAE;QACnB,SAAS,EAAE,SAAS,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;IAUD;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAmB1B;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B5B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAID,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,GAAG;CAKZ"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Batcher = void 0;
4
+ // ─── Constants ───────────────────────────────────────────────
5
+ const DEFAULT_BATCH_SIZE = 50;
6
+ const DEFAULT_FLUSH_INTERVAL = 5000; // 5 seconds
7
+ // ─── Batcher ─────────────────────────────────────────────────
8
+ /**
9
+ * In-memory log buffer that accumulates entries and
10
+ * flushes them in batches via the Transport layer.
11
+ *
12
+ * Auto-flushes when:
13
+ * - Buffer reaches `batchSize` threshold
14
+ * - `flushInterval` timer fires
15
+ *
16
+ * Provides a mutex to prevent concurrent flushes.
17
+ */
18
+ class Batcher {
19
+ constructor(options) {
20
+ this.buffer = [];
21
+ this.flushTimer = null;
22
+ this.flushing = false;
23
+ this.destroyed = false;
24
+ this.transport = options.transport;
25
+ this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
26
+ this.flushInterval = options.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
27
+ this.debug = options.debug ?? false;
28
+ // Start the periodic flush timer
29
+ this.startTimer();
30
+ }
31
+ /**
32
+ * Add a log entry to the buffer.
33
+ * Triggers an immediate flush if the buffer reaches batchSize.
34
+ */
35
+ add(entry) {
36
+ if (this.destroyed) {
37
+ this.log("SDK destroyed — dropping log entry");
38
+ return;
39
+ }
40
+ this.buffer.push(entry);
41
+ this.log(`Buffered log [${entry.level}]: ${entry.message.substring(0, 80)}`);
42
+ // Auto-flush when batch size reached
43
+ if (this.buffer.length >= this.batchSize) {
44
+ this.log(`Batch size ${this.batchSize} reached — flushing`);
45
+ // Fire-and-forget flush (don't block the caller)
46
+ this.flush().catch((err) => {
47
+ this.log(`Flush error: ${err}`);
48
+ });
49
+ }
50
+ }
51
+ /**
52
+ * Flush all buffered logs to the transport.
53
+ * Thread-safe: only one flush can run at a time.
54
+ */
55
+ async flush() {
56
+ // Mutex — prevent concurrent flushes
57
+ if (this.flushing) {
58
+ this.log("Flush already in progress — skipping");
59
+ return;
60
+ }
61
+ if (this.buffer.length === 0) {
62
+ return;
63
+ }
64
+ this.flushing = true;
65
+ try {
66
+ // Drain the buffer (take all current entries)
67
+ const batch = this.buffer.splice(0, this.buffer.length);
68
+ this.log(`Flushing ${batch.length} logs`);
69
+ const result = await this.transport.send({ logs: batch });
70
+ if (!result.success) {
71
+ this.log(`Flush failed: ${result.error}`);
72
+ // Note: we intentionally don't re-add failed logs to the buffer.
73
+ // This prevents unbounded memory growth if the server is persistently down.
74
+ // The transport layer already retried with backoff.
75
+ }
76
+ }
77
+ finally {
78
+ this.flushing = false;
79
+ }
80
+ }
81
+ /**
82
+ * Destroy the batcher: stop the timer and flush remaining logs.
83
+ * After destroy(), no new logs can be added.
84
+ */
85
+ async destroy() {
86
+ if (this.destroyed)
87
+ return;
88
+ this.destroyed = true;
89
+ this.stopTimer();
90
+ this.log("Destroying batcher — final flush");
91
+ await this.flush();
92
+ }
93
+ /**
94
+ * Returns the current number of buffered logs.
95
+ */
96
+ get size() {
97
+ return this.buffer.length;
98
+ }
99
+ // ─── Timer Management ──────────────────────────────────
100
+ startTimer() {
101
+ if (this.flushInterval > 0) {
102
+ this.flushTimer = setInterval(() => {
103
+ this.flush().catch((err) => {
104
+ this.log(`Periodic flush error: ${err}`);
105
+ });
106
+ }, this.flushInterval);
107
+ // Allow the Node.js process to exit even if timer is running
108
+ if (this.flushTimer && typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
109
+ this.flushTimer.unref();
110
+ }
111
+ }
112
+ }
113
+ stopTimer() {
114
+ if (this.flushTimer) {
115
+ clearInterval(this.flushTimer);
116
+ this.flushTimer = null;
117
+ }
118
+ }
119
+ // ─── Debug ─────────────────────────────────────────────
120
+ log(message) {
121
+ if (this.debug) {
122
+ console.log(`[TraceStack:Batcher] ${message}`);
123
+ }
124
+ }
125
+ }
126
+ exports.Batcher = Batcher;
127
+ //# sourceMappingURL=batcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batcher.js","sourceRoot":"","sources":["../src/batcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { TraceStackConfig } from "./types";
2
+ /**
3
+ * TraceStack SDK client for Node.js.
4
+ *
5
+ * Captures logs and sends them to the TraceStack ingestion API
6
+ * with automatic batching, exponential backoff retry, and
7
+ * graceful shutdown support.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { TraceStack } from "@trace-stack/node";
12
+ *
13
+ * const logger = new TraceStack({
14
+ * apiKey: "ts_live_xxxx",
15
+ * serviceName: "payment-service",
16
+ * });
17
+ *
18
+ * logger.info("User logged in", { userId: "123" });
19
+ * logger.error("Payment failed", { orderId: "456", amount: 999 });
20
+ *
21
+ * // On shutdown
22
+ * await logger.destroy();
23
+ * ```
24
+ */
25
+ export declare class TraceStack {
26
+ private readonly config;
27
+ private readonly batcher;
28
+ private readonly shutdownHandlers;
29
+ private destroyed;
30
+ private readonly systemMeta;
31
+ constructor(config: TraceStackConfig);
32
+ /**
33
+ * Log a debug-level message.
34
+ */
35
+ debug(message: string, metadata?: Record<string, unknown>): void;
36
+ /**
37
+ * Log an info-level message.
38
+ */
39
+ info(message: string, metadata?: Record<string, unknown>): void;
40
+ /**
41
+ * Log a warning-level message.
42
+ */
43
+ warn(message: string, metadata?: Record<string, unknown>): void;
44
+ /**
45
+ * Log an error-level message.
46
+ */
47
+ error(message: string, metadata?: Record<string, unknown>): void;
48
+ /**
49
+ * Log a fatal-level message.
50
+ */
51
+ fatal(message: string, metadata?: Record<string, unknown>): void;
52
+ /**
53
+ * Manually flush all buffered logs immediately.
54
+ * Useful before a critical operation or checkpoint.
55
+ */
56
+ flush(): Promise<void>;
57
+ /**
58
+ * Gracefully shut down the SDK.
59
+ * Flushes all remaining logs and stops background timers.
60
+ * After calling destroy(), no new logs will be accepted.
61
+ */
62
+ destroy(): Promise<void>;
63
+ /**
64
+ * Capture a log entry and add it to the buffer.
65
+ */
66
+ private capture;
67
+ private registerShutdownHandlers;
68
+ private removeShutdownHandlers;
69
+ private log;
70
+ }
71
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,SAAS,CAAC;AAYpE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGJ;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA0B;IAC3D,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;gBAEzC,MAAM,EAAE,gBAAgB;IAwDpC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMhE;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B;;OAEG;IACH,OAAO,CAAC,OAAO;IAyBf,OAAO,CAAC,wBAAwB;IAwBhC,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,GAAG;CAMZ"}
package/dist/client.js ADDED
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TraceStack = void 0;
7
+ const transport_1 = require("./transport");
8
+ const batcher_1 = require("./batcher");
9
+ const os_1 = __importDefault(require("os"));
10
+ // ─── Constants ───────────────────────────────────────────────
11
+ const API_KEY_PREFIX = "ts_";
12
+ const DEFAULT_ENDPOINT = "http://localhost:5000";
13
+ // ─── TraceStack Client ──────────────────────────────────────
14
+ /**
15
+ * TraceStack SDK client for Node.js.
16
+ *
17
+ * Captures logs and sends them to the TraceStack ingestion API
18
+ * with automatic batching, exponential backoff retry, and
19
+ * graceful shutdown support.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { TraceStack } from "@trace-stack/node";
24
+ *
25
+ * const logger = new TraceStack({
26
+ * apiKey: "ts_live_xxxx",
27
+ * serviceName: "payment-service",
28
+ * });
29
+ *
30
+ * logger.info("User logged in", { userId: "123" });
31
+ * logger.error("Payment failed", { orderId: "456", amount: 999 });
32
+ *
33
+ * // On shutdown
34
+ * await logger.destroy();
35
+ * ```
36
+ */
37
+ class TraceStack {
38
+ constructor(config) {
39
+ this.destroyed = false;
40
+ // ─── Validate API key ─────────────────────────────────
41
+ if (!config.apiKey) {
42
+ throw new Error("[TraceStack] apiKey is required");
43
+ }
44
+ if (!config.apiKey.startsWith(API_KEY_PREFIX)) {
45
+ throw new Error(`[TraceStack] apiKey must start with "${API_KEY_PREFIX}" — got "${config.apiKey.substring(0, 10)}..."`);
46
+ }
47
+ // ─── Merge defaults ──────────────────────────────────
48
+ this.config = {
49
+ ...config,
50
+ serviceName: config.serviceName ?? "default",
51
+ endpoint: config.endpoint ?? DEFAULT_ENDPOINT,
52
+ debug: config.debug ?? false,
53
+ };
54
+ // ─── System metadata (captured once) ─────────────────
55
+ this.systemMeta = {
56
+ hostname: os_1.default.hostname(),
57
+ pid: process.pid,
58
+ nodeVersion: process.version,
59
+ };
60
+ // ─── Initialize transport + batcher ──────────────────
61
+ const transport = new transport_1.Transport({
62
+ endpoint: this.config.endpoint,
63
+ apiKey: this.config.apiKey,
64
+ maxRetries: config.maxRetries,
65
+ timeout: config.timeout,
66
+ debug: this.config.debug,
67
+ });
68
+ this.batcher = new batcher_1.Batcher({
69
+ transport,
70
+ batchSize: config.batchSize,
71
+ flushInterval: config.flushInterval,
72
+ debug: this.config.debug,
73
+ });
74
+ // ─── Graceful shutdown handlers ──────────────────────
75
+ this.shutdownHandlers = [];
76
+ this.registerShutdownHandlers();
77
+ this.log("Initialized", {
78
+ endpoint: this.config.endpoint,
79
+ serviceName: this.config.serviceName,
80
+ batchSize: config.batchSize ?? 50,
81
+ flushInterval: config.flushInterval ?? 5000,
82
+ });
83
+ }
84
+ // ─── Public Logging Methods ────────────────────────────
85
+ /**
86
+ * Log a debug-level message.
87
+ */
88
+ debug(message, metadata) {
89
+ this.capture("debug", message, metadata);
90
+ }
91
+ /**
92
+ * Log an info-level message.
93
+ */
94
+ info(message, metadata) {
95
+ this.capture("info", message, metadata);
96
+ }
97
+ /**
98
+ * Log a warning-level message.
99
+ */
100
+ warn(message, metadata) {
101
+ this.capture("warn", message, metadata);
102
+ }
103
+ /**
104
+ * Log an error-level message.
105
+ */
106
+ error(message, metadata) {
107
+ this.capture("error", message, metadata);
108
+ }
109
+ /**
110
+ * Log a fatal-level message.
111
+ */
112
+ fatal(message, metadata) {
113
+ this.capture("fatal", message, metadata);
114
+ }
115
+ // ─── Buffer Control ────────────────────────────────────
116
+ /**
117
+ * Manually flush all buffered logs immediately.
118
+ * Useful before a critical operation or checkpoint.
119
+ */
120
+ async flush() {
121
+ await this.batcher.flush();
122
+ }
123
+ /**
124
+ * Gracefully shut down the SDK.
125
+ * Flushes all remaining logs and stops background timers.
126
+ * After calling destroy(), no new logs will be accepted.
127
+ */
128
+ async destroy() {
129
+ if (this.destroyed)
130
+ return;
131
+ this.destroyed = true;
132
+ this.log("Shutting down...");
133
+ this.removeShutdownHandlers();
134
+ await this.batcher.destroy();
135
+ this.log("Shutdown complete");
136
+ }
137
+ // ─── Internal ──────────────────────────────────────────
138
+ /**
139
+ * Capture a log entry and add it to the buffer.
140
+ */
141
+ capture(level, message, metadata) {
142
+ if (this.destroyed) {
143
+ this.log("SDK destroyed — dropping log");
144
+ return;
145
+ }
146
+ const entry = {
147
+ level,
148
+ message,
149
+ timestamp: new Date().toISOString(),
150
+ serviceName: this.config.serviceName,
151
+ metadata: metadata
152
+ ? { ...this.systemMeta, ...metadata }
153
+ : { ...this.systemMeta },
154
+ };
155
+ this.batcher.add(entry);
156
+ }
157
+ // ─── Shutdown Handlers ─────────────────────────────────
158
+ registerShutdownHandlers() {
159
+ const handler = async () => {
160
+ this.log("Received shutdown signal — flushing logs");
161
+ await this.destroy();
162
+ };
163
+ // Wrap in a sync function for process event listeners
164
+ const syncHandler = () => {
165
+ handler().catch((err) => {
166
+ console.error("[TraceStack] Error during shutdown flush:", err);
167
+ });
168
+ };
169
+ process.on("SIGTERM", syncHandler);
170
+ process.on("SIGINT", syncHandler);
171
+ process.on("beforeExit", syncHandler);
172
+ this.shutdownHandlers.push(async () => {
173
+ process.removeListener("SIGTERM", syncHandler);
174
+ process.removeListener("SIGINT", syncHandler);
175
+ process.removeListener("beforeExit", syncHandler);
176
+ });
177
+ }
178
+ removeShutdownHandlers() {
179
+ for (const remove of this.shutdownHandlers) {
180
+ remove().catch(() => { });
181
+ }
182
+ this.shutdownHandlers.length = 0;
183
+ }
184
+ // ─── Debug Logging ─────────────────────────────────────
185
+ log(message, data) {
186
+ if (this.config.debug) {
187
+ const suffix = data ? ` ${JSON.stringify(data)}` : "";
188
+ console.log(`[TraceStack] ${message}${suffix}`);
189
+ }
190
+ }
191
+ }
192
+ exports.TraceStack = TraceStack;
193
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { TraceStack } from "./client";
2
+ export type { TraceStackConfig, LogLevel, LogEntry, IngestPayload, IngestResponse, TransportResult, } from "./types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ // ─── @trace-stack/node ───────────────────────────────────────
3
+ // Node.js SDK for TraceStack log ingestion.
4
+ //
5
+ // Usage:
6
+ // import { TraceStack } from "@trace-stack/node";
7
+ //
8
+ // const logger = new TraceStack({ apiKey: "ts_live_xxx" });
9
+ // logger.info("Hello world");
10
+ // ──────────────────────────────────────────────────────────────
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TraceStack = void 0;
13
+ var client_1 = require("./client");
14
+ Object.defineProperty(exports, "TraceStack", { enumerable: true, get: function () { return client_1.TraceStack; } });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,gEAAgE;AAChE,4CAA4C;AAC5C,EAAE;AACF,SAAS;AACT,oDAAoD;AACpD,EAAE;AACF,8DAA8D;AAC9D,gCAAgC;AAChC,iEAAiE;;;AAEjE,mCAAsC;AAA7B,oGAAA,UAAU,OAAA"}
@@ -0,0 +1,28 @@
1
+ import type { IngestPayload, TransportResult } from "./types";
2
+ /**
3
+ * HTTP transport layer for the TraceStack SDK.
4
+ * Handles sending log batches to the ingestion API with
5
+ * exponential backoff retry on failures.
6
+ */
7
+ export declare class Transport {
8
+ private readonly endpoint;
9
+ private readonly apiKey;
10
+ private readonly maxRetries;
11
+ private readonly timeout;
12
+ private readonly debug;
13
+ constructor(options: {
14
+ endpoint: string;
15
+ apiKey: string;
16
+ maxRetries?: number;
17
+ timeout?: number;
18
+ debug?: boolean;
19
+ });
20
+ /**
21
+ * Send a batch of logs to the ingestion API.
22
+ * Retries with exponential backoff on transient failures.
23
+ */
24
+ send(payload: IngestPayload): Promise<TransportResult>;
25
+ private sleep;
26
+ private log;
27
+ }
28
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAU9D;;;;GAIG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;gBAEpB,OAAO,EAAE;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;IAQD;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC;IAmG5D,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,GAAG;CAKZ"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Transport = void 0;
4
+ // ─── Constants ───────────────────────────────────────────────
5
+ const DEFAULT_TIMEOUT = 10000; // 10 seconds
6
+ const DEFAULT_MAX_RETRIES = 3;
7
+ const BASE_RETRY_DELAY = 1000; // 1 second
8
+ // ─── Transport ───────────────────────────────────────────────
9
+ /**
10
+ * HTTP transport layer for the TraceStack SDK.
11
+ * Handles sending log batches to the ingestion API with
12
+ * exponential backoff retry on failures.
13
+ */
14
+ class Transport {
15
+ constructor(options) {
16
+ this.endpoint = options.endpoint;
17
+ this.apiKey = options.apiKey;
18
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
19
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
20
+ this.debug = options.debug ?? false;
21
+ }
22
+ /**
23
+ * Send a batch of logs to the ingestion API.
24
+ * Retries with exponential backoff on transient failures.
25
+ */
26
+ async send(payload) {
27
+ const url = `${this.endpoint}/api/v1/logs/ingest`;
28
+ let lastError;
29
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
30
+ try {
31
+ // Wait before retry (skip for first attempt)
32
+ if (attempt > 0) {
33
+ const delay = BASE_RETRY_DELAY * Math.pow(2, attempt - 1);
34
+ this.log(`Retry attempt ${attempt}/${this.maxRetries} after ${delay}ms`);
35
+ await this.sleep(delay);
36
+ }
37
+ const controller = new AbortController();
38
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
39
+ const response = await fetch(url, {
40
+ method: "POST",
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ "x-api-key": this.apiKey,
44
+ },
45
+ body: JSON.stringify(payload),
46
+ signal: controller.signal,
47
+ });
48
+ clearTimeout(timeoutId);
49
+ // Parse response body
50
+ const body = await response.json().catch(() => ({}));
51
+ // Success
52
+ if (response.ok) {
53
+ const data = body.data;
54
+ this.log(`Successfully sent ${payload.logs.length} logs`);
55
+ return {
56
+ success: true,
57
+ statusCode: response.status,
58
+ ingested: data?.ingested ?? payload.logs.length,
59
+ retries: attempt,
60
+ };
61
+ }
62
+ // Rate limited — retry with Retry-After if available
63
+ if (response.status === 429) {
64
+ const retryAfter = response.headers.get("Retry-After");
65
+ if (retryAfter && attempt < this.maxRetries) {
66
+ const waitMs = parseInt(retryAfter, 10) * 1000;
67
+ if (!isNaN(waitMs) && waitMs > 0) {
68
+ this.log(`Rate limited. Waiting ${waitMs}ms (Retry-After header)`);
69
+ await this.sleep(waitMs);
70
+ continue;
71
+ }
72
+ }
73
+ lastError = `Rate limited (429)`;
74
+ continue;
75
+ }
76
+ // Client errors (4xx except 429) — don't retry
77
+ if (response.status >= 400 && response.status < 500) {
78
+ const errorMsg = body.error ?? `HTTP ${response.status}`;
79
+ this.log(`Client error: ${errorMsg} — not retrying`);
80
+ return {
81
+ success: false,
82
+ statusCode: response.status,
83
+ error: errorMsg,
84
+ retries: attempt,
85
+ };
86
+ }
87
+ // Server errors (5xx) — retry
88
+ lastError = `Server error: HTTP ${response.status}`;
89
+ this.log(lastError);
90
+ }
91
+ catch (err) {
92
+ // Network error or timeout — retry
93
+ if (err instanceof Error) {
94
+ if (err.name === "AbortError") {
95
+ lastError = `Request timeout after ${this.timeout}ms`;
96
+ }
97
+ else {
98
+ lastError = `Network error: ${err.message}`;
99
+ }
100
+ }
101
+ else {
102
+ lastError = "Unknown transport error";
103
+ }
104
+ this.log(lastError);
105
+ }
106
+ }
107
+ // All retries exhausted
108
+ this.log(`All ${this.maxRetries} retries exhausted. Dropping ${payload.logs.length} logs.`);
109
+ return {
110
+ success: false,
111
+ error: lastError ?? "Max retries exhausted",
112
+ retries: this.maxRetries,
113
+ };
114
+ }
115
+ // ─── Helpers ─────────────────────────────────────────────
116
+ sleep(ms) {
117
+ return new Promise((resolve) => setTimeout(resolve, ms));
118
+ }
119
+ log(message) {
120
+ if (this.debug) {
121
+ console.log(`[TraceStack] ${message}`);
122
+ }
123
+ }
124
+ }
125
+ exports.Transport = Transport;
126
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Configuration for the TraceStack SDK client.
3
+ */
4
+ export interface TraceStackConfig {
5
+ /**
6
+ * Your TraceStack API key.
7
+ * Must start with "ts_" (e.g., "ts_live_abc123...").
8
+ */
9
+ apiKey: string;
10
+ /**
11
+ * Service name attached to every log entry.
12
+ * Identifies which service/app is sending logs.
13
+ * @example "payment-service", "api-gateway"
14
+ */
15
+ serviceName?: string;
16
+ /**
17
+ * TraceStack ingestion API endpoint.
18
+ * @default "http://localhost:5000"
19
+ */
20
+ endpoint?: string;
21
+ /**
22
+ * Number of logs to buffer before auto-flushing.
23
+ * @default 50
24
+ */
25
+ batchSize?: number;
26
+ /**
27
+ * Interval (ms) between automatic flushes of the buffer.
28
+ * @default 5000
29
+ */
30
+ flushInterval?: number;
31
+ /**
32
+ * Maximum number of retry attempts for failed HTTP requests.
33
+ * Uses exponential backoff: 1s, 2s, 4s, ...
34
+ * @default 3
35
+ */
36
+ maxRetries?: number;
37
+ /**
38
+ * HTTP request timeout in milliseconds.
39
+ * @default 10000
40
+ */
41
+ timeout?: number;
42
+ /**
43
+ * Enable debug logging to console.
44
+ * Useful during development to see SDK internals.
45
+ * @default false
46
+ */
47
+ debug?: boolean;
48
+ }
49
+ /**
50
+ * Supported log severity levels, ordered by severity.
51
+ */
52
+ export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal";
53
+ /**
54
+ * A single log entry to be sent to TraceStack.
55
+ */
56
+ export interface LogEntry {
57
+ /** Log severity level */
58
+ level: LogLevel;
59
+ /** Human-readable log message */
60
+ message: string;
61
+ /** ISO 8601 timestamp */
62
+ timestamp: string;
63
+ /** Service name that generated the log */
64
+ serviceName: string;
65
+ /** Optional source identifier (file, module, function) */
66
+ source?: string;
67
+ /** Optional structured metadata */
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+ /**
71
+ * Payload sent to the ingestion API.
72
+ */
73
+ export interface IngestPayload {
74
+ logs: LogEntry[];
75
+ }
76
+ /**
77
+ * Response from the ingestion API.
78
+ */
79
+ export interface IngestResponse {
80
+ success: boolean;
81
+ data?: {
82
+ ingested: number;
83
+ };
84
+ error?: string;
85
+ }
86
+ /**
87
+ * Result of a transport send operation.
88
+ */
89
+ export interface TransportResult {
90
+ success: boolean;
91
+ statusCode?: number;
92
+ ingested?: number;
93
+ error?: string;
94
+ retries: number;
95
+ }
96
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,yBAAyB;IACzB,KAAK,EAAE,QAAQ,CAAC;IAEhB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAEhB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAElB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IAEpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAID;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // ─── SDK Configuration ───────────────────────────────────────
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gEAAgE"}
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@trace-stack/node",
3
+ "version": "1.0.0",
4
+ "description": "Node.js SDK for TraceStack — log ingestion with batching, retries, and graceful shutdown",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "typecheck": "tsc --noEmit"
13
+ },
14
+ "keywords": [
15
+ "tracestack",
16
+ "logging",
17
+ "observability",
18
+ "sdk",
19
+ "monitoring"
20
+ ],
21
+ "license": "MIT",
22
+ "devDependencies": {},
23
+ "dependencies": {
24
+ "typescript": "^5.9.3"
25
+ }
26
+ }