@logtide/sdk-node 0.1.1 → 0.2.1
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 +53 -121
- package/dist/index.cjs +229 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -2
- package/dist/index.d.ts +58 -2
- package/dist/index.js +229 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,21 +1,36 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
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
|
|
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(),
|
|
176
|
+
time: new Date().toISOString(),
|
|
162
177
|
metadata: { key: 'value' },
|
|
163
|
-
trace_id: 'custom-trace-id',
|
|
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
|
-
##
|
|
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
|
-
##
|
|
489
|
+
## Links
|
|
559
490
|
|
|
560
|
-
-
|
|
561
|
-
-
|
|
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,11 @@ var LogTideClient = class {
|
|
|
108
89
|
latencies = [];
|
|
109
90
|
// Context tracking
|
|
110
91
|
currentTraceId = null;
|
|
92
|
+
// Console interception
|
|
93
|
+
consoleInterceptOptions = null;
|
|
94
|
+
originalConsole = null;
|
|
95
|
+
// Payload limits
|
|
96
|
+
payloadLimits;
|
|
111
97
|
constructor(options) {
|
|
112
98
|
this.apiUrl = options.apiUrl.replace(/\/$/, "");
|
|
113
99
|
this.apiKey = options.apiKey;
|
|
@@ -124,15 +110,25 @@ var LogTideClient = class {
|
|
|
124
110
|
options.circuitBreakerThreshold || 5,
|
|
125
111
|
options.circuitBreakerResetMs || 3e4
|
|
126
112
|
);
|
|
113
|
+
this.payloadLimits = {
|
|
114
|
+
maxFieldSize: options.payloadLimits?.maxFieldSize ?? 10 * 1024,
|
|
115
|
+
// 10KB
|
|
116
|
+
maxLogSize: options.payloadLimits?.maxLogSize ?? 100 * 1024,
|
|
117
|
+
// 100KB
|
|
118
|
+
excludeFields: options.payloadLimits?.excludeFields ?? [],
|
|
119
|
+
truncationMarker: options.payloadLimits?.truncationMarker ?? "...[TRUNCATED]"
|
|
120
|
+
};
|
|
127
121
|
this.startFlushTimer();
|
|
122
|
+
if (options.interceptConsole?.enabled) {
|
|
123
|
+
this.startConsoleInterception(options.interceptConsole);
|
|
124
|
+
}
|
|
128
125
|
}
|
|
129
126
|
// ==================== Context Helpers ====================
|
|
130
127
|
/**
|
|
131
128
|
* Set trace ID for subsequent logs
|
|
132
|
-
* Automatically validates and normalizes to UUID v4
|
|
133
129
|
*/
|
|
134
130
|
setTraceId(traceId) {
|
|
135
|
-
this.currentTraceId =
|
|
131
|
+
this.currentTraceId = traceId;
|
|
136
132
|
}
|
|
137
133
|
/**
|
|
138
134
|
* Get current trace ID
|
|
@@ -158,6 +154,207 @@ var LogTideClient = class {
|
|
|
158
154
|
withNewTraceId(fn) {
|
|
159
155
|
return this.withTraceId(crypto.randomUUID(), fn);
|
|
160
156
|
}
|
|
157
|
+
// ==================== Console Interception ====================
|
|
158
|
+
/**
|
|
159
|
+
* Start intercepting console methods and forward them to LogTide
|
|
160
|
+
*/
|
|
161
|
+
startConsoleInterception(options) {
|
|
162
|
+
if (this.originalConsole) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const config = {
|
|
166
|
+
enabled: true,
|
|
167
|
+
service: options?.service ?? "console",
|
|
168
|
+
preserveOriginal: options?.preserveOriginal ?? true,
|
|
169
|
+
includeStackTrace: options?.includeStackTrace ?? false,
|
|
170
|
+
levels: {
|
|
171
|
+
log: options?.levels?.log ?? true,
|
|
172
|
+
info: options?.levels?.info ?? true,
|
|
173
|
+
warn: options?.levels?.warn ?? true,
|
|
174
|
+
error: options?.levels?.error ?? true,
|
|
175
|
+
debug: options?.levels?.debug ?? true
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
this.consoleInterceptOptions = config;
|
|
179
|
+
this.originalConsole = {
|
|
180
|
+
log: console.log.bind(console),
|
|
181
|
+
info: console.info.bind(console),
|
|
182
|
+
warn: console.warn.bind(console),
|
|
183
|
+
error: console.error.bind(console),
|
|
184
|
+
debug: console.debug.bind(console)
|
|
185
|
+
};
|
|
186
|
+
const createInterceptor = (method, level) => {
|
|
187
|
+
const original = this.originalConsole[method];
|
|
188
|
+
return (...args) => {
|
|
189
|
+
if (config.preserveOriginal) {
|
|
190
|
+
original(...args);
|
|
191
|
+
}
|
|
192
|
+
if (!config.levels?.[method]) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const message = args.map((arg) => {
|
|
196
|
+
if (typeof arg === "string") return arg;
|
|
197
|
+
if (arg instanceof Error) return arg.message;
|
|
198
|
+
try {
|
|
199
|
+
return JSON.stringify(arg);
|
|
200
|
+
} catch {
|
|
201
|
+
return String(arg);
|
|
202
|
+
}
|
|
203
|
+
}).join(" ");
|
|
204
|
+
if (message.startsWith("[LogTide]")) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const metadata = {
|
|
208
|
+
source: "console",
|
|
209
|
+
originalMethod: method
|
|
210
|
+
};
|
|
211
|
+
if (config.includeStackTrace) {
|
|
212
|
+
const stack = new Error().stack;
|
|
213
|
+
if (stack) {
|
|
214
|
+
const stackLines = stack.split("\n").slice(2);
|
|
215
|
+
metadata.stackTrace = stackLines.join("\n");
|
|
216
|
+
const callerLine = stackLines[0];
|
|
217
|
+
if (callerLine) {
|
|
218
|
+
const match = callerLine.match(/at\s+(.+?)\s+\((.+):(\d+):(\d+)\)/);
|
|
219
|
+
if (match) {
|
|
220
|
+
metadata.caller = {
|
|
221
|
+
function: match[1],
|
|
222
|
+
file: match[2],
|
|
223
|
+
line: parseInt(match[3], 10),
|
|
224
|
+
column: parseInt(match[4], 10)
|
|
225
|
+
};
|
|
226
|
+
} else {
|
|
227
|
+
const altMatch = callerLine.match(/at\s+(.+):(\d+):(\d+)/);
|
|
228
|
+
if (altMatch) {
|
|
229
|
+
metadata.caller = {
|
|
230
|
+
file: altMatch[1],
|
|
231
|
+
line: parseInt(altMatch[2], 10),
|
|
232
|
+
column: parseInt(altMatch[3], 10)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (args.length > 1 || args.length === 1 && typeof args[0] !== "string") {
|
|
240
|
+
metadata.args = args.map((arg) => {
|
|
241
|
+
if (arg instanceof Error) {
|
|
242
|
+
return serializeError(arg);
|
|
243
|
+
}
|
|
244
|
+
return arg;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
this.log({
|
|
248
|
+
service: config.service,
|
|
249
|
+
level,
|
|
250
|
+
message,
|
|
251
|
+
metadata
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
console.log = createInterceptor("log", "info");
|
|
256
|
+
console.info = createInterceptor("info", "info");
|
|
257
|
+
console.warn = createInterceptor("warn", "warn");
|
|
258
|
+
console.error = createInterceptor("error", "error");
|
|
259
|
+
console.debug = createInterceptor("debug", "debug");
|
|
260
|
+
if (this.debugMode) {
|
|
261
|
+
this.originalConsole.log("[LogTide] Console interception started");
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Stop intercepting console methods and restore originals
|
|
266
|
+
*/
|
|
267
|
+
stopConsoleInterception() {
|
|
268
|
+
if (!this.originalConsole) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
console.log = this.originalConsole.log;
|
|
272
|
+
console.info = this.originalConsole.info;
|
|
273
|
+
console.warn = this.originalConsole.warn;
|
|
274
|
+
console.error = this.originalConsole.error;
|
|
275
|
+
console.debug = this.originalConsole.debug;
|
|
276
|
+
if (this.debugMode) {
|
|
277
|
+
console.log("[LogTide] Console interception stopped");
|
|
278
|
+
}
|
|
279
|
+
this.originalConsole = null;
|
|
280
|
+
this.consoleInterceptOptions = null;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Check if console interception is active
|
|
284
|
+
*/
|
|
285
|
+
isConsoleInterceptionActive() {
|
|
286
|
+
return this.originalConsole !== null;
|
|
287
|
+
}
|
|
288
|
+
// ==================== Payload Processing ====================
|
|
289
|
+
/**
|
|
290
|
+
* Check if a string looks like base64 encoded data
|
|
291
|
+
*/
|
|
292
|
+
looksLikeBase64(str) {
|
|
293
|
+
if (typeof str !== "string" || str.length < 100) return false;
|
|
294
|
+
if (str.startsWith("data:")) return true;
|
|
295
|
+
const base64Regex = /^[A-Za-z0-9+/=]{100,}$/;
|
|
296
|
+
return base64Regex.test(str.replace(/\s/g, ""));
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Process a value for payload limits (truncation, base64 removal, etc.)
|
|
300
|
+
*/
|
|
301
|
+
processValue(value, fieldPath) {
|
|
302
|
+
const fieldName = fieldPath.split(".").pop() || fieldPath;
|
|
303
|
+
if (this.payloadLimits.excludeFields.includes(fieldName)) {
|
|
304
|
+
return "[EXCLUDED]";
|
|
305
|
+
}
|
|
306
|
+
if (value === null || value === void 0) {
|
|
307
|
+
return value;
|
|
308
|
+
}
|
|
309
|
+
if (typeof value === "string") {
|
|
310
|
+
if (this.looksLikeBase64(value)) {
|
|
311
|
+
return "[BASE64 DATA REMOVED]";
|
|
312
|
+
}
|
|
313
|
+
if (value.length > this.payloadLimits.maxFieldSize) {
|
|
314
|
+
return value.substring(0, this.payloadLimits.maxFieldSize) + this.payloadLimits.truncationMarker;
|
|
315
|
+
}
|
|
316
|
+
return value;
|
|
317
|
+
}
|
|
318
|
+
if (Array.isArray(value)) {
|
|
319
|
+
return value.map((item, index) => this.processValue(item, `${fieldPath}[${index}]`));
|
|
320
|
+
}
|
|
321
|
+
if (typeof value === "object") {
|
|
322
|
+
const processed = {};
|
|
323
|
+
for (const [key, val] of Object.entries(value)) {
|
|
324
|
+
processed[key] = this.processValue(val, `${fieldPath}.${key}`);
|
|
325
|
+
}
|
|
326
|
+
return processed;
|
|
327
|
+
}
|
|
328
|
+
return value;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Process metadata to apply payload limits
|
|
332
|
+
*/
|
|
333
|
+
processMetadata(metadata) {
|
|
334
|
+
if (!metadata) return metadata;
|
|
335
|
+
return this.processValue(metadata, "metadata");
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Ensure log entry doesn't exceed max size
|
|
339
|
+
*/
|
|
340
|
+
enforceMaxLogSize(entry) {
|
|
341
|
+
const serialized = JSON.stringify(entry);
|
|
342
|
+
if (serialized.length <= this.payloadLimits.maxLogSize) {
|
|
343
|
+
return entry;
|
|
344
|
+
}
|
|
345
|
+
if (this.debugMode) {
|
|
346
|
+
console.warn(`[LogTide] Log entry too large (${serialized.length} bytes), truncating metadata`);
|
|
347
|
+
}
|
|
348
|
+
const truncated = {
|
|
349
|
+
...entry,
|
|
350
|
+
metadata: {
|
|
351
|
+
_truncated: true,
|
|
352
|
+
_originalSize: serialized.length,
|
|
353
|
+
message: entry.message
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
return truncated;
|
|
357
|
+
}
|
|
161
358
|
// ==================== Logging Methods ====================
|
|
162
359
|
startFlushTimer() {
|
|
163
360
|
this.timer = setInterval(() => {
|
|
@@ -172,16 +369,19 @@ var LogTideClient = class {
|
|
|
172
369
|
}
|
|
173
370
|
return;
|
|
174
371
|
}
|
|
175
|
-
const
|
|
176
|
-
const
|
|
372
|
+
const traceId = entry.trace_id || this.currentTraceId || (this.autoTraceId ? crypto.randomUUID() : void 0);
|
|
373
|
+
const mergedMetadata = {
|
|
374
|
+
...this.globalMetadata,
|
|
375
|
+
...entry.metadata
|
|
376
|
+
};
|
|
377
|
+
const processedMetadata = this.processMetadata(mergedMetadata);
|
|
378
|
+
let internalEntry = {
|
|
177
379
|
...entry,
|
|
178
380
|
time: entry.time || (/* @__PURE__ */ new Date()).toISOString(),
|
|
179
|
-
metadata:
|
|
180
|
-
|
|
181
|
-
...entry.metadata
|
|
182
|
-
},
|
|
183
|
-
trace_id: normalizedTraceId
|
|
381
|
+
metadata: processedMetadata,
|
|
382
|
+
trace_id: traceId
|
|
184
383
|
};
|
|
384
|
+
internalEntry = this.enforceMaxLogSize(internalEntry);
|
|
185
385
|
this.buffer.push(internalEntry);
|
|
186
386
|
if (this.buffer.length >= this.batchSize) {
|
|
187
387
|
this.flush();
|
|
@@ -396,6 +596,7 @@ var LogTideClient = class {
|
|
|
396
596
|
clearInterval(this.timer);
|
|
397
597
|
this.timer = null;
|
|
398
598
|
}
|
|
599
|
+
this.stopConsoleInterception();
|
|
399
600
|
await this.flush();
|
|
400
601
|
}
|
|
401
602
|
};
|