vedatrace 0.1.9 → 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 +25 -5
- package/dist/index.cjs +282 -81
- package/dist/index.d.cts +116 -52
- package/dist/index.d.mts +116 -52
- package/dist/index.mjs +279 -83
- 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-DUNRMOTv.d.cts → types-BU0UESs9.d.cts} +20 -44
- package/dist/{types-DUNRMOTv.d.mts → types-BU0UESs9.d.mts} +20 -44
- 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,28 +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
|
-
|
|
15
|
-
this.startFlushTimer();
|
|
16
|
-
}
|
|
12
|
+
this.context = config.executionContext;
|
|
17
13
|
}
|
|
18
14
|
queue = [];
|
|
19
15
|
flushTimer = null;
|
|
16
|
+
flushDebounceTimer = null;
|
|
20
17
|
isFlushing = false;
|
|
21
18
|
pendingFlush = null;
|
|
22
|
-
|
|
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 */
|
|
23
29
|
add(log) {
|
|
24
30
|
this.queue.push(log);
|
|
25
|
-
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) {
|
|
26
37
|
this.flush();
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
|
-
/**
|
|
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 */
|
|
30
62
|
async flush() {
|
|
31
63
|
if (this.isFlushing) {
|
|
32
64
|
return this.pendingFlush ?? Promise.resolve();
|
|
@@ -37,13 +69,16 @@ class VedaTraceBatcher {
|
|
|
37
69
|
this.isFlushing = true;
|
|
38
70
|
const logsToSend = [...this.queue];
|
|
39
71
|
this.queue = [];
|
|
40
|
-
|
|
72
|
+
const flushPromise = this.sendWithRetry(logsToSend).finally(() => {
|
|
41
73
|
this.isFlushing = false;
|
|
42
74
|
this.pendingFlush = null;
|
|
43
75
|
});
|
|
44
|
-
|
|
76
|
+
this.pendingFlush = flushPromise;
|
|
77
|
+
if (this.context) {
|
|
78
|
+
this.context.waitUntil(flushPromise);
|
|
79
|
+
}
|
|
80
|
+
return flushPromise;
|
|
45
81
|
}
|
|
46
|
-
/** Send logs with retry logic */
|
|
47
82
|
async sendWithRetry(logs, attempt = 0) {
|
|
48
83
|
const errors = [];
|
|
49
84
|
for (const transport of this.transports) {
|
|
@@ -61,16 +96,17 @@ class VedaTraceBatcher {
|
|
|
61
96
|
const combinedError = new Error(
|
|
62
97
|
`Failed to send logs after ${this.config.maxRetries} retries: ${errors.map((e) => e.message).join(", ")}`
|
|
63
98
|
);
|
|
64
|
-
if (this.onError) {
|
|
65
|
-
this.onError(combinedError);
|
|
99
|
+
if (this.config.onError) {
|
|
100
|
+
this.config.onError(combinedError);
|
|
66
101
|
} else {
|
|
67
102
|
console.error("[VedaTrace]", combinedError.message);
|
|
68
103
|
}
|
|
69
104
|
return;
|
|
70
105
|
}
|
|
71
|
-
this.onSuccess
|
|
106
|
+
if (this.config.onSuccess) {
|
|
107
|
+
this.config.onSuccess();
|
|
108
|
+
}
|
|
72
109
|
}
|
|
73
|
-
/** Start the flush interval timer */
|
|
74
110
|
startFlushTimer() {
|
|
75
111
|
if (this.flushTimer) {
|
|
76
112
|
clearInterval(this.flushTimer);
|
|
@@ -78,8 +114,8 @@ class VedaTraceBatcher {
|
|
|
78
114
|
this.flushTimer = setInterval(() => {
|
|
79
115
|
if (this.queue.length > 0) {
|
|
80
116
|
this.flush().catch((error) => {
|
|
81
|
-
if (this.onError) {
|
|
82
|
-
this.onError(
|
|
117
|
+
if (this.config.onError) {
|
|
118
|
+
this.config.onError(
|
|
83
119
|
error instanceof Error ? error : new Error(String(error))
|
|
84
120
|
);
|
|
85
121
|
} else {
|
|
@@ -95,63 +131,84 @@ class VedaTraceBatcher {
|
|
|
95
131
|
this.flushTimer.unref();
|
|
96
132
|
}
|
|
97
133
|
}
|
|
98
|
-
/** Stop the flush timer */
|
|
99
134
|
stop() {
|
|
100
135
|
if (this.flushTimer) {
|
|
101
136
|
clearInterval(this.flushTimer);
|
|
102
137
|
this.flushTimer = null;
|
|
103
138
|
}
|
|
139
|
+
if (this.flushDebounceTimer) {
|
|
140
|
+
clearTimeout(this.flushDebounceTimer);
|
|
141
|
+
this.flushDebounceTimer = null;
|
|
142
|
+
}
|
|
104
143
|
}
|
|
105
|
-
/** Start the flush timer (for manual control in edge runtimes) */
|
|
106
144
|
start() {
|
|
107
145
|
if (!this.flushTimer && !this.immediateFlush) {
|
|
108
146
|
this.startFlushTimer();
|
|
109
147
|
}
|
|
110
148
|
}
|
|
111
|
-
/** Delay helper */
|
|
112
149
|
delay(ms) {
|
|
113
150
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
114
151
|
}
|
|
115
|
-
/** Get current queue size */
|
|
116
152
|
getQueueSize() {
|
|
117
153
|
return this.queue.length;
|
|
118
154
|
}
|
|
155
|
+
setExecutionContext(ctx) {
|
|
156
|
+
this.context = ctx;
|
|
157
|
+
}
|
|
119
158
|
}
|
|
120
159
|
|
|
121
160
|
function detectRuntime() {
|
|
122
|
-
if (typeof
|
|
123
|
-
return "node";
|
|
124
|
-
}
|
|
125
|
-
if (typeof globalThis !== "undefined" && "navigator" in globalThis && typeof self === "undefined") {
|
|
126
|
-
return "browser";
|
|
127
|
-
}
|
|
128
|
-
if (typeof caches !== "undefined") {
|
|
161
|
+
if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
|
|
129
162
|
return "cloudflare";
|
|
130
163
|
}
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
164
|
+
const g = globalThis;
|
|
165
|
+
if (g?.Deno && g.Deno.version?.deno) {
|
|
133
166
|
return "deno";
|
|
134
167
|
}
|
|
135
|
-
|
|
136
|
-
if (maybeBun?.Bun) {
|
|
168
|
+
if (g?.Bun) {
|
|
137
169
|
return "bun";
|
|
138
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
|
+
}
|
|
139
183
|
return "edge";
|
|
140
184
|
}
|
|
141
185
|
function isEdgeRuntime() {
|
|
142
186
|
const runtime = detectRuntime();
|
|
143
187
|
return runtime === "cloudflare" || runtime === "deno" || runtime === "bun" || runtime === "edge";
|
|
144
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";
|
|
199
|
+
}
|
|
145
200
|
|
|
146
|
-
const SDK_VERSION = "
|
|
201
|
+
const SDK_VERSION = process.env.npm_package_version ?? "0.0.0";
|
|
147
202
|
class VedaTraceLogger {
|
|
148
203
|
batcher = null;
|
|
149
204
|
runtime;
|
|
150
205
|
config;
|
|
151
206
|
childDefaults;
|
|
207
|
+
_context;
|
|
152
208
|
constructor(config = {}, childDefaults = {}) {
|
|
153
209
|
this.runtime = config.runtime ?? detectRuntime();
|
|
154
210
|
this.childDefaults = childDefaults;
|
|
211
|
+
this._context = config.executionContext;
|
|
155
212
|
this.config = {
|
|
156
213
|
service: config.service,
|
|
157
214
|
apiKey: config.apiKey,
|
|
@@ -161,61 +218,68 @@ class VedaTraceLogger {
|
|
|
161
218
|
flushInterval: config.flushInterval ?? 5e3,
|
|
162
219
|
maxRetries: config.maxRetries ?? 3,
|
|
163
220
|
retryDelay: config.retryDelay ?? 1e3,
|
|
164
|
-
onError: config.onError,
|
|
165
|
-
onSuccess: config.onSuccess,
|
|
166
221
|
debug: config.debug ?? false,
|
|
167
222
|
immediateFlush: config.immediateFlush ?? false,
|
|
168
|
-
unrefTimer: config.unrefTimer
|
|
223
|
+
unrefTimer: config.unrefTimer ?? false
|
|
169
224
|
};
|
|
170
225
|
if (!config.disabled) {
|
|
171
226
|
this.initializeBatcher(config);
|
|
172
227
|
}
|
|
173
228
|
}
|
|
174
|
-
/** Initialize the batcher with transports */
|
|
175
229
|
initializeBatcher(config) {
|
|
176
230
|
const transports = config.transports ?? [];
|
|
177
|
-
if (config.apiKey && transports.length === 0) ;
|
|
178
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
|
+
};
|
|
179
242
|
this.batcher = new VedaTraceBatcher(
|
|
180
243
|
transports,
|
|
181
|
-
|
|
182
|
-
batchSize: this.config.batchSize,
|
|
183
|
-
flushInterval: this.config.flushInterval,
|
|
184
|
-
maxRetries: this.config.maxRetries,
|
|
185
|
-
retryDelay: this.config.retryDelay,
|
|
186
|
-
unrefTimer: this.config.unrefTimer
|
|
187
|
-
},
|
|
188
|
-
this.config.onError,
|
|
189
|
-
this.config.onSuccess,
|
|
244
|
+
batcherConfig,
|
|
190
245
|
this.config.immediateFlush
|
|
191
246
|
);
|
|
192
247
|
}
|
|
193
248
|
}
|
|
194
|
-
/** Set batcher (called from factory function) */
|
|
195
249
|
setBatcher(batcher) {
|
|
196
250
|
this.batcher = batcher;
|
|
197
251
|
}
|
|
198
|
-
/**
|
|
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
|
+
}
|
|
199
268
|
debug(message, metadata) {
|
|
200
269
|
this.log("debug", message, metadata);
|
|
201
270
|
}
|
|
202
|
-
/** Log at info level */
|
|
203
271
|
info(message, metadata) {
|
|
204
272
|
this.log("info", message, metadata);
|
|
205
273
|
}
|
|
206
|
-
/** Log at warn level */
|
|
207
274
|
warn(message, metadata) {
|
|
208
275
|
this.log("warn", message, metadata);
|
|
209
276
|
}
|
|
210
|
-
/** Log at error level */
|
|
211
277
|
error(message, metadata) {
|
|
212
278
|
this.log("error", message, metadata);
|
|
213
279
|
}
|
|
214
|
-
/** Log at fatal level */
|
|
215
280
|
fatal(message, metadata) {
|
|
216
281
|
this.log("fatal", message, metadata);
|
|
217
282
|
}
|
|
218
|
-
/** Internal log method */
|
|
219
283
|
log(level, message, metadata) {
|
|
220
284
|
if (!this.batcher) {
|
|
221
285
|
return;
|
|
@@ -230,7 +294,7 @@ class VedaTraceLogger {
|
|
|
230
294
|
timestamp: Date.now(),
|
|
231
295
|
metadata: cleanMetadata,
|
|
232
296
|
_sdk: {
|
|
233
|
-
source:
|
|
297
|
+
source: detectRuntime(),
|
|
234
298
|
version: SDK_VERSION
|
|
235
299
|
}
|
|
236
300
|
};
|
|
@@ -243,7 +307,6 @@ class VedaTraceLogger {
|
|
|
243
307
|
}
|
|
244
308
|
this.batcher.add(logEntry);
|
|
245
309
|
}
|
|
246
|
-
/** Create a child logger with default metadata */
|
|
247
310
|
child(defaults) {
|
|
248
311
|
const mergedDefaults = { ...this.childDefaults, ...defaults };
|
|
249
312
|
const childLogger = new VedaTraceLogger(
|
|
@@ -252,7 +315,8 @@ class VedaTraceLogger {
|
|
|
252
315
|
apiKey: this.config.apiKey,
|
|
253
316
|
endpoint: this.config.endpoint,
|
|
254
317
|
environment: this.config.environment,
|
|
255
|
-
disabled: !this.batcher
|
|
318
|
+
disabled: !this.batcher,
|
|
319
|
+
executionContext: this._context
|
|
256
320
|
},
|
|
257
321
|
mergedDefaults
|
|
258
322
|
);
|
|
@@ -261,33 +325,132 @@ class VedaTraceLogger {
|
|
|
261
325
|
}
|
|
262
326
|
return childLogger;
|
|
263
327
|
}
|
|
264
|
-
/** Flush pending logs */
|
|
265
328
|
async flush() {
|
|
266
329
|
if (this.batcher) {
|
|
267
|
-
|
|
330
|
+
const flushPromise = this.batcher.flush();
|
|
331
|
+
if (this._context) {
|
|
332
|
+
this._context.waitUntil(flushPromise);
|
|
333
|
+
}
|
|
334
|
+
return flushPromise;
|
|
268
335
|
}
|
|
269
336
|
}
|
|
270
|
-
/** Stop the batcher and flush timer */
|
|
271
337
|
stop() {
|
|
272
338
|
if (this.batcher) {
|
|
273
339
|
this.batcher.stop();
|
|
274
340
|
}
|
|
275
341
|
}
|
|
276
|
-
/** Start the flush timer (for manual control in edge runtimes) */
|
|
277
342
|
start() {
|
|
278
343
|
if (this.batcher) {
|
|
279
344
|
this.batcher.start();
|
|
280
345
|
}
|
|
281
346
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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);
|
|
286
388
|
}
|
|
287
|
-
|
|
288
|
-
|
|
389
|
+
this.isAttached = false;
|
|
390
|
+
if (this.config.debug) {
|
|
391
|
+
console.log("[VedaTrace] Browser lifecycle handlers detached");
|
|
289
392
|
}
|
|
290
|
-
|
|
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;
|
|
291
454
|
}
|
|
292
455
|
}
|
|
293
456
|
|
|
@@ -365,31 +528,55 @@ function redactPii(value, mask) {
|
|
|
365
528
|
return result;
|
|
366
529
|
}
|
|
367
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
|
+
};
|
|
368
539
|
function vedatrace(config = {}) {
|
|
540
|
+
const runtime = detectRuntime();
|
|
369
541
|
const logger = new VedaTraceLogger(config);
|
|
370
|
-
const isEdge = isEdgeRuntime();
|
|
371
|
-
const shouldImmediateFlush = config.immediateFlush ?? isEdge;
|
|
372
|
-
const shouldAutoStart = config.autoStart ?? !isEdge;
|
|
373
542
|
if (config.apiKey && (!config.transports || config.transports.length === 0)) {
|
|
374
|
-
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
|
+
};
|
|
375
551
|
if (config.endpoint) httpConfig.endpoint = config.endpoint;
|
|
376
|
-
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;
|
|
377
564
|
const batcher = new VedaTraceBatcher(
|
|
378
565
|
[httpTransport],
|
|
379
566
|
{
|
|
380
567
|
batchSize: config.batchSize ?? 100,
|
|
381
|
-
flushInterval
|
|
568
|
+
flushInterval,
|
|
382
569
|
maxRetries: config.maxRetries ?? 3,
|
|
383
570
|
retryDelay: config.retryDelay ?? 1e3,
|
|
384
|
-
unrefTimer: config.unrefTimer
|
|
571
|
+
unrefTimer: config.unrefTimer ?? shouldUnrefTimer,
|
|
572
|
+
executionContext: config.executionContext,
|
|
573
|
+
onError: config.onError,
|
|
574
|
+
onSuccess: config.onSuccess
|
|
385
575
|
},
|
|
386
|
-
|
|
387
|
-
config.onSuccess,
|
|
388
|
-
shouldImmediateFlush,
|
|
389
|
-
shouldAutoStart
|
|
576
|
+
immediateFlush
|
|
390
577
|
);
|
|
391
578
|
logger.setBatcher(batcher);
|
|
392
|
-
if (typeof process !== "undefined") {
|
|
579
|
+
if (typeof process !== "undefined" && isLongRunningEnv) {
|
|
393
580
|
const flushLogs = async () => {
|
|
394
581
|
await batcher.flush();
|
|
395
582
|
};
|
|
@@ -397,6 +584,15 @@ function vedatrace(config = {}) {
|
|
|
397
584
|
process.on("SIGTERM", flushLogs);
|
|
398
585
|
process.on("SIGINT", flushLogs);
|
|
399
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
|
+
}
|
|
400
596
|
}
|
|
401
597
|
return logger;
|
|
402
598
|
}
|
|
@@ -415,11 +611,16 @@ function devVedatrace(config = {}) {
|
|
|
415
611
|
|
|
416
612
|
exports.VedaTraceConsoleTransport = transports_index.VedaTraceConsoleTransport;
|
|
417
613
|
exports.VedaTraceHttpTransport = transports_index.VedaTraceHttpTransport;
|
|
614
|
+
exports.VedaTraceHttpTransportBrowser = transports_index.VedaTraceHttpTransportBrowser;
|
|
615
|
+
exports.BrowserLifecycle = BrowserLifecycle;
|
|
418
616
|
exports.VedaTraceBatcher = VedaTraceBatcher;
|
|
419
617
|
exports.VedaTraceLogger = VedaTraceLogger;
|
|
420
618
|
exports.default = vedatrace;
|
|
421
619
|
exports.detectRuntime = detectRuntime;
|
|
422
620
|
exports.devVedatrace = devVedatrace;
|
|
621
|
+
exports.isBrowser = isBrowser;
|
|
423
622
|
exports.isEdgeRuntime = isEdgeRuntime;
|
|
623
|
+
exports.isLongRunning = isLongRunning;
|
|
624
|
+
exports.isServerless = isServerless;
|
|
424
625
|
exports.redact = redact;
|
|
425
626
|
exports.vedatrace = vedatrace;
|