@logtide/sdk-node 0.1.1 → 0.2.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 CHANGED
@@ -1,21 +1,36 @@
1
- # LogTide Node.js SDK
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/logtide-dev/logtide/main/docs/images/logo.png" alt="LogTide Logo" width="400">
3
+ </p>
2
4
 
3
- Official Node.js SDK for LogTide with advanced features: retry logic, circuit breaker, query API, live streaming, and middleware support.
5
+ <h1 align="center">LogTide Node.js SDK</h1>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@logtide/sdk-node"><img src="https://img.shields.io/npm/v/@logtide/sdk-node?color=blue" alt="npm"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"></a>
10
+ <a href="https://nodejs.org/"><img src="https://img.shields.io/badge/Node.js-18+-green.svg" alt="Node.js"></a>
11
+ <a href="https://github.com/logtide-dev/logtide-sdk-node/releases"><img src="https://img.shields.io/github/v/release/logtide-dev/logtide-sdk-node" alt="Release"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ Official Node.js SDK for <a href="https://logtide.dev">LogTide</a> with automatic batching, retry logic, circuit breaker, query API, live streaming, and middleware support.
16
+ </p>
17
+
18
+ ---
4
19
 
5
20
  ## Features
6
21
 
7
- - **Automatic batching** with configurable size and interval
8
- - **Retry logic** with exponential backoff
9
- - **Circuit breaker** pattern for fault tolerance
10
- - **Max buffer size** with drop policy to prevent memory leaks
11
- - **Query API** for searching and filtering logs
12
- - **Live tail** with Server-Sent Events (SSE)
13
- - **Trace ID context** for distributed tracing
14
- - **Global metadata** added to all logs
15
- - **Structured error serialization**
16
- - **Internal metrics** (logs sent, errors, latency, etc.)
17
- - **Express & Fastify middleware** for auto-logging HTTP requests
18
- - **Full TypeScript support** with strict types
22
+ - **Automatic batching** with configurable size and interval
23
+ - **Retry logic** with exponential backoff
24
+ - **Circuit breaker** pattern for fault tolerance
25
+ - **Max buffer size** with drop policy to prevent memory leaks
26
+ - **Query API** for searching and filtering logs
27
+ - **Live tail** with Server-Sent Events (SSE)
28
+ - **Trace ID context** for distributed tracing
29
+ - **Global metadata** added to all logs
30
+ - **Structured error serialization**
31
+ - **Internal metrics** (logs sent, errors, latency, etc.)
32
+ - **Express & Fastify middleware** for auto-logging HTTP requests
33
+ - **Full TypeScript support** with strict types
19
34
 
20
35
  ## Installation
21
36
 
@@ -89,7 +104,7 @@ const client = new LogTideClient({
89
104
  // Buffer management
90
105
  maxBufferSize: 10000,
91
106
 
92
- // Retry with exponential backoff (1s 2s 4s)
107
+ // Retry with exponential backoff (1s -> 2s -> 4s)
93
108
  maxRetries: 3,
94
109
  retryDelayMs: 1000,
95
110
 
@@ -158,9 +173,9 @@ client.log({
158
173
  service: 'custom-service',
159
174
  level: 'info',
160
175
  message: 'Custom log',
161
- time: new Date().toISOString(), // Optional
176
+ time: new Date().toISOString(),
162
177
  metadata: { key: 'value' },
163
- trace_id: 'custom-trace-id', // Optional
178
+ trace_id: 'custom-trace-id',
164
179
  });
165
180
  ```
166
181
 
@@ -201,16 +216,6 @@ client.withNewTraceId(() => {
201
216
  });
202
217
  ```
203
218
 
204
- ### Auto Trace ID Mode
205
-
206
- ```typescript
207
- const client = new LogTideClient({
208
- apiUrl: 'http://localhost:8080',
209
- apiKey: 'lp_your_api_key_here',
210
- autoTraceId: true, // Every log gets a unique trace ID
211
- });
212
- ```
213
-
214
219
  ---
215
220
 
216
221
  ## Query API
@@ -315,7 +320,9 @@ client.resetMetrics();
315
320
 
316
321
  ---
317
322
 
318
- ## Middleware
323
+ ## Middleware Integration
324
+
325
+ LogTide provides ready-to-use middleware for popular frameworks.
319
326
 
320
327
  ### Express Middleware
321
328
 
@@ -385,6 +392,17 @@ await fastify.listen({ port: 3000 });
385
392
 
386
393
  ---
387
394
 
395
+ ## Examples
396
+
397
+ See the [examples/](./examples) directory for complete working examples:
398
+
399
+ - **[basic.ts](./examples/basic.ts)** - Simple usage
400
+ - **[advanced.ts](./examples/advanced.ts)** - All advanced features
401
+ - **[express-middleware.ts](./examples/express-middleware.ts)** - Express integration
402
+ - **[fastify-plugin.ts](./examples/fastify-plugin.ts)** - Fastify integration
403
+
404
+ ---
405
+
388
406
  ## Best Practices
389
407
 
390
408
  ### 1. Always Close on Shutdown
@@ -442,72 +460,6 @@ setInterval(() => {
442
460
  }, 60000);
443
461
  ```
444
462
 
445
- ### 5. Use Trace IDs for Request Correlation
446
-
447
- ```typescript
448
- app.use((req, res, next) => {
449
- const traceId = req.headers['x-trace-id'] || randomUUID();
450
- req.traceId = traceId;
451
-
452
- client.withTraceId(traceId, () => {
453
- next();
454
- });
455
- });
456
- ```
457
-
458
- ---
459
-
460
- ## API Reference
461
-
462
- ### LogTideClient
463
-
464
- #### Constructor
465
- ```typescript
466
- new LogTideClient(options: LogTideClientOptions)
467
- ```
468
-
469
- #### Logging Methods
470
- - `log(entry: LogEntry): void`
471
- - `debug(service: string, message: string, metadata?: object): void`
472
- - `info(service: string, message: string, metadata?: object): void`
473
- - `warn(service: string, message: string, metadata?: object): void`
474
- - `error(service: string, message: string, metadataOrError?: object | Error): void`
475
- - `critical(service: string, message: string, metadataOrError?: object | Error): void`
476
-
477
- #### Context Methods
478
- - `setTraceId(traceId: string | null): void`
479
- - `getTraceId(): string | null`
480
- - `withTraceId<T>(traceId: string, fn: () => T): T`
481
- - `withNewTraceId<T>(fn: () => T): T`
482
-
483
- #### Query Methods
484
- - `query(options: QueryOptions): Promise<LogsResponse>`
485
- - `getByTraceId(traceId: string): Promise<InternalLogEntry[]>`
486
- - `getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse>`
487
-
488
- #### Streaming
489
- - `stream(options: StreamOptions): () => void` (returns cleanup function)
490
-
491
- #### Metrics
492
- - `getMetrics(): ClientMetrics`
493
- - `resetMetrics(): void`
494
- - `getCircuitBreakerState(): string`
495
-
496
- #### Lifecycle
497
- - `flush(): Promise<void>`
498
- - `close(): Promise<void>`
499
-
500
- ---
501
-
502
- ## Examples
503
-
504
- See the [examples/](./examples) directory for complete working examples:
505
-
506
- - **[basic.ts](./examples/basic.ts)** - Simple usage
507
- - **[advanced.ts](./examples/advanced.ts)** - All advanced features
508
- - **[express-middleware.ts](./examples/express-middleware.ts)** - Express integration
509
- - **[fastify-plugin.ts](./examples/fastify-plugin.ts)** - Fastify integration
510
-
511
463
  ---
512
464
 
513
465
  ## TypeScript Support
@@ -526,36 +478,16 @@ import type {
526
478
 
527
479
  ---
528
480
 
529
- ## Testing
530
-
531
- Run the test suite:
532
-
533
- ```bash
534
- # Run tests
535
- pnpm test
536
-
537
- # Watch mode
538
- pnpm test:watch
539
-
540
- # Coverage
541
- pnpm test:coverage
542
- ```
481
+ ## Contributing
543
482
 
544
- ---
483
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
545
484
 
546
485
  ## License
547
486
 
548
- MIT
549
-
550
- ---
551
-
552
- ## Contributing
553
-
554
- Contributions are welcome! Please open an issue or PR on [GitHub](https://github.com/logtide-dev/logtide-sdk-node).
555
-
556
- ---
487
+ MIT License - see [LICENSE](LICENSE) for details.
557
488
 
558
- ## Support
489
+ ## Links
559
490
 
560
- - **Documentation**: [https://logtide.dev/docs](https://logtide.dev/docs)
561
- - **Issues**: [GitHub Issues](https://github.com/logtide-dev/logtide-sdk-node/issues)
491
+ - [LogTide Website](https://logtide.dev)
492
+ - [Documentation](https://logtide.dev/docs/sdks/node/)
493
+ - [GitHub Issues](https://github.com/logtide-dev/logtide-sdk-node/issues)
package/dist/index.cjs CHANGED
@@ -42,25 +42,6 @@ var CircuitBreaker = class {
42
42
  return this.state;
43
43
  }
44
44
  };
45
- function isValidUUID(str) {
46
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
47
- return uuidRegex.test(str);
48
- }
49
- function normalizeTraceId(traceId, debug) {
50
- if (!traceId) {
51
- return void 0;
52
- }
53
- if (isValidUUID(traceId)) {
54
- return traceId;
55
- }
56
- const newTraceId = crypto.randomUUID();
57
- if (debug) {
58
- console.warn(
59
- `[LogTide] Invalid trace_id "${traceId}" (must be UUID v4). Generated new UUID: ${newTraceId}`
60
- );
61
- }
62
- return newTraceId;
63
- }
64
45
  function serializeError(error) {
65
46
  if (error instanceof Error) {
66
47
  const result = {
@@ -108,6 +89,9 @@ var LogTideClient = class {
108
89
  latencies = [];
109
90
  // Context tracking
110
91
  currentTraceId = null;
92
+ // Console interception
93
+ consoleInterceptOptions = null;
94
+ originalConsole = null;
111
95
  constructor(options) {
112
96
  this.apiUrl = options.apiUrl.replace(/\/$/, "");
113
97
  this.apiKey = options.apiKey;
@@ -125,14 +109,16 @@ var LogTideClient = class {
125
109
  options.circuitBreakerResetMs || 3e4
126
110
  );
127
111
  this.startFlushTimer();
112
+ if (options.interceptConsole?.enabled) {
113
+ this.startConsoleInterception(options.interceptConsole);
114
+ }
128
115
  }
129
116
  // ==================== Context Helpers ====================
130
117
  /**
131
118
  * Set trace ID for subsequent logs
132
- * Automatically validates and normalizes to UUID v4
133
119
  */
134
120
  setTraceId(traceId) {
135
- this.currentTraceId = normalizeTraceId(traceId, this.debugMode) || null;
121
+ this.currentTraceId = traceId;
136
122
  }
137
123
  /**
138
124
  * Get current trace ID
@@ -158,6 +144,137 @@ var LogTideClient = class {
158
144
  withNewTraceId(fn) {
159
145
  return this.withTraceId(crypto.randomUUID(), fn);
160
146
  }
147
+ // ==================== Console Interception ====================
148
+ /**
149
+ * Start intercepting console methods and forward them to LogTide
150
+ */
151
+ startConsoleInterception(options) {
152
+ if (this.originalConsole) {
153
+ return;
154
+ }
155
+ const config = {
156
+ enabled: true,
157
+ service: options?.service ?? "console",
158
+ preserveOriginal: options?.preserveOriginal ?? true,
159
+ includeStackTrace: options?.includeStackTrace ?? false,
160
+ levels: {
161
+ log: options?.levels?.log ?? true,
162
+ info: options?.levels?.info ?? true,
163
+ warn: options?.levels?.warn ?? true,
164
+ error: options?.levels?.error ?? true,
165
+ debug: options?.levels?.debug ?? true
166
+ }
167
+ };
168
+ this.consoleInterceptOptions = config;
169
+ this.originalConsole = {
170
+ log: console.log.bind(console),
171
+ info: console.info.bind(console),
172
+ warn: console.warn.bind(console),
173
+ error: console.error.bind(console),
174
+ debug: console.debug.bind(console)
175
+ };
176
+ const createInterceptor = (method, level) => {
177
+ const original = this.originalConsole[method];
178
+ return (...args) => {
179
+ if (config.preserveOriginal) {
180
+ original(...args);
181
+ }
182
+ if (!config.levels?.[method]) {
183
+ return;
184
+ }
185
+ const message = args.map((arg) => {
186
+ if (typeof arg === "string") return arg;
187
+ if (arg instanceof Error) return arg.message;
188
+ try {
189
+ return JSON.stringify(arg);
190
+ } catch {
191
+ return String(arg);
192
+ }
193
+ }).join(" ");
194
+ if (message.startsWith("[LogTide]")) {
195
+ return;
196
+ }
197
+ const metadata = {
198
+ source: "console",
199
+ originalMethod: method
200
+ };
201
+ if (config.includeStackTrace) {
202
+ const stack = new Error().stack;
203
+ if (stack) {
204
+ const stackLines = stack.split("\n").slice(2);
205
+ metadata.stackTrace = stackLines.join("\n");
206
+ const callerLine = stackLines[0];
207
+ if (callerLine) {
208
+ const match = callerLine.match(/at\s+(.+?)\s+\((.+):(\d+):(\d+)\)/);
209
+ if (match) {
210
+ metadata.caller = {
211
+ function: match[1],
212
+ file: match[2],
213
+ line: parseInt(match[3], 10),
214
+ column: parseInt(match[4], 10)
215
+ };
216
+ } else {
217
+ const altMatch = callerLine.match(/at\s+(.+):(\d+):(\d+)/);
218
+ if (altMatch) {
219
+ metadata.caller = {
220
+ file: altMatch[1],
221
+ line: parseInt(altMatch[2], 10),
222
+ column: parseInt(altMatch[3], 10)
223
+ };
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ if (args.length > 1 || args.length === 1 && typeof args[0] !== "string") {
230
+ metadata.args = args.map((arg) => {
231
+ if (arg instanceof Error) {
232
+ return serializeError(arg);
233
+ }
234
+ return arg;
235
+ });
236
+ }
237
+ this.log({
238
+ service: config.service,
239
+ level,
240
+ message,
241
+ metadata
242
+ });
243
+ };
244
+ };
245
+ console.log = createInterceptor("log", "info");
246
+ console.info = createInterceptor("info", "info");
247
+ console.warn = createInterceptor("warn", "warn");
248
+ console.error = createInterceptor("error", "error");
249
+ console.debug = createInterceptor("debug", "debug");
250
+ if (this.debugMode) {
251
+ this.originalConsole.log("[LogTide] Console interception started");
252
+ }
253
+ }
254
+ /**
255
+ * Stop intercepting console methods and restore originals
256
+ */
257
+ stopConsoleInterception() {
258
+ if (!this.originalConsole) {
259
+ return;
260
+ }
261
+ console.log = this.originalConsole.log;
262
+ console.info = this.originalConsole.info;
263
+ console.warn = this.originalConsole.warn;
264
+ console.error = this.originalConsole.error;
265
+ console.debug = this.originalConsole.debug;
266
+ if (this.debugMode) {
267
+ console.log("[LogTide] Console interception stopped");
268
+ }
269
+ this.originalConsole = null;
270
+ this.consoleInterceptOptions = null;
271
+ }
272
+ /**
273
+ * Check if console interception is active
274
+ */
275
+ isConsoleInterceptionActive() {
276
+ return this.originalConsole !== null;
277
+ }
161
278
  // ==================== Logging Methods ====================
162
279
  startFlushTimer() {
163
280
  this.timer = setInterval(() => {
@@ -172,7 +289,7 @@ var LogTideClient = class {
172
289
  }
173
290
  return;
174
291
  }
175
- const normalizedTraceId = normalizeTraceId(entry.trace_id, this.debugMode) || normalizeTraceId(this.currentTraceId, this.debugMode) || (this.autoTraceId ? crypto.randomUUID() : void 0);
292
+ const traceId = entry.trace_id || this.currentTraceId || (this.autoTraceId ? crypto.randomUUID() : void 0);
176
293
  const internalEntry = {
177
294
  ...entry,
178
295
  time: entry.time || (/* @__PURE__ */ new Date()).toISOString(),
@@ -180,7 +297,7 @@ var LogTideClient = class {
180
297
  ...this.globalMetadata,
181
298
  ...entry.metadata
182
299
  },
183
- trace_id: normalizedTraceId
300
+ trace_id: traceId
184
301
  };
185
302
  this.buffer.push(internalEntry);
186
303
  if (this.buffer.length >= this.batchSize) {
@@ -396,6 +513,7 @@ var LogTideClient = class {
396
513
  clearInterval(this.timer);
397
514
  this.timer = null;
398
515
  }
516
+ this.stopConsoleInterception();
399
517
  await this.flush();
400
518
  }
401
519
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["import { randomUUID } from 'crypto';\n\n// ==================== Types ====================\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface LogTideClientOptions {\n apiUrl: string;\n apiKey: string;\n batchSize?: number;\n flushInterval?: number;\n maxBufferSize?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n circuitBreakerThreshold?: number;\n circuitBreakerResetMs?: number;\n enableMetrics?: boolean;\n debug?: boolean;\n globalMetadata?: Record<string, unknown>;\n autoTraceId?: boolean;\n}\n\nexport interface LogEntry {\n service: string;\n level: LogLevel;\n message: string;\n time?: string;\n metadata?: Record<string, unknown>;\n trace_id?: string;\n}\n\nexport interface InternalLogEntry extends LogEntry {\n time: string;\n}\n\nexport interface QueryOptions {\n service?: string;\n level?: LogLevel;\n from?: Date | string;\n to?: Date | string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface LogsResponse {\n logs: InternalLogEntry[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface AggregatedStatsOptions {\n from: Date | string;\n to: Date | string;\n interval?: '1m' | '5m' | '1h' | '1d';\n service?: string;\n}\n\nexport interface AggregatedStatsResponse {\n timeseries: Array<{\n bucket: string;\n total: number;\n by_level: Record<string, number>;\n }>;\n top_services: Array<{ service: string; count: number }>;\n top_errors: Array<{ message: string; count: number }>;\n}\n\nexport interface ClientMetrics {\n logsSent: number;\n logsDropped: number;\n errors: number;\n retries: number;\n avgLatencyMs: number;\n circuitBreakerTrips: number;\n}\n\nexport interface StreamOptions {\n service?: string;\n level?: LogLevel;\n onLog: (log: InternalLogEntry) => void;\n onError?: (error: Error) => void;\n}\n\n// ==================== Circuit Breaker ====================\n\nenum CircuitState {\n CLOSED = 'CLOSED',\n OPEN = 'OPEN',\n HALF_OPEN = 'HALF_OPEN',\n}\n\nclass CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failureCount = 0;\n private lastFailureTime: number | null = null;\n\n constructor(\n private threshold: number,\n private resetMs: number,\n ) {}\n\n recordSuccess() {\n this.failureCount = 0;\n this.state = CircuitState.CLOSED;\n }\n\n recordFailure() {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.threshold) {\n this.state = CircuitState.OPEN;\n }\n }\n\n canAttempt(): boolean {\n if (this.state === CircuitState.CLOSED) {\n return true;\n }\n\n if (this.state === CircuitState.OPEN) {\n const now = Date.now();\n if (this.lastFailureTime && now - this.lastFailureTime >= this.resetMs) {\n this.state = CircuitState.HALF_OPEN;\n return true;\n }\n return false;\n }\n\n // HALF_OPEN state - allow one attempt\n return true;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n\n// ==================== UUID Validation ====================\n\n/**\n * Validates if a string is a valid UUID (v4)\n */\nfunction isValidUUID(str: string): boolean {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return uuidRegex.test(str);\n}\n\n/**\n * Normalizes a trace_id to ensure it's a valid UUID.\n * If invalid, generates a new UUID and warns in debug mode.\n */\nfunction normalizeTraceId(traceId: string | null | undefined, debug: boolean): string | undefined {\n if (!traceId) {\n return undefined;\n }\n\n if (isValidUUID(traceId)) {\n return traceId;\n }\n\n // Invalid UUID - generate a new one\n const newTraceId = randomUUID();\n if (debug) {\n console.warn(\n `[LogTide] Invalid trace_id \"${traceId}\" (must be UUID v4). Generated new UUID: ${newTraceId}`,\n );\n }\n return newTraceId;\n}\n\n// ==================== Error Serialization ====================\n\nexport function serializeError(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n const result: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n\n if (error.cause) {\n result.cause = serializeError(error.cause);\n }\n\n return result;\n }\n\n if (typeof error === 'string') {\n return { message: error };\n }\n\n if (typeof error === 'object' && error !== null) {\n return error as Record<string, unknown>;\n }\n\n return { message: String(error) };\n}\n\n// ==================== Main Client ====================\n\nexport class LogTideClient {\n private apiUrl: string;\n private apiKey: string;\n private batchSize: number;\n private flushInterval: number;\n private maxBufferSize: number;\n private maxRetries: number;\n private retryDelayMs: number;\n private enableMetrics: boolean;\n private debugMode: boolean;\n private globalMetadata: Record<string, unknown>;\n private autoTraceId: boolean;\n\n private buffer: InternalLogEntry[] = [];\n private timer: NodeJS.Timeout | null = null;\n private circuitBreaker: CircuitBreaker;\n\n // Metrics\n private metrics: ClientMetrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n private latencies: number[] = [];\n\n // Context tracking\n private currentTraceId: string | null = null;\n\n constructor(options: LogTideClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 5000;\n this.maxBufferSize = options.maxBufferSize || 10000;\n this.maxRetries = options.maxRetries || 3;\n this.retryDelayMs = options.retryDelayMs || 1000;\n this.enableMetrics = options.enableMetrics ?? true;\n this.debugMode = options.debug ?? false;\n this.globalMetadata = options.globalMetadata || {};\n this.autoTraceId = options.autoTraceId ?? false;\n\n this.circuitBreaker = new CircuitBreaker(\n options.circuitBreakerThreshold || 5,\n options.circuitBreakerResetMs || 30000,\n );\n\n this.startFlushTimer();\n }\n\n // ==================== Context Helpers ====================\n\n /**\n * Set trace ID for subsequent logs\n * Automatically validates and normalizes to UUID v4\n */\n setTraceId(traceId: string | null) {\n this.currentTraceId = normalizeTraceId(traceId, this.debugMode) || null;\n }\n\n /**\n * Get current trace ID\n */\n getTraceId(): string | null {\n return this.currentTraceId;\n }\n\n /**\n * Execute function with a specific trace ID context\n */\n withTraceId<T>(traceId: string, fn: () => T): T {\n const previousTraceId = this.currentTraceId;\n this.currentTraceId = traceId;\n try {\n return fn();\n } finally {\n this.currentTraceId = previousTraceId;\n }\n }\n\n /**\n * Execute function with a new auto-generated trace ID\n */\n withNewTraceId<T>(fn: () => T): T {\n return this.withTraceId(randomUUID(), fn);\n }\n\n // ==================== Logging Methods ====================\n\n private startFlushTimer() {\n this.timer = setInterval(() => {\n this.flush();\n }, this.flushInterval);\n }\n\n log(entry: LogEntry) {\n // Check buffer size limit\n if (this.buffer.length >= this.maxBufferSize) {\n this.metrics.logsDropped++;\n if (this.debugMode) {\n console.warn(`[LogTide] Buffer full, dropping log: ${entry.message}`);\n }\n return;\n }\n\n // Normalize trace_id to ensure it's a valid UUID\n const normalizedTraceId =\n normalizeTraceId(entry.trace_id, this.debugMode) ||\n normalizeTraceId(this.currentTraceId, this.debugMode) ||\n (this.autoTraceId ? randomUUID() : undefined);\n\n const internalEntry: InternalLogEntry = {\n ...entry,\n time: entry.time || new Date().toISOString(),\n metadata: {\n ...this.globalMetadata,\n ...entry.metadata,\n },\n trace_id: normalizedTraceId,\n };\n\n this.buffer.push(internalEntry);\n\n if (this.buffer.length >= this.batchSize) {\n this.flush();\n }\n }\n\n debug(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'debug', message, metadata });\n }\n\n info(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'info', message, metadata });\n }\n\n warn(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'warn', message, metadata });\n }\n\n error(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'error', message, metadata });\n }\n\n critical(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'critical', message, metadata });\n }\n\n // ==================== Flush with Retry & Circuit Breaker ====================\n\n async flush() {\n if (this.buffer.length === 0) return;\n\n // Check circuit breaker\n if (!this.circuitBreaker.canAttempt()) {\n this.metrics.circuitBreakerTrips++;\n if (this.debugMode) {\n console.warn('[LogTide] Circuit breaker OPEN, skipping flush');\n }\n return;\n }\n\n const logs = [...this.buffer];\n this.buffer = [];\n\n const startTime = Date.now();\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n },\n body: JSON.stringify({ logs }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n // Success\n this.circuitBreaker.recordSuccess();\n this.metrics.logsSent += logs.length;\n\n if (this.enableMetrics) {\n const latency = Date.now() - startTime;\n this.latencies.push(latency);\n if (this.latencies.length > 100) {\n this.latencies.shift();\n }\n this.metrics.avgLatencyMs =\n this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;\n }\n\n if (this.debugMode) {\n console.log(`[LogTide] Sent ${logs.length} logs successfully`);\n }\n\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n this.metrics.errors++;\n\n if (attempt < this.maxRetries) {\n this.metrics.retries++;\n const delay = this.retryDelayMs * Math.pow(2, attempt);\n if (this.debugMode) {\n console.warn(\n `[LogTide] Retry ${attempt + 1}/${this.maxRetries} after ${delay}ms: ${lastError.message}`,\n );\n }\n await this.sleep(delay);\n }\n }\n }\n\n // All retries failed\n this.circuitBreaker.recordFailure();\n\n if (this.debugMode) {\n console.error(`[LogTide] Failed to send logs after ${this.maxRetries} retries:`, lastError);\n }\n\n // Re-add logs to buffer if not full\n if (this.buffer.length + logs.length <= this.maxBufferSize) {\n this.buffer.unshift(...logs);\n } else {\n this.metrics.logsDropped += logs.length;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ==================== Query Methods ====================\n\n async query(options: QueryOptions = {}): Promise<LogsResponse> {\n const params = new URLSearchParams();\n\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n if (options.from) {\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n params.append('from', from);\n }\n if (options.to) {\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n params.append('to', to);\n }\n if (options.q) params.append('q', options.q);\n if (options.limit) params.append('limit', String(options.limit));\n if (options.offset) params.append('offset', String(options.offset));\n\n const url = `${this.apiUrl}/api/v1/logs?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Query failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as LogsResponse;\n }\n\n async getByTraceId(traceId: string): Promise<InternalLogEntry[]> {\n const url = `${this.apiUrl}/api/v1/logs/trace/${traceId}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get by trace ID failed: HTTP ${response.status}: ${errorText}`);\n }\n\n const data = (await response.json()) as { logs?: InternalLogEntry[] };\n return data.logs || [];\n }\n\n async getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse> {\n const params = new URLSearchParams();\n\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n\n params.append('from', from);\n params.append('to', to);\n if (options.interval) params.append('interval', options.interval);\n if (options.service) params.append('service', options.service);\n\n const url = `${this.apiUrl}/api/v1/logs/aggregated?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get aggregated stats failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as AggregatedStatsResponse;\n }\n\n // ==================== Live Tail (SSE) ====================\n\n stream(options: StreamOptions): () => void {\n const params = new URLSearchParams();\n params.append('token', this.apiKey);\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n\n const url = `${this.apiUrl}/api/v1/logs/stream?${params.toString()}`;\n\n const eventSource = new EventSource(url);\n\n eventSource.addEventListener('log', (event: Event) => {\n try {\n const messageEvent = event as MessageEvent;\n const log = JSON.parse(messageEvent.data) as InternalLogEntry;\n options.onLog(log);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n options.onError?.(err);\n }\n });\n\n eventSource.addEventListener('error', () => {\n const error = new Error('SSE connection error');\n options.onError?.(error);\n });\n\n // Return cleanup function\n return () => {\n eventSource.close();\n };\n }\n\n // ==================== Metrics ====================\n\n getMetrics(): ClientMetrics {\n return { ...this.metrics };\n }\n\n resetMetrics() {\n this.metrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n this.latencies = [];\n }\n\n getCircuitBreakerState(): string {\n return this.circuitBreaker.getState();\n }\n\n // ==================== Cleanup ====================\n\n async close() {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n\nexport default LogTideClient;\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["import { randomUUID } from 'crypto';\n\n// ==================== Types ====================\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface ConsoleInterceptOptions {\n enabled: boolean;\n service?: string;\n preserveOriginal?: boolean;\n includeStackTrace?: boolean;\n levels?: {\n log?: boolean;\n info?: boolean;\n warn?: boolean;\n error?: boolean;\n debug?: boolean;\n };\n}\n\nexport interface LogTideClientOptions {\n apiUrl: string;\n apiKey: string;\n batchSize?: number;\n flushInterval?: number;\n maxBufferSize?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n circuitBreakerThreshold?: number;\n circuitBreakerResetMs?: number;\n enableMetrics?: boolean;\n debug?: boolean;\n globalMetadata?: Record<string, unknown>;\n autoTraceId?: boolean;\n interceptConsole?: ConsoleInterceptOptions;\n}\n\nexport interface LogEntry {\n service: string;\n level: LogLevel;\n message: string;\n time?: string;\n metadata?: Record<string, unknown>;\n trace_id?: string;\n}\n\nexport interface InternalLogEntry extends LogEntry {\n time: string;\n}\n\nexport interface QueryOptions {\n service?: string;\n level?: LogLevel;\n from?: Date | string;\n to?: Date | string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface LogsResponse {\n logs: InternalLogEntry[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface AggregatedStatsOptions {\n from: Date | string;\n to: Date | string;\n interval?: '1m' | '5m' | '1h' | '1d';\n service?: string;\n}\n\nexport interface AggregatedStatsResponse {\n timeseries: Array<{\n bucket: string;\n total: number;\n by_level: Record<string, number>;\n }>;\n top_services: Array<{ service: string; count: number }>;\n top_errors: Array<{ message: string; count: number }>;\n}\n\nexport interface ClientMetrics {\n logsSent: number;\n logsDropped: number;\n errors: number;\n retries: number;\n avgLatencyMs: number;\n circuitBreakerTrips: number;\n}\n\nexport interface StreamOptions {\n service?: string;\n level?: LogLevel;\n onLog: (log: InternalLogEntry) => void;\n onError?: (error: Error) => void;\n}\n\n// ==================== Circuit Breaker ====================\n\nenum CircuitState {\n CLOSED = 'CLOSED',\n OPEN = 'OPEN',\n HALF_OPEN = 'HALF_OPEN',\n}\n\nclass CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failureCount = 0;\n private lastFailureTime: number | null = null;\n\n constructor(\n private threshold: number,\n private resetMs: number,\n ) {}\n\n recordSuccess() {\n this.failureCount = 0;\n this.state = CircuitState.CLOSED;\n }\n\n recordFailure() {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.threshold) {\n this.state = CircuitState.OPEN;\n }\n }\n\n canAttempt(): boolean {\n if (this.state === CircuitState.CLOSED) {\n return true;\n }\n\n if (this.state === CircuitState.OPEN) {\n const now = Date.now();\n if (this.lastFailureTime && now - this.lastFailureTime >= this.resetMs) {\n this.state = CircuitState.HALF_OPEN;\n return true;\n }\n return false;\n }\n\n // HALF_OPEN state - allow one attempt\n return true;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n\n\n// ==================== Error Serialization ====================\n\nexport function serializeError(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n const result: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n\n if (error.cause) {\n result.cause = serializeError(error.cause);\n }\n\n return result;\n }\n\n if (typeof error === 'string') {\n return { message: error };\n }\n\n if (typeof error === 'object' && error !== null) {\n return error as Record<string, unknown>;\n }\n\n return { message: String(error) };\n}\n\n// ==================== Main Client ====================\n\nexport class LogTideClient {\n private apiUrl: string;\n private apiKey: string;\n private batchSize: number;\n private flushInterval: number;\n private maxBufferSize: number;\n private maxRetries: number;\n private retryDelayMs: number;\n private enableMetrics: boolean;\n private debugMode: boolean;\n private globalMetadata: Record<string, unknown>;\n private autoTraceId: boolean;\n\n private buffer: InternalLogEntry[] = [];\n private timer: NodeJS.Timeout | null = null;\n private circuitBreaker: CircuitBreaker;\n\n // Metrics\n private metrics: ClientMetrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n private latencies: number[] = [];\n\n // Context tracking\n private currentTraceId: string | null = null;\n\n // Console interception\n private consoleInterceptOptions: ConsoleInterceptOptions | null = null;\n private originalConsole: {\n log: typeof console.log;\n info: typeof console.info;\n warn: typeof console.warn;\n error: typeof console.error;\n debug: typeof console.debug;\n } | null = null;\n\n constructor(options: LogTideClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 5000;\n this.maxBufferSize = options.maxBufferSize || 10000;\n this.maxRetries = options.maxRetries || 3;\n this.retryDelayMs = options.retryDelayMs || 1000;\n this.enableMetrics = options.enableMetrics ?? true;\n this.debugMode = options.debug ?? false;\n this.globalMetadata = options.globalMetadata || {};\n this.autoTraceId = options.autoTraceId ?? false;\n\n this.circuitBreaker = new CircuitBreaker(\n options.circuitBreakerThreshold || 5,\n options.circuitBreakerResetMs || 30000,\n );\n\n this.startFlushTimer();\n\n // Start console interception if configured\n if (options.interceptConsole?.enabled) {\n this.startConsoleInterception(options.interceptConsole);\n }\n }\n\n // ==================== Context Helpers ====================\n\n /**\n * Set trace ID for subsequent logs\n */\n setTraceId(traceId: string | null) {\n this.currentTraceId = traceId;\n }\n\n /**\n * Get current trace ID\n */\n getTraceId(): string | null {\n return this.currentTraceId;\n }\n\n /**\n * Execute function with a specific trace ID context\n */\n withTraceId<T>(traceId: string, fn: () => T): T {\n const previousTraceId = this.currentTraceId;\n this.currentTraceId = traceId;\n try {\n return fn();\n } finally {\n this.currentTraceId = previousTraceId;\n }\n }\n\n /**\n * Execute function with a new auto-generated trace ID\n */\n withNewTraceId<T>(fn: () => T): T {\n return this.withTraceId(randomUUID(), fn);\n }\n\n // ==================== Console Interception ====================\n\n /**\n * Start intercepting console methods and forward them to LogTide\n */\n startConsoleInterception(options?: Partial<ConsoleInterceptOptions>) {\n if (this.originalConsole) {\n // Already intercepting\n return;\n }\n\n const config: ConsoleInterceptOptions = {\n enabled: true,\n service: options?.service ?? 'console',\n preserveOriginal: options?.preserveOriginal ?? true,\n includeStackTrace: options?.includeStackTrace ?? false,\n levels: {\n log: options?.levels?.log ?? true,\n info: options?.levels?.info ?? true,\n warn: options?.levels?.warn ?? true,\n error: options?.levels?.error ?? true,\n debug: options?.levels?.debug ?? true,\n },\n };\n\n this.consoleInterceptOptions = config;\n\n // Save original console methods\n this.originalConsole = {\n log: console.log.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n debug: console.debug.bind(console),\n };\n\n const createInterceptor = (\n method: 'log' | 'info' | 'warn' | 'error' | 'debug',\n level: LogLevel,\n ) => {\n const original = this.originalConsole![method];\n\n return (...args: unknown[]) => {\n // Always call original if preserveOriginal is true\n if (config.preserveOriginal) {\n original(...args);\n }\n\n // Skip if this method is not configured for interception\n if (!config.levels?.[method]) {\n return;\n }\n\n // Skip internal LogTide logs to prevent infinite loops\n const message = args\n .map((arg) => {\n if (typeof arg === 'string') return arg;\n if (arg instanceof Error) return arg.message;\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n })\n .join(' ');\n\n if (message.startsWith('[LogTide]')) {\n return;\n }\n\n // Build metadata\n const metadata: Record<string, unknown> = {\n source: 'console',\n originalMethod: method,\n };\n\n // Include stack trace if configured\n if (config.includeStackTrace) {\n const stack = new Error().stack;\n if (stack) {\n // Remove the first two lines (Error + this interceptor function)\n const stackLines = stack.split('\\n').slice(2);\n metadata.stackTrace = stackLines.join('\\n');\n\n // Extract caller location from first relevant stack line\n const callerLine = stackLines[0];\n if (callerLine) {\n const match = callerLine.match(/at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)/);\n if (match) {\n metadata.caller = {\n function: match[1],\n file: match[2],\n line: parseInt(match[3], 10),\n column: parseInt(match[4], 10),\n };\n } else {\n // Try alternative format: \"at file:line:column\"\n const altMatch = callerLine.match(/at\\s+(.+):(\\d+):(\\d+)/);\n if (altMatch) {\n metadata.caller = {\n file: altMatch[1],\n line: parseInt(altMatch[2], 10),\n column: parseInt(altMatch[3], 10),\n };\n }\n }\n }\n }\n }\n\n // Include raw arguments for complex objects\n if (args.length > 1 || (args.length === 1 && typeof args[0] !== 'string')) {\n metadata.args = args.map((arg) => {\n if (arg instanceof Error) {\n return serializeError(arg);\n }\n return arg;\n });\n }\n\n // Log to LogTide\n this.log({\n service: config.service!,\n level,\n message,\n metadata,\n });\n };\n };\n\n // Replace console methods\n console.log = createInterceptor('log', 'info');\n console.info = createInterceptor('info', 'info');\n console.warn = createInterceptor('warn', 'warn');\n console.error = createInterceptor('error', 'error');\n console.debug = createInterceptor('debug', 'debug');\n\n if (this.debugMode) {\n this.originalConsole.log('[LogTide] Console interception started');\n }\n }\n\n /**\n * Stop intercepting console methods and restore originals\n */\n stopConsoleInterception() {\n if (!this.originalConsole) {\n return;\n }\n\n // Restore original console methods\n console.log = this.originalConsole.log;\n console.info = this.originalConsole.info;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n console.debug = this.originalConsole.debug;\n\n if (this.debugMode) {\n console.log('[LogTide] Console interception stopped');\n }\n\n this.originalConsole = null;\n this.consoleInterceptOptions = null;\n }\n\n /**\n * Check if console interception is active\n */\n isConsoleInterceptionActive(): boolean {\n return this.originalConsole !== null;\n }\n\n // ==================== Logging Methods ====================\n\n private startFlushTimer() {\n this.timer = setInterval(() => {\n this.flush();\n }, this.flushInterval);\n }\n\n log(entry: LogEntry) {\n // Check buffer size limit\n if (this.buffer.length >= this.maxBufferSize) {\n this.metrics.logsDropped++;\n if (this.debugMode) {\n console.warn(`[LogTide] Buffer full, dropping log: ${entry.message}`);\n }\n return;\n }\n\n // Determine trace_id: use entry's trace_id, current context, or auto-generate if enabled\n const traceId = entry.trace_id || this.currentTraceId || (this.autoTraceId ? randomUUID() : undefined);\n\n const internalEntry: InternalLogEntry = {\n ...entry,\n time: entry.time || new Date().toISOString(),\n metadata: {\n ...this.globalMetadata,\n ...entry.metadata,\n },\n trace_id: traceId,\n };\n\n this.buffer.push(internalEntry);\n\n if (this.buffer.length >= this.batchSize) {\n this.flush();\n }\n }\n\n debug(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'debug', message, metadata });\n }\n\n info(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'info', message, metadata });\n }\n\n warn(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'warn', message, metadata });\n }\n\n error(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'error', message, metadata });\n }\n\n critical(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'critical', message, metadata });\n }\n\n // ==================== Flush with Retry & Circuit Breaker ====================\n\n async flush() {\n if (this.buffer.length === 0) return;\n\n // Check circuit breaker\n if (!this.circuitBreaker.canAttempt()) {\n this.metrics.circuitBreakerTrips++;\n if (this.debugMode) {\n console.warn('[LogTide] Circuit breaker OPEN, skipping flush');\n }\n return;\n }\n\n const logs = [...this.buffer];\n this.buffer = [];\n\n const startTime = Date.now();\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n },\n body: JSON.stringify({ logs }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n // Success\n this.circuitBreaker.recordSuccess();\n this.metrics.logsSent += logs.length;\n\n if (this.enableMetrics) {\n const latency = Date.now() - startTime;\n this.latencies.push(latency);\n if (this.latencies.length > 100) {\n this.latencies.shift();\n }\n this.metrics.avgLatencyMs =\n this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;\n }\n\n if (this.debugMode) {\n console.log(`[LogTide] Sent ${logs.length} logs successfully`);\n }\n\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n this.metrics.errors++;\n\n if (attempt < this.maxRetries) {\n this.metrics.retries++;\n const delay = this.retryDelayMs * Math.pow(2, attempt);\n if (this.debugMode) {\n console.warn(\n `[LogTide] Retry ${attempt + 1}/${this.maxRetries} after ${delay}ms: ${lastError.message}`,\n );\n }\n await this.sleep(delay);\n }\n }\n }\n\n // All retries failed\n this.circuitBreaker.recordFailure();\n\n if (this.debugMode) {\n console.error(`[LogTide] Failed to send logs after ${this.maxRetries} retries:`, lastError);\n }\n\n // Re-add logs to buffer if not full\n if (this.buffer.length + logs.length <= this.maxBufferSize) {\n this.buffer.unshift(...logs);\n } else {\n this.metrics.logsDropped += logs.length;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ==================== Query Methods ====================\n\n async query(options: QueryOptions = {}): Promise<LogsResponse> {\n const params = new URLSearchParams();\n\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n if (options.from) {\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n params.append('from', from);\n }\n if (options.to) {\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n params.append('to', to);\n }\n if (options.q) params.append('q', options.q);\n if (options.limit) params.append('limit', String(options.limit));\n if (options.offset) params.append('offset', String(options.offset));\n\n const url = `${this.apiUrl}/api/v1/logs?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Query failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as LogsResponse;\n }\n\n async getByTraceId(traceId: string): Promise<InternalLogEntry[]> {\n const url = `${this.apiUrl}/api/v1/logs/trace/${traceId}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get by trace ID failed: HTTP ${response.status}: ${errorText}`);\n }\n\n const data = (await response.json()) as { logs?: InternalLogEntry[] };\n return data.logs || [];\n }\n\n async getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse> {\n const params = new URLSearchParams();\n\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n\n params.append('from', from);\n params.append('to', to);\n if (options.interval) params.append('interval', options.interval);\n if (options.service) params.append('service', options.service);\n\n const url = `${this.apiUrl}/api/v1/logs/aggregated?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get aggregated stats failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as AggregatedStatsResponse;\n }\n\n // ==================== Live Tail (SSE) ====================\n\n stream(options: StreamOptions): () => void {\n const params = new URLSearchParams();\n params.append('token', this.apiKey);\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n\n const url = `${this.apiUrl}/api/v1/logs/stream?${params.toString()}`;\n\n const eventSource = new EventSource(url);\n\n eventSource.addEventListener('log', (event: Event) => {\n try {\n const messageEvent = event as MessageEvent;\n const log = JSON.parse(messageEvent.data) as InternalLogEntry;\n options.onLog(log);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n options.onError?.(err);\n }\n });\n\n eventSource.addEventListener('error', () => {\n const error = new Error('SSE connection error');\n options.onError?.(error);\n });\n\n // Return cleanup function\n return () => {\n eventSource.close();\n };\n }\n\n // ==================== Metrics ====================\n\n getMetrics(): ClientMetrics {\n return { ...this.metrics };\n }\n\n resetMetrics() {\n this.metrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n this.latencies = [];\n }\n\n getCircuitBreakerState(): string {\n return this.circuitBreaker.getState();\n }\n\n // ==================== Cleanup ====================\n\n async close() {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.stopConsoleInterception();\n await this.flush();\n }\n}\n\nexport default LogTideClient;\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,17 @@
1
1
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';
2
+ interface ConsoleInterceptOptions {
3
+ enabled: boolean;
4
+ service?: string;
5
+ preserveOriginal?: boolean;
6
+ includeStackTrace?: boolean;
7
+ levels?: {
8
+ log?: boolean;
9
+ info?: boolean;
10
+ warn?: boolean;
11
+ error?: boolean;
12
+ debug?: boolean;
13
+ };
14
+ }
2
15
  interface LogTideClientOptions {
3
16
  apiUrl: string;
4
17
  apiKey: string;
@@ -13,6 +26,7 @@ interface LogTideClientOptions {
13
26
  debug?: boolean;
14
27
  globalMetadata?: Record<string, unknown>;
15
28
  autoTraceId?: boolean;
29
+ interceptConsole?: ConsoleInterceptOptions;
16
30
  }
17
31
  interface LogEntry {
18
32
  service: string;
@@ -94,10 +108,11 @@ declare class LogTideClient {
94
108
  private metrics;
95
109
  private latencies;
96
110
  private currentTraceId;
111
+ private consoleInterceptOptions;
112
+ private originalConsole;
97
113
  constructor(options: LogTideClientOptions);
98
114
  /**
99
115
  * Set trace ID for subsequent logs
100
- * Automatically validates and normalizes to UUID v4
101
116
  */
102
117
  setTraceId(traceId: string | null): void;
103
118
  /**
@@ -112,6 +127,18 @@ declare class LogTideClient {
112
127
  * Execute function with a new auto-generated trace ID
113
128
  */
114
129
  withNewTraceId<T>(fn: () => T): T;
130
+ /**
131
+ * Start intercepting console methods and forward them to LogTide
132
+ */
133
+ startConsoleInterception(options?: Partial<ConsoleInterceptOptions>): void;
134
+ /**
135
+ * Stop intercepting console methods and restore originals
136
+ */
137
+ stopConsoleInterception(): void;
138
+ /**
139
+ * Check if console interception is active
140
+ */
141
+ isConsoleInterceptionActive(): boolean;
115
142
  private startFlushTimer;
116
143
  log(entry: LogEntry): void;
117
144
  debug(service: string, message: string, metadata?: Record<string, unknown>): void;
@@ -131,4 +158,4 @@ declare class LogTideClient {
131
158
  close(): Promise<void>;
132
159
  }
133
160
 
134
- export { type AggregatedStatsOptions, type AggregatedStatsResponse, type ClientMetrics, type InternalLogEntry, type LogEntry, type LogLevel, LogTideClient, type LogTideClientOptions, type LogsResponse, type QueryOptions, type StreamOptions, LogTideClient as default, serializeError };
161
+ export { type AggregatedStatsOptions, type AggregatedStatsResponse, type ClientMetrics, type ConsoleInterceptOptions, type InternalLogEntry, type LogEntry, type LogLevel, LogTideClient, type LogTideClientOptions, type LogsResponse, type QueryOptions, type StreamOptions, LogTideClient as default, serializeError };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,17 @@
1
1
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';
2
+ interface ConsoleInterceptOptions {
3
+ enabled: boolean;
4
+ service?: string;
5
+ preserveOriginal?: boolean;
6
+ includeStackTrace?: boolean;
7
+ levels?: {
8
+ log?: boolean;
9
+ info?: boolean;
10
+ warn?: boolean;
11
+ error?: boolean;
12
+ debug?: boolean;
13
+ };
14
+ }
2
15
  interface LogTideClientOptions {
3
16
  apiUrl: string;
4
17
  apiKey: string;
@@ -13,6 +26,7 @@ interface LogTideClientOptions {
13
26
  debug?: boolean;
14
27
  globalMetadata?: Record<string, unknown>;
15
28
  autoTraceId?: boolean;
29
+ interceptConsole?: ConsoleInterceptOptions;
16
30
  }
17
31
  interface LogEntry {
18
32
  service: string;
@@ -94,10 +108,11 @@ declare class LogTideClient {
94
108
  private metrics;
95
109
  private latencies;
96
110
  private currentTraceId;
111
+ private consoleInterceptOptions;
112
+ private originalConsole;
97
113
  constructor(options: LogTideClientOptions);
98
114
  /**
99
115
  * Set trace ID for subsequent logs
100
- * Automatically validates and normalizes to UUID v4
101
116
  */
102
117
  setTraceId(traceId: string | null): void;
103
118
  /**
@@ -112,6 +127,18 @@ declare class LogTideClient {
112
127
  * Execute function with a new auto-generated trace ID
113
128
  */
114
129
  withNewTraceId<T>(fn: () => T): T;
130
+ /**
131
+ * Start intercepting console methods and forward them to LogTide
132
+ */
133
+ startConsoleInterception(options?: Partial<ConsoleInterceptOptions>): void;
134
+ /**
135
+ * Stop intercepting console methods and restore originals
136
+ */
137
+ stopConsoleInterception(): void;
138
+ /**
139
+ * Check if console interception is active
140
+ */
141
+ isConsoleInterceptionActive(): boolean;
115
142
  private startFlushTimer;
116
143
  log(entry: LogEntry): void;
117
144
  debug(service: string, message: string, metadata?: Record<string, unknown>): void;
@@ -131,4 +158,4 @@ declare class LogTideClient {
131
158
  close(): Promise<void>;
132
159
  }
133
160
 
134
- export { type AggregatedStatsOptions, type AggregatedStatsResponse, type ClientMetrics, type InternalLogEntry, type LogEntry, type LogLevel, LogTideClient, type LogTideClientOptions, type LogsResponse, type QueryOptions, type StreamOptions, LogTideClient as default, serializeError };
161
+ export { type AggregatedStatsOptions, type AggregatedStatsResponse, type ClientMetrics, type ConsoleInterceptOptions, type InternalLogEntry, type LogEntry, type LogLevel, LogTideClient, type LogTideClientOptions, type LogsResponse, type QueryOptions, type StreamOptions, LogTideClient as default, serializeError };
package/dist/index.js CHANGED
@@ -38,25 +38,6 @@ var CircuitBreaker = class {
38
38
  return this.state;
39
39
  }
40
40
  };
41
- function isValidUUID(str) {
42
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
43
- return uuidRegex.test(str);
44
- }
45
- function normalizeTraceId(traceId, debug) {
46
- if (!traceId) {
47
- return void 0;
48
- }
49
- if (isValidUUID(traceId)) {
50
- return traceId;
51
- }
52
- const newTraceId = randomUUID();
53
- if (debug) {
54
- console.warn(
55
- `[LogTide] Invalid trace_id "${traceId}" (must be UUID v4). Generated new UUID: ${newTraceId}`
56
- );
57
- }
58
- return newTraceId;
59
- }
60
41
  function serializeError(error) {
61
42
  if (error instanceof Error) {
62
43
  const result = {
@@ -104,6 +85,9 @@ var LogTideClient = class {
104
85
  latencies = [];
105
86
  // Context tracking
106
87
  currentTraceId = null;
88
+ // Console interception
89
+ consoleInterceptOptions = null;
90
+ originalConsole = null;
107
91
  constructor(options) {
108
92
  this.apiUrl = options.apiUrl.replace(/\/$/, "");
109
93
  this.apiKey = options.apiKey;
@@ -121,14 +105,16 @@ var LogTideClient = class {
121
105
  options.circuitBreakerResetMs || 3e4
122
106
  );
123
107
  this.startFlushTimer();
108
+ if (options.interceptConsole?.enabled) {
109
+ this.startConsoleInterception(options.interceptConsole);
110
+ }
124
111
  }
125
112
  // ==================== Context Helpers ====================
126
113
  /**
127
114
  * Set trace ID for subsequent logs
128
- * Automatically validates and normalizes to UUID v4
129
115
  */
130
116
  setTraceId(traceId) {
131
- this.currentTraceId = normalizeTraceId(traceId, this.debugMode) || null;
117
+ this.currentTraceId = traceId;
132
118
  }
133
119
  /**
134
120
  * Get current trace ID
@@ -154,6 +140,137 @@ var LogTideClient = class {
154
140
  withNewTraceId(fn) {
155
141
  return this.withTraceId(randomUUID(), fn);
156
142
  }
143
+ // ==================== Console Interception ====================
144
+ /**
145
+ * Start intercepting console methods and forward them to LogTide
146
+ */
147
+ startConsoleInterception(options) {
148
+ if (this.originalConsole) {
149
+ return;
150
+ }
151
+ const config = {
152
+ enabled: true,
153
+ service: options?.service ?? "console",
154
+ preserveOriginal: options?.preserveOriginal ?? true,
155
+ includeStackTrace: options?.includeStackTrace ?? false,
156
+ levels: {
157
+ log: options?.levels?.log ?? true,
158
+ info: options?.levels?.info ?? true,
159
+ warn: options?.levels?.warn ?? true,
160
+ error: options?.levels?.error ?? true,
161
+ debug: options?.levels?.debug ?? true
162
+ }
163
+ };
164
+ this.consoleInterceptOptions = config;
165
+ this.originalConsole = {
166
+ log: console.log.bind(console),
167
+ info: console.info.bind(console),
168
+ warn: console.warn.bind(console),
169
+ error: console.error.bind(console),
170
+ debug: console.debug.bind(console)
171
+ };
172
+ const createInterceptor = (method, level) => {
173
+ const original = this.originalConsole[method];
174
+ return (...args) => {
175
+ if (config.preserveOriginal) {
176
+ original(...args);
177
+ }
178
+ if (!config.levels?.[method]) {
179
+ return;
180
+ }
181
+ const message = args.map((arg) => {
182
+ if (typeof arg === "string") return arg;
183
+ if (arg instanceof Error) return arg.message;
184
+ try {
185
+ return JSON.stringify(arg);
186
+ } catch {
187
+ return String(arg);
188
+ }
189
+ }).join(" ");
190
+ if (message.startsWith("[LogTide]")) {
191
+ return;
192
+ }
193
+ const metadata = {
194
+ source: "console",
195
+ originalMethod: method
196
+ };
197
+ if (config.includeStackTrace) {
198
+ const stack = new Error().stack;
199
+ if (stack) {
200
+ const stackLines = stack.split("\n").slice(2);
201
+ metadata.stackTrace = stackLines.join("\n");
202
+ const callerLine = stackLines[0];
203
+ if (callerLine) {
204
+ const match = callerLine.match(/at\s+(.+?)\s+\((.+):(\d+):(\d+)\)/);
205
+ if (match) {
206
+ metadata.caller = {
207
+ function: match[1],
208
+ file: match[2],
209
+ line: parseInt(match[3], 10),
210
+ column: parseInt(match[4], 10)
211
+ };
212
+ } else {
213
+ const altMatch = callerLine.match(/at\s+(.+):(\d+):(\d+)/);
214
+ if (altMatch) {
215
+ metadata.caller = {
216
+ file: altMatch[1],
217
+ line: parseInt(altMatch[2], 10),
218
+ column: parseInt(altMatch[3], 10)
219
+ };
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ if (args.length > 1 || args.length === 1 && typeof args[0] !== "string") {
226
+ metadata.args = args.map((arg) => {
227
+ if (arg instanceof Error) {
228
+ return serializeError(arg);
229
+ }
230
+ return arg;
231
+ });
232
+ }
233
+ this.log({
234
+ service: config.service,
235
+ level,
236
+ message,
237
+ metadata
238
+ });
239
+ };
240
+ };
241
+ console.log = createInterceptor("log", "info");
242
+ console.info = createInterceptor("info", "info");
243
+ console.warn = createInterceptor("warn", "warn");
244
+ console.error = createInterceptor("error", "error");
245
+ console.debug = createInterceptor("debug", "debug");
246
+ if (this.debugMode) {
247
+ this.originalConsole.log("[LogTide] Console interception started");
248
+ }
249
+ }
250
+ /**
251
+ * Stop intercepting console methods and restore originals
252
+ */
253
+ stopConsoleInterception() {
254
+ if (!this.originalConsole) {
255
+ return;
256
+ }
257
+ console.log = this.originalConsole.log;
258
+ console.info = this.originalConsole.info;
259
+ console.warn = this.originalConsole.warn;
260
+ console.error = this.originalConsole.error;
261
+ console.debug = this.originalConsole.debug;
262
+ if (this.debugMode) {
263
+ console.log("[LogTide] Console interception stopped");
264
+ }
265
+ this.originalConsole = null;
266
+ this.consoleInterceptOptions = null;
267
+ }
268
+ /**
269
+ * Check if console interception is active
270
+ */
271
+ isConsoleInterceptionActive() {
272
+ return this.originalConsole !== null;
273
+ }
157
274
  // ==================== Logging Methods ====================
158
275
  startFlushTimer() {
159
276
  this.timer = setInterval(() => {
@@ -168,7 +285,7 @@ var LogTideClient = class {
168
285
  }
169
286
  return;
170
287
  }
171
- const normalizedTraceId = normalizeTraceId(entry.trace_id, this.debugMode) || normalizeTraceId(this.currentTraceId, this.debugMode) || (this.autoTraceId ? randomUUID() : void 0);
288
+ const traceId = entry.trace_id || this.currentTraceId || (this.autoTraceId ? randomUUID() : void 0);
172
289
  const internalEntry = {
173
290
  ...entry,
174
291
  time: entry.time || (/* @__PURE__ */ new Date()).toISOString(),
@@ -176,7 +293,7 @@ var LogTideClient = class {
176
293
  ...this.globalMetadata,
177
294
  ...entry.metadata
178
295
  },
179
- trace_id: normalizedTraceId
296
+ trace_id: traceId
180
297
  };
181
298
  this.buffer.push(internalEntry);
182
299
  if (this.buffer.length >= this.batchSize) {
@@ -392,6 +509,7 @@ var LogTideClient = class {
392
509
  clearInterval(this.timer);
393
510
  this.timer = null;
394
511
  }
512
+ this.stopConsoleInterception();
395
513
  await this.flush();
396
514
  }
397
515
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { randomUUID } from 'crypto';\n\n// ==================== Types ====================\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface LogTideClientOptions {\n apiUrl: string;\n apiKey: string;\n batchSize?: number;\n flushInterval?: number;\n maxBufferSize?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n circuitBreakerThreshold?: number;\n circuitBreakerResetMs?: number;\n enableMetrics?: boolean;\n debug?: boolean;\n globalMetadata?: Record<string, unknown>;\n autoTraceId?: boolean;\n}\n\nexport interface LogEntry {\n service: string;\n level: LogLevel;\n message: string;\n time?: string;\n metadata?: Record<string, unknown>;\n trace_id?: string;\n}\n\nexport interface InternalLogEntry extends LogEntry {\n time: string;\n}\n\nexport interface QueryOptions {\n service?: string;\n level?: LogLevel;\n from?: Date | string;\n to?: Date | string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface LogsResponse {\n logs: InternalLogEntry[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface AggregatedStatsOptions {\n from: Date | string;\n to: Date | string;\n interval?: '1m' | '5m' | '1h' | '1d';\n service?: string;\n}\n\nexport interface AggregatedStatsResponse {\n timeseries: Array<{\n bucket: string;\n total: number;\n by_level: Record<string, number>;\n }>;\n top_services: Array<{ service: string; count: number }>;\n top_errors: Array<{ message: string; count: number }>;\n}\n\nexport interface ClientMetrics {\n logsSent: number;\n logsDropped: number;\n errors: number;\n retries: number;\n avgLatencyMs: number;\n circuitBreakerTrips: number;\n}\n\nexport interface StreamOptions {\n service?: string;\n level?: LogLevel;\n onLog: (log: InternalLogEntry) => void;\n onError?: (error: Error) => void;\n}\n\n// ==================== Circuit Breaker ====================\n\nenum CircuitState {\n CLOSED = 'CLOSED',\n OPEN = 'OPEN',\n HALF_OPEN = 'HALF_OPEN',\n}\n\nclass CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failureCount = 0;\n private lastFailureTime: number | null = null;\n\n constructor(\n private threshold: number,\n private resetMs: number,\n ) {}\n\n recordSuccess() {\n this.failureCount = 0;\n this.state = CircuitState.CLOSED;\n }\n\n recordFailure() {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.threshold) {\n this.state = CircuitState.OPEN;\n }\n }\n\n canAttempt(): boolean {\n if (this.state === CircuitState.CLOSED) {\n return true;\n }\n\n if (this.state === CircuitState.OPEN) {\n const now = Date.now();\n if (this.lastFailureTime && now - this.lastFailureTime >= this.resetMs) {\n this.state = CircuitState.HALF_OPEN;\n return true;\n }\n return false;\n }\n\n // HALF_OPEN state - allow one attempt\n return true;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n\n// ==================== UUID Validation ====================\n\n/**\n * Validates if a string is a valid UUID (v4)\n */\nfunction isValidUUID(str: string): boolean {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return uuidRegex.test(str);\n}\n\n/**\n * Normalizes a trace_id to ensure it's a valid UUID.\n * If invalid, generates a new UUID and warns in debug mode.\n */\nfunction normalizeTraceId(traceId: string | null | undefined, debug: boolean): string | undefined {\n if (!traceId) {\n return undefined;\n }\n\n if (isValidUUID(traceId)) {\n return traceId;\n }\n\n // Invalid UUID - generate a new one\n const newTraceId = randomUUID();\n if (debug) {\n console.warn(\n `[LogTide] Invalid trace_id \"${traceId}\" (must be UUID v4). Generated new UUID: ${newTraceId}`,\n );\n }\n return newTraceId;\n}\n\n// ==================== Error Serialization ====================\n\nexport function serializeError(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n const result: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n\n if (error.cause) {\n result.cause = serializeError(error.cause);\n }\n\n return result;\n }\n\n if (typeof error === 'string') {\n return { message: error };\n }\n\n if (typeof error === 'object' && error !== null) {\n return error as Record<string, unknown>;\n }\n\n return { message: String(error) };\n}\n\n// ==================== Main Client ====================\n\nexport class LogTideClient {\n private apiUrl: string;\n private apiKey: string;\n private batchSize: number;\n private flushInterval: number;\n private maxBufferSize: number;\n private maxRetries: number;\n private retryDelayMs: number;\n private enableMetrics: boolean;\n private debugMode: boolean;\n private globalMetadata: Record<string, unknown>;\n private autoTraceId: boolean;\n\n private buffer: InternalLogEntry[] = [];\n private timer: NodeJS.Timeout | null = null;\n private circuitBreaker: CircuitBreaker;\n\n // Metrics\n private metrics: ClientMetrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n private latencies: number[] = [];\n\n // Context tracking\n private currentTraceId: string | null = null;\n\n constructor(options: LogTideClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 5000;\n this.maxBufferSize = options.maxBufferSize || 10000;\n this.maxRetries = options.maxRetries || 3;\n this.retryDelayMs = options.retryDelayMs || 1000;\n this.enableMetrics = options.enableMetrics ?? true;\n this.debugMode = options.debug ?? false;\n this.globalMetadata = options.globalMetadata || {};\n this.autoTraceId = options.autoTraceId ?? false;\n\n this.circuitBreaker = new CircuitBreaker(\n options.circuitBreakerThreshold || 5,\n options.circuitBreakerResetMs || 30000,\n );\n\n this.startFlushTimer();\n }\n\n // ==================== Context Helpers ====================\n\n /**\n * Set trace ID for subsequent logs\n * Automatically validates and normalizes to UUID v4\n */\n setTraceId(traceId: string | null) {\n this.currentTraceId = normalizeTraceId(traceId, this.debugMode) || null;\n }\n\n /**\n * Get current trace ID\n */\n getTraceId(): string | null {\n return this.currentTraceId;\n }\n\n /**\n * Execute function with a specific trace ID context\n */\n withTraceId<T>(traceId: string, fn: () => T): T {\n const previousTraceId = this.currentTraceId;\n this.currentTraceId = traceId;\n try {\n return fn();\n } finally {\n this.currentTraceId = previousTraceId;\n }\n }\n\n /**\n * Execute function with a new auto-generated trace ID\n */\n withNewTraceId<T>(fn: () => T): T {\n return this.withTraceId(randomUUID(), fn);\n }\n\n // ==================== Logging Methods ====================\n\n private startFlushTimer() {\n this.timer = setInterval(() => {\n this.flush();\n }, this.flushInterval);\n }\n\n log(entry: LogEntry) {\n // Check buffer size limit\n if (this.buffer.length >= this.maxBufferSize) {\n this.metrics.logsDropped++;\n if (this.debugMode) {\n console.warn(`[LogTide] Buffer full, dropping log: ${entry.message}`);\n }\n return;\n }\n\n // Normalize trace_id to ensure it's a valid UUID\n const normalizedTraceId =\n normalizeTraceId(entry.trace_id, this.debugMode) ||\n normalizeTraceId(this.currentTraceId, this.debugMode) ||\n (this.autoTraceId ? randomUUID() : undefined);\n\n const internalEntry: InternalLogEntry = {\n ...entry,\n time: entry.time || new Date().toISOString(),\n metadata: {\n ...this.globalMetadata,\n ...entry.metadata,\n },\n trace_id: normalizedTraceId,\n };\n\n this.buffer.push(internalEntry);\n\n if (this.buffer.length >= this.batchSize) {\n this.flush();\n }\n }\n\n debug(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'debug', message, metadata });\n }\n\n info(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'info', message, metadata });\n }\n\n warn(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'warn', message, metadata });\n }\n\n error(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'error', message, metadata });\n }\n\n critical(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'critical', message, metadata });\n }\n\n // ==================== Flush with Retry & Circuit Breaker ====================\n\n async flush() {\n if (this.buffer.length === 0) return;\n\n // Check circuit breaker\n if (!this.circuitBreaker.canAttempt()) {\n this.metrics.circuitBreakerTrips++;\n if (this.debugMode) {\n console.warn('[LogTide] Circuit breaker OPEN, skipping flush');\n }\n return;\n }\n\n const logs = [...this.buffer];\n this.buffer = [];\n\n const startTime = Date.now();\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n },\n body: JSON.stringify({ logs }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n // Success\n this.circuitBreaker.recordSuccess();\n this.metrics.logsSent += logs.length;\n\n if (this.enableMetrics) {\n const latency = Date.now() - startTime;\n this.latencies.push(latency);\n if (this.latencies.length > 100) {\n this.latencies.shift();\n }\n this.metrics.avgLatencyMs =\n this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;\n }\n\n if (this.debugMode) {\n console.log(`[LogTide] Sent ${logs.length} logs successfully`);\n }\n\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n this.metrics.errors++;\n\n if (attempt < this.maxRetries) {\n this.metrics.retries++;\n const delay = this.retryDelayMs * Math.pow(2, attempt);\n if (this.debugMode) {\n console.warn(\n `[LogTide] Retry ${attempt + 1}/${this.maxRetries} after ${delay}ms: ${lastError.message}`,\n );\n }\n await this.sleep(delay);\n }\n }\n }\n\n // All retries failed\n this.circuitBreaker.recordFailure();\n\n if (this.debugMode) {\n console.error(`[LogTide] Failed to send logs after ${this.maxRetries} retries:`, lastError);\n }\n\n // Re-add logs to buffer if not full\n if (this.buffer.length + logs.length <= this.maxBufferSize) {\n this.buffer.unshift(...logs);\n } else {\n this.metrics.logsDropped += logs.length;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ==================== Query Methods ====================\n\n async query(options: QueryOptions = {}): Promise<LogsResponse> {\n const params = new URLSearchParams();\n\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n if (options.from) {\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n params.append('from', from);\n }\n if (options.to) {\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n params.append('to', to);\n }\n if (options.q) params.append('q', options.q);\n if (options.limit) params.append('limit', String(options.limit));\n if (options.offset) params.append('offset', String(options.offset));\n\n const url = `${this.apiUrl}/api/v1/logs?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Query failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as LogsResponse;\n }\n\n async getByTraceId(traceId: string): Promise<InternalLogEntry[]> {\n const url = `${this.apiUrl}/api/v1/logs/trace/${traceId}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get by trace ID failed: HTTP ${response.status}: ${errorText}`);\n }\n\n const data = (await response.json()) as { logs?: InternalLogEntry[] };\n return data.logs || [];\n }\n\n async getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse> {\n const params = new URLSearchParams();\n\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n\n params.append('from', from);\n params.append('to', to);\n if (options.interval) params.append('interval', options.interval);\n if (options.service) params.append('service', options.service);\n\n const url = `${this.apiUrl}/api/v1/logs/aggregated?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get aggregated stats failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as AggregatedStatsResponse;\n }\n\n // ==================== Live Tail (SSE) ====================\n\n stream(options: StreamOptions): () => void {\n const params = new URLSearchParams();\n params.append('token', this.apiKey);\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n\n const url = `${this.apiUrl}/api/v1/logs/stream?${params.toString()}`;\n\n const eventSource = new EventSource(url);\n\n eventSource.addEventListener('log', (event: Event) => {\n try {\n const messageEvent = event as MessageEvent;\n const log = JSON.parse(messageEvent.data) as InternalLogEntry;\n options.onLog(log);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n options.onError?.(err);\n }\n });\n\n eventSource.addEventListener('error', () => {\n const error = new Error('SSE connection error');\n options.onError?.(error);\n });\n\n // Return cleanup function\n return () => {\n eventSource.close();\n };\n }\n\n // ==================== Metrics ====================\n\n getMetrics(): ClientMetrics {\n return { ...this.metrics };\n }\n\n resetMetrics() {\n this.metrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n this.latencies = [];\n }\n\n getCircuitBreakerState(): string {\n return this.circuitBreaker.getState();\n }\n\n // ==================== Cleanup ====================\n\n async close() {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n}\n\nexport default LogTideClient;\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { randomUUID } from 'crypto';\n\n// ==================== Types ====================\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';\n\nexport interface ConsoleInterceptOptions {\n enabled: boolean;\n service?: string;\n preserveOriginal?: boolean;\n includeStackTrace?: boolean;\n levels?: {\n log?: boolean;\n info?: boolean;\n warn?: boolean;\n error?: boolean;\n debug?: boolean;\n };\n}\n\nexport interface LogTideClientOptions {\n apiUrl: string;\n apiKey: string;\n batchSize?: number;\n flushInterval?: number;\n maxBufferSize?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n circuitBreakerThreshold?: number;\n circuitBreakerResetMs?: number;\n enableMetrics?: boolean;\n debug?: boolean;\n globalMetadata?: Record<string, unknown>;\n autoTraceId?: boolean;\n interceptConsole?: ConsoleInterceptOptions;\n}\n\nexport interface LogEntry {\n service: string;\n level: LogLevel;\n message: string;\n time?: string;\n metadata?: Record<string, unknown>;\n trace_id?: string;\n}\n\nexport interface InternalLogEntry extends LogEntry {\n time: string;\n}\n\nexport interface QueryOptions {\n service?: string;\n level?: LogLevel;\n from?: Date | string;\n to?: Date | string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface LogsResponse {\n logs: InternalLogEntry[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface AggregatedStatsOptions {\n from: Date | string;\n to: Date | string;\n interval?: '1m' | '5m' | '1h' | '1d';\n service?: string;\n}\n\nexport interface AggregatedStatsResponse {\n timeseries: Array<{\n bucket: string;\n total: number;\n by_level: Record<string, number>;\n }>;\n top_services: Array<{ service: string; count: number }>;\n top_errors: Array<{ message: string; count: number }>;\n}\n\nexport interface ClientMetrics {\n logsSent: number;\n logsDropped: number;\n errors: number;\n retries: number;\n avgLatencyMs: number;\n circuitBreakerTrips: number;\n}\n\nexport interface StreamOptions {\n service?: string;\n level?: LogLevel;\n onLog: (log: InternalLogEntry) => void;\n onError?: (error: Error) => void;\n}\n\n// ==================== Circuit Breaker ====================\n\nenum CircuitState {\n CLOSED = 'CLOSED',\n OPEN = 'OPEN',\n HALF_OPEN = 'HALF_OPEN',\n}\n\nclass CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failureCount = 0;\n private lastFailureTime: number | null = null;\n\n constructor(\n private threshold: number,\n private resetMs: number,\n ) {}\n\n recordSuccess() {\n this.failureCount = 0;\n this.state = CircuitState.CLOSED;\n }\n\n recordFailure() {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.failureCount >= this.threshold) {\n this.state = CircuitState.OPEN;\n }\n }\n\n canAttempt(): boolean {\n if (this.state === CircuitState.CLOSED) {\n return true;\n }\n\n if (this.state === CircuitState.OPEN) {\n const now = Date.now();\n if (this.lastFailureTime && now - this.lastFailureTime >= this.resetMs) {\n this.state = CircuitState.HALF_OPEN;\n return true;\n }\n return false;\n }\n\n // HALF_OPEN state - allow one attempt\n return true;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n\n\n// ==================== Error Serialization ====================\n\nexport function serializeError(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n const result: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n\n if (error.cause) {\n result.cause = serializeError(error.cause);\n }\n\n return result;\n }\n\n if (typeof error === 'string') {\n return { message: error };\n }\n\n if (typeof error === 'object' && error !== null) {\n return error as Record<string, unknown>;\n }\n\n return { message: String(error) };\n}\n\n// ==================== Main Client ====================\n\nexport class LogTideClient {\n private apiUrl: string;\n private apiKey: string;\n private batchSize: number;\n private flushInterval: number;\n private maxBufferSize: number;\n private maxRetries: number;\n private retryDelayMs: number;\n private enableMetrics: boolean;\n private debugMode: boolean;\n private globalMetadata: Record<string, unknown>;\n private autoTraceId: boolean;\n\n private buffer: InternalLogEntry[] = [];\n private timer: NodeJS.Timeout | null = null;\n private circuitBreaker: CircuitBreaker;\n\n // Metrics\n private metrics: ClientMetrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n private latencies: number[] = [];\n\n // Context tracking\n private currentTraceId: string | null = null;\n\n // Console interception\n private consoleInterceptOptions: ConsoleInterceptOptions | null = null;\n private originalConsole: {\n log: typeof console.log;\n info: typeof console.info;\n warn: typeof console.warn;\n error: typeof console.error;\n debug: typeof console.debug;\n } | null = null;\n\n constructor(options: LogTideClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 5000;\n this.maxBufferSize = options.maxBufferSize || 10000;\n this.maxRetries = options.maxRetries || 3;\n this.retryDelayMs = options.retryDelayMs || 1000;\n this.enableMetrics = options.enableMetrics ?? true;\n this.debugMode = options.debug ?? false;\n this.globalMetadata = options.globalMetadata || {};\n this.autoTraceId = options.autoTraceId ?? false;\n\n this.circuitBreaker = new CircuitBreaker(\n options.circuitBreakerThreshold || 5,\n options.circuitBreakerResetMs || 30000,\n );\n\n this.startFlushTimer();\n\n // Start console interception if configured\n if (options.interceptConsole?.enabled) {\n this.startConsoleInterception(options.interceptConsole);\n }\n }\n\n // ==================== Context Helpers ====================\n\n /**\n * Set trace ID for subsequent logs\n */\n setTraceId(traceId: string | null) {\n this.currentTraceId = traceId;\n }\n\n /**\n * Get current trace ID\n */\n getTraceId(): string | null {\n return this.currentTraceId;\n }\n\n /**\n * Execute function with a specific trace ID context\n */\n withTraceId<T>(traceId: string, fn: () => T): T {\n const previousTraceId = this.currentTraceId;\n this.currentTraceId = traceId;\n try {\n return fn();\n } finally {\n this.currentTraceId = previousTraceId;\n }\n }\n\n /**\n * Execute function with a new auto-generated trace ID\n */\n withNewTraceId<T>(fn: () => T): T {\n return this.withTraceId(randomUUID(), fn);\n }\n\n // ==================== Console Interception ====================\n\n /**\n * Start intercepting console methods and forward them to LogTide\n */\n startConsoleInterception(options?: Partial<ConsoleInterceptOptions>) {\n if (this.originalConsole) {\n // Already intercepting\n return;\n }\n\n const config: ConsoleInterceptOptions = {\n enabled: true,\n service: options?.service ?? 'console',\n preserveOriginal: options?.preserveOriginal ?? true,\n includeStackTrace: options?.includeStackTrace ?? false,\n levels: {\n log: options?.levels?.log ?? true,\n info: options?.levels?.info ?? true,\n warn: options?.levels?.warn ?? true,\n error: options?.levels?.error ?? true,\n debug: options?.levels?.debug ?? true,\n },\n };\n\n this.consoleInterceptOptions = config;\n\n // Save original console methods\n this.originalConsole = {\n log: console.log.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n debug: console.debug.bind(console),\n };\n\n const createInterceptor = (\n method: 'log' | 'info' | 'warn' | 'error' | 'debug',\n level: LogLevel,\n ) => {\n const original = this.originalConsole![method];\n\n return (...args: unknown[]) => {\n // Always call original if preserveOriginal is true\n if (config.preserveOriginal) {\n original(...args);\n }\n\n // Skip if this method is not configured for interception\n if (!config.levels?.[method]) {\n return;\n }\n\n // Skip internal LogTide logs to prevent infinite loops\n const message = args\n .map((arg) => {\n if (typeof arg === 'string') return arg;\n if (arg instanceof Error) return arg.message;\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n })\n .join(' ');\n\n if (message.startsWith('[LogTide]')) {\n return;\n }\n\n // Build metadata\n const metadata: Record<string, unknown> = {\n source: 'console',\n originalMethod: method,\n };\n\n // Include stack trace if configured\n if (config.includeStackTrace) {\n const stack = new Error().stack;\n if (stack) {\n // Remove the first two lines (Error + this interceptor function)\n const stackLines = stack.split('\\n').slice(2);\n metadata.stackTrace = stackLines.join('\\n');\n\n // Extract caller location from first relevant stack line\n const callerLine = stackLines[0];\n if (callerLine) {\n const match = callerLine.match(/at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)/);\n if (match) {\n metadata.caller = {\n function: match[1],\n file: match[2],\n line: parseInt(match[3], 10),\n column: parseInt(match[4], 10),\n };\n } else {\n // Try alternative format: \"at file:line:column\"\n const altMatch = callerLine.match(/at\\s+(.+):(\\d+):(\\d+)/);\n if (altMatch) {\n metadata.caller = {\n file: altMatch[1],\n line: parseInt(altMatch[2], 10),\n column: parseInt(altMatch[3], 10),\n };\n }\n }\n }\n }\n }\n\n // Include raw arguments for complex objects\n if (args.length > 1 || (args.length === 1 && typeof args[0] !== 'string')) {\n metadata.args = args.map((arg) => {\n if (arg instanceof Error) {\n return serializeError(arg);\n }\n return arg;\n });\n }\n\n // Log to LogTide\n this.log({\n service: config.service!,\n level,\n message,\n metadata,\n });\n };\n };\n\n // Replace console methods\n console.log = createInterceptor('log', 'info');\n console.info = createInterceptor('info', 'info');\n console.warn = createInterceptor('warn', 'warn');\n console.error = createInterceptor('error', 'error');\n console.debug = createInterceptor('debug', 'debug');\n\n if (this.debugMode) {\n this.originalConsole.log('[LogTide] Console interception started');\n }\n }\n\n /**\n * Stop intercepting console methods and restore originals\n */\n stopConsoleInterception() {\n if (!this.originalConsole) {\n return;\n }\n\n // Restore original console methods\n console.log = this.originalConsole.log;\n console.info = this.originalConsole.info;\n console.warn = this.originalConsole.warn;\n console.error = this.originalConsole.error;\n console.debug = this.originalConsole.debug;\n\n if (this.debugMode) {\n console.log('[LogTide] Console interception stopped');\n }\n\n this.originalConsole = null;\n this.consoleInterceptOptions = null;\n }\n\n /**\n * Check if console interception is active\n */\n isConsoleInterceptionActive(): boolean {\n return this.originalConsole !== null;\n }\n\n // ==================== Logging Methods ====================\n\n private startFlushTimer() {\n this.timer = setInterval(() => {\n this.flush();\n }, this.flushInterval);\n }\n\n log(entry: LogEntry) {\n // Check buffer size limit\n if (this.buffer.length >= this.maxBufferSize) {\n this.metrics.logsDropped++;\n if (this.debugMode) {\n console.warn(`[LogTide] Buffer full, dropping log: ${entry.message}`);\n }\n return;\n }\n\n // Determine trace_id: use entry's trace_id, current context, or auto-generate if enabled\n const traceId = entry.trace_id || this.currentTraceId || (this.autoTraceId ? randomUUID() : undefined);\n\n const internalEntry: InternalLogEntry = {\n ...entry,\n time: entry.time || new Date().toISOString(),\n metadata: {\n ...this.globalMetadata,\n ...entry.metadata,\n },\n trace_id: traceId,\n };\n\n this.buffer.push(internalEntry);\n\n if (this.buffer.length >= this.batchSize) {\n this.flush();\n }\n }\n\n debug(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'debug', message, metadata });\n }\n\n info(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'info', message, metadata });\n }\n\n warn(service: string, message: string, metadata?: Record<string, unknown>) {\n this.log({ service, level: 'warn', message, metadata });\n }\n\n error(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'error', message, metadata });\n }\n\n critical(service: string, message: string, metadataOrError?: Record<string, unknown> | Error) {\n let metadata: Record<string, unknown> = {};\n\n if (metadataOrError instanceof Error) {\n metadata = { error: serializeError(metadataOrError) };\n } else if (metadataOrError) {\n metadata = metadataOrError;\n }\n\n this.log({ service, level: 'critical', message, metadata });\n }\n\n // ==================== Flush with Retry & Circuit Breaker ====================\n\n async flush() {\n if (this.buffer.length === 0) return;\n\n // Check circuit breaker\n if (!this.circuitBreaker.canAttempt()) {\n this.metrics.circuitBreakerTrips++;\n if (this.debugMode) {\n console.warn('[LogTide] Circuit breaker OPEN, skipping flush');\n }\n return;\n }\n\n const logs = [...this.buffer];\n this.buffer = [];\n\n const startTime = Date.now();\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/v1/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n },\n body: JSON.stringify({ logs }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n // Success\n this.circuitBreaker.recordSuccess();\n this.metrics.logsSent += logs.length;\n\n if (this.enableMetrics) {\n const latency = Date.now() - startTime;\n this.latencies.push(latency);\n if (this.latencies.length > 100) {\n this.latencies.shift();\n }\n this.metrics.avgLatencyMs =\n this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;\n }\n\n if (this.debugMode) {\n console.log(`[LogTide] Sent ${logs.length} logs successfully`);\n }\n\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n this.metrics.errors++;\n\n if (attempt < this.maxRetries) {\n this.metrics.retries++;\n const delay = this.retryDelayMs * Math.pow(2, attempt);\n if (this.debugMode) {\n console.warn(\n `[LogTide] Retry ${attempt + 1}/${this.maxRetries} after ${delay}ms: ${lastError.message}`,\n );\n }\n await this.sleep(delay);\n }\n }\n }\n\n // All retries failed\n this.circuitBreaker.recordFailure();\n\n if (this.debugMode) {\n console.error(`[LogTide] Failed to send logs after ${this.maxRetries} retries:`, lastError);\n }\n\n // Re-add logs to buffer if not full\n if (this.buffer.length + logs.length <= this.maxBufferSize) {\n this.buffer.unshift(...logs);\n } else {\n this.metrics.logsDropped += logs.length;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ==================== Query Methods ====================\n\n async query(options: QueryOptions = {}): Promise<LogsResponse> {\n const params = new URLSearchParams();\n\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n if (options.from) {\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n params.append('from', from);\n }\n if (options.to) {\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n params.append('to', to);\n }\n if (options.q) params.append('q', options.q);\n if (options.limit) params.append('limit', String(options.limit));\n if (options.offset) params.append('offset', String(options.offset));\n\n const url = `${this.apiUrl}/api/v1/logs?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Query failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as LogsResponse;\n }\n\n async getByTraceId(traceId: string): Promise<InternalLogEntry[]> {\n const url = `${this.apiUrl}/api/v1/logs/trace/${traceId}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get by trace ID failed: HTTP ${response.status}: ${errorText}`);\n }\n\n const data = (await response.json()) as { logs?: InternalLogEntry[] };\n return data.logs || [];\n }\n\n async getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse> {\n const params = new URLSearchParams();\n\n const from = options.from instanceof Date ? options.from.toISOString() : options.from;\n const to = options.to instanceof Date ? options.to.toISOString() : options.to;\n\n params.append('from', from);\n params.append('to', to);\n if (options.interval) params.append('interval', options.interval);\n if (options.service) params.append('service', options.service);\n\n const url = `${this.apiUrl}/api/v1/logs/aggregated?${params.toString()}`;\n\n const response = await fetch(url, {\n headers: {\n 'X-API-Key': this.apiKey,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Get aggregated stats failed: HTTP ${response.status}: ${errorText}`);\n }\n\n return (await response.json()) as AggregatedStatsResponse;\n }\n\n // ==================== Live Tail (SSE) ====================\n\n stream(options: StreamOptions): () => void {\n const params = new URLSearchParams();\n params.append('token', this.apiKey);\n if (options.service) params.append('service', options.service);\n if (options.level) params.append('level', options.level);\n\n const url = `${this.apiUrl}/api/v1/logs/stream?${params.toString()}`;\n\n const eventSource = new EventSource(url);\n\n eventSource.addEventListener('log', (event: Event) => {\n try {\n const messageEvent = event as MessageEvent;\n const log = JSON.parse(messageEvent.data) as InternalLogEntry;\n options.onLog(log);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n options.onError?.(err);\n }\n });\n\n eventSource.addEventListener('error', () => {\n const error = new Error('SSE connection error');\n options.onError?.(error);\n });\n\n // Return cleanup function\n return () => {\n eventSource.close();\n };\n }\n\n // ==================== Metrics ====================\n\n getMetrics(): ClientMetrics {\n return { ...this.metrics };\n }\n\n resetMetrics() {\n this.metrics = {\n logsSent: 0,\n logsDropped: 0,\n errors: 0,\n retries: 0,\n avgLatencyMs: 0,\n circuitBreakerTrips: 0,\n };\n this.latencies = [];\n }\n\n getCircuitBreakerState(): string {\n return this.circuitBreaker.getState();\n }\n\n // ==================== Cleanup ====================\n\n async close() {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.stopConsoleInterception();\n await this.flush();\n }\n}\n\nexport default LogTideClient;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logtide/sdk-node",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Official Node.js SDK for LogTide (logtide.dev) - Self-hosted log management with advanced features: retry logic, circuit breaker, query API, live streaming, and middleware support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",