@logtide/sdk-node 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Polliog
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,561 @@
1
+ # LogTide Node.js SDK
2
+
3
+ Official Node.js SDK for LogTide with advanced features: retry logic, circuit breaker, query API, live streaming, and middleware support.
4
+
5
+ ## Features
6
+
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
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @logtide/sdk-node
24
+ # or
25
+ pnpm add @logtide/sdk-node
26
+ # or
27
+ yarn add @logtide/sdk-node
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```typescript
33
+ import { LogTideClient } from '@logtide/sdk-node';
34
+
35
+ const client = new LogTideClient({
36
+ apiUrl: 'http://localhost:8080',
37
+ apiKey: 'lp_your_api_key_here',
38
+ });
39
+
40
+ // Send logs
41
+ client.info('api-gateway', 'Server started', { port: 3000 });
42
+ client.error('database', 'Connection failed', new Error('Timeout'));
43
+
44
+ // Graceful shutdown
45
+ process.on('SIGINT', async () => {
46
+ await client.close();
47
+ process.exit(0);
48
+ });
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Configuration Options
54
+
55
+ ### Basic Options
56
+
57
+ | Option | Type | Default | Description |
58
+ |--------|------|---------|-------------|
59
+ | `apiUrl` | `string` | **required** | Base URL of your LogTide instance |
60
+ | `apiKey` | `string` | **required** | Project API key (starts with `lp_`) |
61
+ | `batchSize` | `number` | `100` | Number of logs to batch before sending |
62
+ | `flushInterval` | `number` | `5000` | Interval in ms to auto-flush logs |
63
+
64
+ ### Advanced Options
65
+
66
+ | Option | Type | Default | Description |
67
+ |--------|------|---------|-------------|
68
+ | `maxBufferSize` | `number` | `10000` | Max logs in buffer (prevents memory leak) |
69
+ | `maxRetries` | `number` | `3` | Max retry attempts on failure |
70
+ | `retryDelayMs` | `number` | `1000` | Initial retry delay (exponential backoff) |
71
+ | `circuitBreakerThreshold` | `number` | `5` | Failures before opening circuit |
72
+ | `circuitBreakerResetMs` | `number` | `30000` | Time before retrying after circuit opens |
73
+ | `enableMetrics` | `boolean` | `true` | Track internal metrics |
74
+ | `debug` | `boolean` | `false` | Enable debug logging to console |
75
+ | `globalMetadata` | `object` | `{}` | Metadata added to all logs |
76
+ | `autoTraceId` | `boolean` | `false` | Auto-generate trace IDs for logs |
77
+
78
+ ### Example: Full Configuration
79
+
80
+ ```typescript
81
+ const client = new LogTideClient({
82
+ apiUrl: 'http://localhost:8080',
83
+ apiKey: 'lp_your_api_key_here',
84
+
85
+ // Batching
86
+ batchSize: 100,
87
+ flushInterval: 5000,
88
+
89
+ // Buffer management
90
+ maxBufferSize: 10000,
91
+
92
+ // Retry with exponential backoff (1s → 2s → 4s)
93
+ maxRetries: 3,
94
+ retryDelayMs: 1000,
95
+
96
+ // Circuit breaker
97
+ circuitBreakerThreshold: 5,
98
+ circuitBreakerResetMs: 30000,
99
+
100
+ // Metrics & debugging
101
+ enableMetrics: true,
102
+ debug: true,
103
+
104
+ // Global context
105
+ globalMetadata: {
106
+ env: process.env.NODE_ENV,
107
+ version: '1.0.0',
108
+ hostname: process.env.HOSTNAME,
109
+ },
110
+
111
+ // Auto trace IDs
112
+ autoTraceId: false,
113
+ });
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Logging Methods
119
+
120
+ ### Basic Logging
121
+
122
+ ```typescript
123
+ client.debug('service-name', 'Debug message');
124
+ client.info('service-name', 'Info message', { userId: 123 });
125
+ client.warn('service-name', 'Warning message');
126
+ client.error('service-name', 'Error message', { custom: 'data' });
127
+ client.critical('service-name', 'Critical message');
128
+ ```
129
+
130
+ ### Error Logging with Auto-Serialization
131
+
132
+ The SDK automatically serializes `Error` objects:
133
+
134
+ ```typescript
135
+ try {
136
+ throw new Error('Database timeout');
137
+ } catch (error) {
138
+ // Automatically serializes error with stack trace
139
+ client.error('database', 'Query failed', error);
140
+ }
141
+ ```
142
+
143
+ Generated log metadata:
144
+ ```json
145
+ {
146
+ "error": {
147
+ "name": "Error",
148
+ "message": "Database timeout",
149
+ "stack": "Error: Database timeout\n at ..."
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### Custom Log Entry
155
+
156
+ ```typescript
157
+ client.log({
158
+ service: 'custom-service',
159
+ level: 'info',
160
+ message: 'Custom log',
161
+ time: new Date().toISOString(), // Optional
162
+ metadata: { key: 'value' },
163
+ trace_id: 'custom-trace-id', // Optional
164
+ });
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Trace ID Context
170
+
171
+ Track requests across services with trace IDs.
172
+
173
+ ### Manual Trace ID
174
+
175
+ ```typescript
176
+ client.setTraceId('request-123');
177
+
178
+ client.info('api', 'Request received');
179
+ client.info('database', 'Querying users');
180
+ client.info('api', 'Response sent');
181
+
182
+ client.setTraceId(null); // Clear context
183
+ ```
184
+
185
+ ### Scoped Trace ID
186
+
187
+ ```typescript
188
+ client.withTraceId('request-456', () => {
189
+ client.info('api', 'Processing in context');
190
+ client.warn('cache', 'Cache miss');
191
+ });
192
+ // Trace ID automatically restored after block
193
+ ```
194
+
195
+ ### Auto-Generated Trace ID
196
+
197
+ ```typescript
198
+ client.withNewTraceId(() => {
199
+ client.info('worker', 'Background job started');
200
+ client.info('worker', 'Job completed');
201
+ });
202
+ ```
203
+
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
+ ---
215
+
216
+ ## Query API
217
+
218
+ Search and retrieve logs programmatically.
219
+
220
+ ### Basic Query
221
+
222
+ ```typescript
223
+ const result = await client.query({
224
+ service: 'api-gateway',
225
+ level: 'error',
226
+ from: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24h
227
+ to: new Date(),
228
+ limit: 100,
229
+ offset: 0,
230
+ });
231
+
232
+ console.log(`Found ${result.total} logs`);
233
+ console.log(result.logs);
234
+ ```
235
+
236
+ ### Full-Text Search
237
+
238
+ ```typescript
239
+ const result = await client.query({
240
+ q: 'timeout',
241
+ limit: 50,
242
+ });
243
+ ```
244
+
245
+ ### Get Logs by Trace ID
246
+
247
+ ```typescript
248
+ const logs = await client.getByTraceId('trace-123');
249
+ console.log(`Trace has ${logs.length} logs`);
250
+ ```
251
+
252
+ ### Aggregated Statistics
253
+
254
+ ```typescript
255
+ const stats = await client.getAggregatedStats({
256
+ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
257
+ to: new Date(),
258
+ interval: '1h', // '1m' | '5m' | '1h' | '1d'
259
+ service: 'api-gateway', // Optional
260
+ });
261
+
262
+ console.log(stats.timeseries); // Time-bucketed counts
263
+ console.log(stats.top_services); // Top services by log count
264
+ console.log(stats.top_errors); // Most common errors
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Live Tail (Streaming)
270
+
271
+ Stream logs in real-time using Server-Sent Events.
272
+
273
+ ```typescript
274
+ const cleanup = client.stream({
275
+ service: 'api-gateway', // Optional filter
276
+ level: 'error', // Optional filter
277
+
278
+ onLog: (log) => {
279
+ console.log(`[${log.time}] ${log.level}: ${log.message}`);
280
+ },
281
+
282
+ onError: (error) => {
283
+ console.error('Stream error:', error);
284
+ },
285
+ });
286
+
287
+ // Stop streaming when done
288
+ setTimeout(() => {
289
+ cleanup();
290
+ }, 60000);
291
+ ```
292
+
293
+ ---
294
+
295
+ ## Metrics
296
+
297
+ Track SDK performance and health.
298
+
299
+ ```typescript
300
+ const metrics = client.getMetrics();
301
+
302
+ console.log(metrics.logsSent); // Total logs sent
303
+ console.log(metrics.logsDropped); // Logs dropped (buffer full)
304
+ console.log(metrics.errors); // Send errors
305
+ console.log(metrics.retries); // Retry attempts
306
+ console.log(metrics.avgLatencyMs); // Average send latency
307
+ console.log(metrics.circuitBreakerTrips); // Circuit breaker openings
308
+
309
+ // Get circuit breaker state
310
+ console.log(client.getCircuitBreakerState()); // 'CLOSED' | 'OPEN' | 'HALF_OPEN'
311
+
312
+ // Reset metrics
313
+ client.resetMetrics();
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Middleware
319
+
320
+ ### Express Middleware
321
+
322
+ Auto-log all HTTP requests and responses.
323
+
324
+ ```typescript
325
+ import express from 'express';
326
+ import { LogTideClient, logTideMiddleware } from '@logtide/sdk-node';
327
+
328
+ const app = express();
329
+ const logger = new LogTideClient({
330
+ apiUrl: 'http://localhost:8080',
331
+ apiKey: 'lp_your_api_key_here',
332
+ });
333
+
334
+ app.use(
335
+ logTideMiddleware({
336
+ client: logger,
337
+ serviceName: 'express-api',
338
+ logRequests: true,
339
+ logResponses: true,
340
+ logErrors: true,
341
+ includeHeaders: false,
342
+ includeBody: false,
343
+ skipHealthCheck: true,
344
+ skipPaths: ['/metrics'],
345
+ }),
346
+ );
347
+
348
+ app.get('/', (req, res) => {
349
+ res.json({ message: 'Hello' });
350
+ });
351
+
352
+ app.listen(3000);
353
+ ```
354
+
355
+ **Logged automatically:**
356
+ - Request: `GET /users/123`
357
+ - Response: `GET /users/123 200 (45ms)`
358
+ - Errors: `Request error: Internal Server Error`
359
+
360
+ ### Fastify Plugin
361
+
362
+ ```typescript
363
+ import Fastify from 'fastify';
364
+ import { LogTideClient, logTideFastifyPlugin } from '@logtide/sdk-node';
365
+
366
+ const fastify = Fastify();
367
+ const logger = new LogTideClient({
368
+ apiUrl: 'http://localhost:8080',
369
+ apiKey: 'lp_your_api_key_here',
370
+ });
371
+
372
+ await fastify.register(logTideFastifyPlugin, {
373
+ client: logger,
374
+ serviceName: 'fastify-api',
375
+ logRequests: true,
376
+ logResponses: true,
377
+ logErrors: true,
378
+ skipHealthCheck: true,
379
+ });
380
+
381
+ fastify.get('/', async () => ({ message: 'Hello' }));
382
+
383
+ await fastify.listen({ port: 3000 });
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Best Practices
389
+
390
+ ### 1. Always Close on Shutdown
391
+
392
+ ```typescript
393
+ process.on('SIGINT', async () => {
394
+ await client.close(); // Flushes buffered logs
395
+ process.exit(0);
396
+ });
397
+
398
+ process.on('SIGTERM', async () => {
399
+ await client.close();
400
+ process.exit(0);
401
+ });
402
+ ```
403
+
404
+ ### 2. Use Global Metadata
405
+
406
+ ```typescript
407
+ const client = new LogTideClient({
408
+ apiUrl: 'http://localhost:8080',
409
+ apiKey: 'lp_your_api_key_here',
410
+ globalMetadata: {
411
+ env: process.env.NODE_ENV,
412
+ version: require('./package.json').version,
413
+ region: process.env.AWS_REGION,
414
+ pod: process.env.HOSTNAME,
415
+ },
416
+ });
417
+ ```
418
+
419
+ ### 3. Enable Debug Mode in Development
420
+
421
+ ```typescript
422
+ const client = new LogTideClient({
423
+ apiUrl: 'http://localhost:8080',
424
+ apiKey: 'lp_your_api_key_here',
425
+ debug: process.env.NODE_ENV === 'development',
426
+ });
427
+ ```
428
+
429
+ ### 4. Monitor Metrics in Production
430
+
431
+ ```typescript
432
+ setInterval(() => {
433
+ const metrics = client.getMetrics();
434
+
435
+ if (metrics.logsDropped > 0) {
436
+ console.warn(`Logs dropped: ${metrics.logsDropped}`);
437
+ }
438
+
439
+ if (metrics.circuitBreakerTrips > 0) {
440
+ console.error('Circuit breaker is OPEN!');
441
+ }
442
+ }, 60000);
443
+ ```
444
+
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
+ ---
512
+
513
+ ## TypeScript Support
514
+
515
+ Fully typed with strict TypeScript support:
516
+
517
+ ```typescript
518
+ import type {
519
+ LogTideClient,
520
+ LogEntry,
521
+ QueryOptions,
522
+ LogsResponse,
523
+ ClientMetrics,
524
+ } from '@logtide/sdk-node';
525
+ ```
526
+
527
+ ---
528
+
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
+ ```
543
+
544
+ ---
545
+
546
+ ## License
547
+
548
+ MIT
549
+
550
+ ---
551
+
552
+ ## Contributing
553
+
554
+ Contributions are welcome! Please open an issue or PR on [GitHub](https://github.com/logtide/logtide-sdk-node).
555
+
556
+ ---
557
+
558
+ ## Support
559
+
560
+ - **Documentation**: [https://logtide.dev/docs](https://logtide.dev/docs)
561
+ - **Issues**: [GitHub Issues](https://github.com/logtide/logtide-sdk-node/issues)