vedatrace 0.1.8 → 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 +25 -5
- package/dist/index.cjs +310 -61
- package/dist/index.d.cts +126 -49
- package/dist/index.d.mts +126 -49
- package/dist/index.mjs +305 -63
- package/dist/integrations/express.d.cts +1 -1
- package/dist/integrations/express.d.mts +1 -1
- package/dist/integrations/nextjs.d.cts +1 -1
- package/dist/integrations/nextjs.d.mts +1 -1
- package/dist/integrations/react.cjs +1 -2
- package/dist/integrations/react.d.cts +1 -1
- package/dist/integrations/react.d.mts +1 -1
- package/dist/integrations/react.mjs +1 -2
- package/dist/transports/index.cjs +26 -1
- package/dist/transports/index.d.cts +23 -6
- package/dist/transports/index.d.mts +23 -6
- package/dist/transports/index.mjs +26 -2
- package/dist/{types-CcdFb-vY.d.cts → types-BU0UESs9.d.cts} +25 -41
- package/dist/{types-CcdFb-vY.d.mts → types-BU0UESs9.d.mts} +25 -41
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -72,6 +72,10 @@ const logger = vedatrace({
|
|
|
72
72
|
mask: '[REDACTED]'
|
|
73
73
|
},
|
|
74
74
|
|
|
75
|
+
// Advanced
|
|
76
|
+
immediateFlush: false, // Flush on each log (dev mode, edge runtimes)
|
|
77
|
+
runtime: 'auto', // Force runtime: 'node' | 'browser' | 'cloudflare' | 'deno' | 'bun'
|
|
78
|
+
|
|
75
79
|
// Callbacks
|
|
76
80
|
onError: (err) => console.error('VedaTrace error:', err),
|
|
77
81
|
onSuccess: () => console.log('Logs sent')
|
|
@@ -174,13 +178,15 @@ function MyComponent() {
|
|
|
174
178
|
```typescript
|
|
175
179
|
import { vedatrace } from 'vedatrace'
|
|
176
180
|
|
|
181
|
+
// Works seamlessly - no special configuration needed
|
|
182
|
+
// Timer starts automatically on first log (in handler context)
|
|
183
|
+
const logger = vedatrace({
|
|
184
|
+
apiKey: env.VEDATRACE_API_KEY,
|
|
185
|
+
service: 'worker'
|
|
186
|
+
})
|
|
187
|
+
|
|
177
188
|
export default {
|
|
178
189
|
async fetch(req, env, ctx) {
|
|
179
|
-
const logger = vedatrace({
|
|
180
|
-
apiKey: env.VEDATRACE_API_KEY,
|
|
181
|
-
service: 'worker'
|
|
182
|
-
})
|
|
183
|
-
|
|
184
190
|
logger.info('Request received', {
|
|
185
191
|
method: req.method,
|
|
186
192
|
url: req.url
|
|
@@ -194,6 +200,8 @@ export default {
|
|
|
194
200
|
}
|
|
195
201
|
```
|
|
196
202
|
|
|
203
|
+
The SDK automatically detects edge runtimes (Cloudflare Workers, Deno, Bun) and uses lazy timer initialization - the flush timer starts on the first log call, which happens inside your handler where async I/O is allowed.
|
|
204
|
+
|
|
197
205
|
## Advanced Usage
|
|
198
206
|
|
|
199
207
|
### Custom Transports
|
|
@@ -308,6 +316,18 @@ Manually flush pending logs. Returns a Promise.
|
|
|
308
316
|
|
|
309
317
|
Stop the background flush timer. Call this for explicit cleanup in long-running processes or before shutdown.
|
|
310
318
|
|
|
319
|
+
### `logger.start()`
|
|
320
|
+
|
|
321
|
+
Manually start the flush timer. Usually not needed - the timer starts automatically on first log. Useful if you want to ensure the timer is running before any logs are sent.
|
|
322
|
+
|
|
323
|
+
### `logger.runtime`
|
|
324
|
+
|
|
325
|
+
Get the detected runtime environment. Returns: `'node' | 'browser' | 'cloudflare' | 'deno' | 'bun' | 'edge'`
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
console.log(logger.runtime) // 'cloudflare' when running in Workers
|
|
329
|
+
```
|
|
330
|
+
|
|
311
331
|
## License
|
|
312
332
|
|
|
313
333
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -5,26 +5,60 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var transports_index = require('./transports/index.cjs');
|
|
6
6
|
|
|
7
7
|
class VedaTraceBatcher {
|
|
8
|
-
constructor(transports, config,
|
|
8
|
+
constructor(transports, config, immediateFlush = false) {
|
|
9
9
|
this.transports = transports;
|
|
10
10
|
this.config = config;
|
|
11
|
-
this.onError = onError;
|
|
12
|
-
this.onSuccess = onSuccess;
|
|
13
11
|
this.immediateFlush = immediateFlush;
|
|
14
|
-
this.
|
|
12
|
+
this.context = config.executionContext;
|
|
15
13
|
}
|
|
16
14
|
queue = [];
|
|
17
15
|
flushTimer = null;
|
|
16
|
+
flushDebounceTimer = null;
|
|
18
17
|
isFlushing = false;
|
|
19
18
|
pendingFlush = null;
|
|
20
|
-
|
|
19
|
+
context;
|
|
20
|
+
/** Attach execution context after initialization */
|
|
21
|
+
setContext(ctx) {
|
|
22
|
+
this.context = ctx;
|
|
23
|
+
}
|
|
24
|
+
/** Get current context */
|
|
25
|
+
getContext() {
|
|
26
|
+
return this.context;
|
|
27
|
+
}
|
|
28
|
+
/** Add log to queue with context-aware flush */
|
|
21
29
|
add(log) {
|
|
22
30
|
this.queue.push(log);
|
|
23
|
-
if (this.
|
|
31
|
+
if (!this.flushTimer && !this.immediateFlush) {
|
|
32
|
+
this.startFlushTimer();
|
|
33
|
+
}
|
|
34
|
+
if (this.immediateFlush || this.context) {
|
|
35
|
+
this.debouncedFlush();
|
|
36
|
+
} else if (this.queue.length >= this.config.batchSize) {
|
|
24
37
|
this.flush();
|
|
25
38
|
}
|
|
26
39
|
}
|
|
27
|
-
/**
|
|
40
|
+
/** Debounced flush - prevents rapid-fire flushes */
|
|
41
|
+
debouncedFlush() {
|
|
42
|
+
if (this.flushDebounceTimer) {
|
|
43
|
+
clearTimeout(this.flushDebounceTimer);
|
|
44
|
+
}
|
|
45
|
+
this.flushDebounceTimer = setTimeout(() => {
|
|
46
|
+
this.flushDebounceTimer = null;
|
|
47
|
+
this.flush().catch((error) => {
|
|
48
|
+
if (this.config.onError) {
|
|
49
|
+
this.config.onError(
|
|
50
|
+
error instanceof Error ? error : new Error(String(error))
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
console.error(
|
|
54
|
+
"[VedaTrace] Debounced flush error:",
|
|
55
|
+
error instanceof Error ? error.message : String(error)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}, 100);
|
|
60
|
+
}
|
|
61
|
+
/** Flush logs to all transports with waitUntil protection */
|
|
28
62
|
async flush() {
|
|
29
63
|
if (this.isFlushing) {
|
|
30
64
|
return this.pendingFlush ?? Promise.resolve();
|
|
@@ -35,13 +69,16 @@ class VedaTraceBatcher {
|
|
|
35
69
|
this.isFlushing = true;
|
|
36
70
|
const logsToSend = [...this.queue];
|
|
37
71
|
this.queue = [];
|
|
38
|
-
|
|
72
|
+
const flushPromise = this.sendWithRetry(logsToSend).finally(() => {
|
|
39
73
|
this.isFlushing = false;
|
|
40
74
|
this.pendingFlush = null;
|
|
41
75
|
});
|
|
42
|
-
|
|
76
|
+
this.pendingFlush = flushPromise;
|
|
77
|
+
if (this.context) {
|
|
78
|
+
this.context.waitUntil(flushPromise);
|
|
79
|
+
}
|
|
80
|
+
return flushPromise;
|
|
43
81
|
}
|
|
44
|
-
/** Send logs with retry logic */
|
|
45
82
|
async sendWithRetry(logs, attempt = 0) {
|
|
46
83
|
const errors = [];
|
|
47
84
|
for (const transport of this.transports) {
|
|
@@ -59,16 +96,17 @@ class VedaTraceBatcher {
|
|
|
59
96
|
const combinedError = new Error(
|
|
60
97
|
`Failed to send logs after ${this.config.maxRetries} retries: ${errors.map((e) => e.message).join(", ")}`
|
|
61
98
|
);
|
|
62
|
-
if (this.onError) {
|
|
63
|
-
this.onError(combinedError);
|
|
99
|
+
if (this.config.onError) {
|
|
100
|
+
this.config.onError(combinedError);
|
|
64
101
|
} else {
|
|
65
102
|
console.error("[VedaTrace]", combinedError.message);
|
|
66
103
|
}
|
|
67
104
|
return;
|
|
68
105
|
}
|
|
69
|
-
this.onSuccess
|
|
106
|
+
if (this.config.onSuccess) {
|
|
107
|
+
this.config.onSuccess();
|
|
108
|
+
}
|
|
70
109
|
}
|
|
71
|
-
/** Start the flush interval timer */
|
|
72
110
|
startFlushTimer() {
|
|
73
111
|
if (this.flushTimer) {
|
|
74
112
|
clearInterval(this.flushTimer);
|
|
@@ -76,8 +114,8 @@ class VedaTraceBatcher {
|
|
|
76
114
|
this.flushTimer = setInterval(() => {
|
|
77
115
|
if (this.queue.length > 0) {
|
|
78
116
|
this.flush().catch((error) => {
|
|
79
|
-
if (this.onError) {
|
|
80
|
-
this.onError(
|
|
117
|
+
if (this.config.onError) {
|
|
118
|
+
this.config.onError(
|
|
81
119
|
error instanceof Error ? error : new Error(String(error))
|
|
82
120
|
);
|
|
83
121
|
} else {
|
|
@@ -93,30 +131,84 @@ class VedaTraceBatcher {
|
|
|
93
131
|
this.flushTimer.unref();
|
|
94
132
|
}
|
|
95
133
|
}
|
|
96
|
-
/** Stop the flush timer */
|
|
97
134
|
stop() {
|
|
98
135
|
if (this.flushTimer) {
|
|
99
136
|
clearInterval(this.flushTimer);
|
|
100
137
|
this.flushTimer = null;
|
|
101
138
|
}
|
|
139
|
+
if (this.flushDebounceTimer) {
|
|
140
|
+
clearTimeout(this.flushDebounceTimer);
|
|
141
|
+
this.flushDebounceTimer = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
start() {
|
|
145
|
+
if (!this.flushTimer && !this.immediateFlush) {
|
|
146
|
+
this.startFlushTimer();
|
|
147
|
+
}
|
|
102
148
|
}
|
|
103
|
-
/** Delay helper */
|
|
104
149
|
delay(ms) {
|
|
105
150
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
106
151
|
}
|
|
107
|
-
/** Get current queue size */
|
|
108
152
|
getQueueSize() {
|
|
109
153
|
return this.queue.length;
|
|
110
154
|
}
|
|
155
|
+
setExecutionContext(ctx) {
|
|
156
|
+
this.context = ctx;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function detectRuntime() {
|
|
161
|
+
if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
|
|
162
|
+
return "cloudflare";
|
|
163
|
+
}
|
|
164
|
+
const g = globalThis;
|
|
165
|
+
if (g?.Deno && g.Deno.version?.deno) {
|
|
166
|
+
return "deno";
|
|
167
|
+
}
|
|
168
|
+
if (g?.Bun) {
|
|
169
|
+
return "bun";
|
|
170
|
+
}
|
|
171
|
+
if (typeof g?.WebSocketPair !== "undefined") {
|
|
172
|
+
return "cloudflare";
|
|
173
|
+
}
|
|
174
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
175
|
+
return "node";
|
|
176
|
+
}
|
|
177
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
178
|
+
return "browser";
|
|
179
|
+
}
|
|
180
|
+
if (typeof fetch !== "undefined" && typeof window === "undefined" && typeof process === "undefined") {
|
|
181
|
+
return "edge";
|
|
182
|
+
}
|
|
183
|
+
return "edge";
|
|
184
|
+
}
|
|
185
|
+
function isEdgeRuntime() {
|
|
186
|
+
const runtime = detectRuntime();
|
|
187
|
+
return runtime === "cloudflare" || runtime === "deno" || runtime === "bun" || runtime === "edge";
|
|
188
|
+
}
|
|
189
|
+
function isServerless() {
|
|
190
|
+
const runtime = detectRuntime();
|
|
191
|
+
return runtime === "cloudflare" || runtime === "edge";
|
|
192
|
+
}
|
|
193
|
+
function isLongRunning() {
|
|
194
|
+
const runtime = detectRuntime();
|
|
195
|
+
return runtime === "node" || runtime === "bun" || runtime === "deno";
|
|
196
|
+
}
|
|
197
|
+
function isBrowser() {
|
|
198
|
+
return detectRuntime() === "browser";
|
|
111
199
|
}
|
|
112
200
|
|
|
113
|
-
const SDK_VERSION = "
|
|
201
|
+
const SDK_VERSION = process.env.npm_package_version ?? "0.0.0";
|
|
114
202
|
class VedaTraceLogger {
|
|
115
203
|
batcher = null;
|
|
204
|
+
runtime;
|
|
116
205
|
config;
|
|
117
206
|
childDefaults;
|
|
207
|
+
_context;
|
|
118
208
|
constructor(config = {}, childDefaults = {}) {
|
|
209
|
+
this.runtime = config.runtime ?? detectRuntime();
|
|
119
210
|
this.childDefaults = childDefaults;
|
|
211
|
+
this._context = config.executionContext;
|
|
120
212
|
this.config = {
|
|
121
213
|
service: config.service,
|
|
122
214
|
apiKey: config.apiKey,
|
|
@@ -126,61 +218,68 @@ class VedaTraceLogger {
|
|
|
126
218
|
flushInterval: config.flushInterval ?? 5e3,
|
|
127
219
|
maxRetries: config.maxRetries ?? 3,
|
|
128
220
|
retryDelay: config.retryDelay ?? 1e3,
|
|
129
|
-
onError: config.onError,
|
|
130
|
-
onSuccess: config.onSuccess,
|
|
131
221
|
debug: config.debug ?? false,
|
|
132
222
|
immediateFlush: config.immediateFlush ?? false,
|
|
133
|
-
unrefTimer: config.unrefTimer
|
|
223
|
+
unrefTimer: config.unrefTimer ?? false
|
|
134
224
|
};
|
|
135
225
|
if (!config.disabled) {
|
|
136
226
|
this.initializeBatcher(config);
|
|
137
227
|
}
|
|
138
228
|
}
|
|
139
|
-
/** Initialize the batcher with transports */
|
|
140
229
|
initializeBatcher(config) {
|
|
141
230
|
const transports = config.transports ?? [];
|
|
142
|
-
if (config.apiKey && transports.length === 0) ;
|
|
143
231
|
if (transports.length > 0) {
|
|
232
|
+
const batcherConfig = {
|
|
233
|
+
batchSize: this.config.batchSize,
|
|
234
|
+
flushInterval: this.config.flushInterval,
|
|
235
|
+
maxRetries: this.config.maxRetries,
|
|
236
|
+
retryDelay: this.config.retryDelay,
|
|
237
|
+
unrefTimer: this.config.unrefTimer,
|
|
238
|
+
executionContext: this._context,
|
|
239
|
+
onError: config.onError,
|
|
240
|
+
onSuccess: config.onSuccess
|
|
241
|
+
};
|
|
144
242
|
this.batcher = new VedaTraceBatcher(
|
|
145
243
|
transports,
|
|
146
|
-
|
|
147
|
-
batchSize: this.config.batchSize,
|
|
148
|
-
flushInterval: this.config.flushInterval,
|
|
149
|
-
maxRetries: this.config.maxRetries,
|
|
150
|
-
retryDelay: this.config.retryDelay,
|
|
151
|
-
unrefTimer: this.config.unrefTimer
|
|
152
|
-
},
|
|
153
|
-
this.config.onError,
|
|
154
|
-
this.config.onSuccess,
|
|
244
|
+
batcherConfig,
|
|
155
245
|
this.config.immediateFlush
|
|
156
246
|
);
|
|
157
247
|
}
|
|
158
248
|
}
|
|
159
|
-
/** Set batcher (called from factory function) */
|
|
160
249
|
setBatcher(batcher) {
|
|
161
250
|
this.batcher = batcher;
|
|
162
251
|
}
|
|
163
|
-
/**
|
|
252
|
+
/** Attach execution context for waitUntil support (Cloudflare Workers / Pages) */
|
|
253
|
+
withContext(ctx) {
|
|
254
|
+
this._context = ctx;
|
|
255
|
+
if (this.batcher) {
|
|
256
|
+
this.batcher.setContext(ctx);
|
|
257
|
+
}
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
/** Check if context is attached */
|
|
261
|
+
hasContext() {
|
|
262
|
+
return this._context !== void 0;
|
|
263
|
+
}
|
|
264
|
+
/** Get current execution context */
|
|
265
|
+
getContext() {
|
|
266
|
+
return this._context;
|
|
267
|
+
}
|
|
164
268
|
debug(message, metadata) {
|
|
165
269
|
this.log("debug", message, metadata);
|
|
166
270
|
}
|
|
167
|
-
/** Log at info level */
|
|
168
271
|
info(message, metadata) {
|
|
169
272
|
this.log("info", message, metadata);
|
|
170
273
|
}
|
|
171
|
-
/** Log at warn level */
|
|
172
274
|
warn(message, metadata) {
|
|
173
275
|
this.log("warn", message, metadata);
|
|
174
276
|
}
|
|
175
|
-
/** Log at error level */
|
|
176
277
|
error(message, metadata) {
|
|
177
278
|
this.log("error", message, metadata);
|
|
178
279
|
}
|
|
179
|
-
/** Log at fatal level */
|
|
180
280
|
fatal(message, metadata) {
|
|
181
281
|
this.log("fatal", message, metadata);
|
|
182
282
|
}
|
|
183
|
-
/** Internal log method */
|
|
184
283
|
log(level, message, metadata) {
|
|
185
284
|
if (!this.batcher) {
|
|
186
285
|
return;
|
|
@@ -195,7 +294,7 @@ class VedaTraceLogger {
|
|
|
195
294
|
timestamp: Date.now(),
|
|
196
295
|
metadata: cleanMetadata,
|
|
197
296
|
_sdk: {
|
|
198
|
-
source:
|
|
297
|
+
source: detectRuntime(),
|
|
199
298
|
version: SDK_VERSION
|
|
200
299
|
}
|
|
201
300
|
};
|
|
@@ -208,7 +307,6 @@ class VedaTraceLogger {
|
|
|
208
307
|
}
|
|
209
308
|
this.batcher.add(logEntry);
|
|
210
309
|
}
|
|
211
|
-
/** Create a child logger with default metadata */
|
|
212
310
|
child(defaults) {
|
|
213
311
|
const mergedDefaults = { ...this.childDefaults, ...defaults };
|
|
214
312
|
const childLogger = new VedaTraceLogger(
|
|
@@ -217,7 +315,8 @@ class VedaTraceLogger {
|
|
|
217
315
|
apiKey: this.config.apiKey,
|
|
218
316
|
endpoint: this.config.endpoint,
|
|
219
317
|
environment: this.config.environment,
|
|
220
|
-
disabled: !this.batcher
|
|
318
|
+
disabled: !this.batcher,
|
|
319
|
+
executionContext: this._context
|
|
221
320
|
},
|
|
222
321
|
mergedDefaults
|
|
223
322
|
);
|
|
@@ -226,27 +325,132 @@ class VedaTraceLogger {
|
|
|
226
325
|
}
|
|
227
326
|
return childLogger;
|
|
228
327
|
}
|
|
229
|
-
/** Flush pending logs */
|
|
230
328
|
async flush() {
|
|
231
329
|
if (this.batcher) {
|
|
232
|
-
|
|
330
|
+
const flushPromise = this.batcher.flush();
|
|
331
|
+
if (this._context) {
|
|
332
|
+
this._context.waitUntil(flushPromise);
|
|
333
|
+
}
|
|
334
|
+
return flushPromise;
|
|
233
335
|
}
|
|
234
336
|
}
|
|
235
|
-
/** Stop the batcher and flush timer */
|
|
236
337
|
stop() {
|
|
237
338
|
if (this.batcher) {
|
|
238
339
|
this.batcher.stop();
|
|
239
340
|
}
|
|
240
341
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return "browser";
|
|
342
|
+
start() {
|
|
343
|
+
if (this.batcher) {
|
|
344
|
+
this.batcher.start();
|
|
245
345
|
}
|
|
246
|
-
|
|
247
|
-
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
class BrowserLifecycle {
|
|
350
|
+
constructor(config) {
|
|
351
|
+
this.config = config;
|
|
352
|
+
this.boundVisibilityHandler = this.handleVisibilityChange.bind(this);
|
|
353
|
+
this.boundPageHideHandler = this.handlePageHide.bind(this);
|
|
354
|
+
this.boundBeforeUnloadHandler = this.handleBeforeUnload.bind(this);
|
|
355
|
+
this.boundUnloadHandler = this.handleUnload.bind(this);
|
|
356
|
+
}
|
|
357
|
+
boundVisibilityHandler;
|
|
358
|
+
boundPageHideHandler;
|
|
359
|
+
boundBeforeUnloadHandler;
|
|
360
|
+
boundUnloadHandler;
|
|
361
|
+
isAttached = false;
|
|
362
|
+
pendingFlush = null;
|
|
363
|
+
/** Start listening for browser lifecycle events */
|
|
364
|
+
attach() {
|
|
365
|
+
if (this.isAttached) return;
|
|
366
|
+
if (typeof document !== "undefined") {
|
|
367
|
+
document.addEventListener("visibilitychange", this.boundVisibilityHandler);
|
|
368
|
+
window.addEventListener("pagehide", this.boundPageHideHandler);
|
|
369
|
+
window.addEventListener("beforeunload", this.boundBeforeUnloadHandler);
|
|
370
|
+
window.addEventListener("unload", this.boundUnloadHandler);
|
|
371
|
+
}
|
|
372
|
+
this.isAttached = true;
|
|
373
|
+
if (this.config.debug) {
|
|
374
|
+
console.log("[VedaTrace] Browser lifecycle handlers attached");
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/** Stop listening for browser lifecycle events */
|
|
378
|
+
detach() {
|
|
379
|
+
if (!this.isAttached) return;
|
|
380
|
+
if (typeof document !== "undefined") {
|
|
381
|
+
document.removeEventListener(
|
|
382
|
+
"visibilitychange",
|
|
383
|
+
this.boundVisibilityHandler
|
|
384
|
+
);
|
|
385
|
+
window.removeEventListener("pagehide", this.boundPageHideHandler);
|
|
386
|
+
window.removeEventListener("beforeunload", this.boundBeforeUnloadHandler);
|
|
387
|
+
window.removeEventListener("unload", this.boundUnloadHandler);
|
|
388
|
+
}
|
|
389
|
+
this.isAttached = false;
|
|
390
|
+
if (this.config.debug) {
|
|
391
|
+
console.log("[VedaTrace] Browser lifecycle handlers detached");
|
|
248
392
|
}
|
|
249
|
-
|
|
393
|
+
}
|
|
394
|
+
/** Handle visibility change - flush when page becomes hidden */
|
|
395
|
+
handleVisibilityChange() {
|
|
396
|
+
if (document.visibilityState === "hidden") {
|
|
397
|
+
if (this.config.debug) {
|
|
398
|
+
console.log("[VedaTrace] Page became hidden, flushing logs");
|
|
399
|
+
}
|
|
400
|
+
this.scheduleFlush();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Handle pagehide event - primary flush handler for Safari */
|
|
404
|
+
handlePageHide(event) {
|
|
405
|
+
if (this.config.debug) {
|
|
406
|
+
console.log(
|
|
407
|
+
"[VedaTrace] Page hide event",
|
|
408
|
+
event.persisted ? "(cached)" : "(navigation)"
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
if (event.persisted) {
|
|
412
|
+
this.scheduleFlush();
|
|
413
|
+
} else {
|
|
414
|
+
this.finalFlush();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/** Handle beforeunload - backup flush mechanism */
|
|
418
|
+
handleBeforeUnload(event) {
|
|
419
|
+
if (this.config.debug) {
|
|
420
|
+
console.log("[VedaTrace] Before unload event");
|
|
421
|
+
}
|
|
422
|
+
this.finalFlush();
|
|
423
|
+
}
|
|
424
|
+
/** Handle unload - fallback for older browsers */
|
|
425
|
+
handleUnload() {
|
|
426
|
+
if (this.config.debug) {
|
|
427
|
+
console.log("[VedaTrace] Unload event");
|
|
428
|
+
}
|
|
429
|
+
this.finalFlush();
|
|
430
|
+
}
|
|
431
|
+
/** Schedule a debounced flush (for visibility change) */
|
|
432
|
+
scheduleFlush() {
|
|
433
|
+
if (this.pendingFlush) return;
|
|
434
|
+
this.pendingFlush = this.config.flush().finally(() => {
|
|
435
|
+
this.pendingFlush = null;
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Final flush using keepalive fetch
|
|
440
|
+
* For sending logs after the page context is destroyed
|
|
441
|
+
*/
|
|
442
|
+
finalFlush() {
|
|
443
|
+
for (const transport of this.config.transports) {
|
|
444
|
+
if (transport.name === "http" && "flush" in transport) {
|
|
445
|
+
transport.flush?.();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
this.config.flush().catch(() => {
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
/** Check if handlers are attached */
|
|
452
|
+
isActive() {
|
|
453
|
+
return this.isAttached;
|
|
250
454
|
}
|
|
251
455
|
}
|
|
252
456
|
|
|
@@ -324,26 +528,55 @@ function redactPii(value, mask) {
|
|
|
324
528
|
return result;
|
|
325
529
|
}
|
|
326
530
|
|
|
531
|
+
const RUNTIME_FLUSH_INTERVALS = {
|
|
532
|
+
node: 3e3,
|
|
533
|
+
bun: 3e3,
|
|
534
|
+
deno: 3e3,
|
|
535
|
+
browser: 3e3,
|
|
536
|
+
cloudflare: 1e3,
|
|
537
|
+
edge: 1e3
|
|
538
|
+
};
|
|
327
539
|
function vedatrace(config = {}) {
|
|
540
|
+
const runtime = detectRuntime();
|
|
328
541
|
const logger = new VedaTraceLogger(config);
|
|
329
542
|
if (config.apiKey && (!config.transports || config.transports.length === 0)) {
|
|
330
|
-
const
|
|
543
|
+
const isBrowserEnv = isBrowser();
|
|
544
|
+
const isServerlessEnv = isServerless();
|
|
545
|
+
const isLongRunningEnv = isLongRunning();
|
|
546
|
+
const HttpTransport = isBrowserEnv ? transports_index.VedaTraceHttpTransportBrowser : transports_index.VedaTraceHttpTransport;
|
|
547
|
+
const httpConfig = {
|
|
548
|
+
apiKey: config.apiKey,
|
|
549
|
+
keepalive: isBrowserEnv
|
|
550
|
+
};
|
|
331
551
|
if (config.endpoint) httpConfig.endpoint = config.endpoint;
|
|
332
|
-
const httpTransport = new
|
|
552
|
+
const httpTransport = new HttpTransport(httpConfig);
|
|
553
|
+
let immediateFlush = config.immediateFlush ?? false;
|
|
554
|
+
let shouldUnrefTimer = false;
|
|
555
|
+
if (isServerlessEnv) {
|
|
556
|
+
immediateFlush = config.immediateFlush ?? !config.executionContext;
|
|
557
|
+
} else if (isLongRunningEnv) {
|
|
558
|
+
immediateFlush = config.immediateFlush ?? false;
|
|
559
|
+
shouldUnrefTimer = true;
|
|
560
|
+
} else if (isBrowserEnv) {
|
|
561
|
+
immediateFlush = config.immediateFlush ?? false;
|
|
562
|
+
}
|
|
563
|
+
const flushInterval = config.flushInterval ?? RUNTIME_FLUSH_INTERVALS[runtime] ?? 3e3;
|
|
333
564
|
const batcher = new VedaTraceBatcher(
|
|
334
565
|
[httpTransport],
|
|
335
566
|
{
|
|
336
567
|
batchSize: config.batchSize ?? 100,
|
|
337
|
-
flushInterval
|
|
568
|
+
flushInterval,
|
|
338
569
|
maxRetries: config.maxRetries ?? 3,
|
|
339
570
|
retryDelay: config.retryDelay ?? 1e3,
|
|
340
|
-
unrefTimer: config.unrefTimer
|
|
571
|
+
unrefTimer: config.unrefTimer ?? shouldUnrefTimer,
|
|
572
|
+
executionContext: config.executionContext,
|
|
573
|
+
onError: config.onError,
|
|
574
|
+
onSuccess: config.onSuccess
|
|
341
575
|
},
|
|
342
|
-
|
|
343
|
-
config.onSuccess
|
|
576
|
+
immediateFlush
|
|
344
577
|
);
|
|
345
578
|
logger.setBatcher(batcher);
|
|
346
|
-
if (typeof process !== "undefined") {
|
|
579
|
+
if (typeof process !== "undefined" && isLongRunningEnv) {
|
|
347
580
|
const flushLogs = async () => {
|
|
348
581
|
await batcher.flush();
|
|
349
582
|
};
|
|
@@ -351,6 +584,15 @@ function vedatrace(config = {}) {
|
|
|
351
584
|
process.on("SIGTERM", flushLogs);
|
|
352
585
|
process.on("SIGINT", flushLogs);
|
|
353
586
|
}
|
|
587
|
+
if (isBrowserEnv) {
|
|
588
|
+
const lifecycle = new BrowserLifecycle({
|
|
589
|
+
transports: [httpTransport],
|
|
590
|
+
flush: () => batcher.flush(),
|
|
591
|
+
debug: config.debug
|
|
592
|
+
});
|
|
593
|
+
lifecycle.attach();
|
|
594
|
+
logger._lifecycle = lifecycle;
|
|
595
|
+
}
|
|
354
596
|
}
|
|
355
597
|
return logger;
|
|
356
598
|
}
|
|
@@ -369,9 +611,16 @@ function devVedatrace(config = {}) {
|
|
|
369
611
|
|
|
370
612
|
exports.VedaTraceConsoleTransport = transports_index.VedaTraceConsoleTransport;
|
|
371
613
|
exports.VedaTraceHttpTransport = transports_index.VedaTraceHttpTransport;
|
|
614
|
+
exports.VedaTraceHttpTransportBrowser = transports_index.VedaTraceHttpTransportBrowser;
|
|
615
|
+
exports.BrowserLifecycle = BrowserLifecycle;
|
|
372
616
|
exports.VedaTraceBatcher = VedaTraceBatcher;
|
|
373
617
|
exports.VedaTraceLogger = VedaTraceLogger;
|
|
374
618
|
exports.default = vedatrace;
|
|
619
|
+
exports.detectRuntime = detectRuntime;
|
|
375
620
|
exports.devVedatrace = devVedatrace;
|
|
621
|
+
exports.isBrowser = isBrowser;
|
|
622
|
+
exports.isEdgeRuntime = isEdgeRuntime;
|
|
623
|
+
exports.isLongRunning = isLongRunning;
|
|
624
|
+
exports.isServerless = isServerless;
|
|
376
625
|
exports.redact = redact;
|
|
377
626
|
exports.vedatrace = vedatrace;
|