@glasstrace/sdk 0.12.3 → 0.12.5
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/dist/index.cjs +162 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +159 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -17036,6 +17036,7 @@ function loadFsSyncOrNull() {
|
|
|
17036
17036
|
var currentConfig = null;
|
|
17037
17037
|
var configCacheChecked = false;
|
|
17038
17038
|
var rateLimitBackoff = false;
|
|
17039
|
+
var lastInitSucceeded = false;
|
|
17039
17040
|
function loadCachedConfig(projectRoot) {
|
|
17040
17041
|
const modules = loadFsSyncOrNull();
|
|
17041
17042
|
if (!modules) return null;
|
|
@@ -17205,6 +17206,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17205
17206
|
}
|
|
17206
17207
|
}
|
|
17207
17208
|
async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
17209
|
+
lastInitSucceeded = false;
|
|
17208
17210
|
if (rateLimitBackoff) {
|
|
17209
17211
|
rateLimitBackoff = false;
|
|
17210
17212
|
return null;
|
|
@@ -17233,6 +17235,7 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
|
17233
17235
|
if (healthReport) {
|
|
17234
17236
|
acknowledgeHealthReport(healthReport);
|
|
17235
17237
|
}
|
|
17238
|
+
lastInitSucceeded = true;
|
|
17236
17239
|
await saveCachedConfig(result);
|
|
17237
17240
|
if (result.claimResult) {
|
|
17238
17241
|
try {
|
|
@@ -17279,7 +17282,6 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
|
17279
17282
|
return null;
|
|
17280
17283
|
}
|
|
17281
17284
|
} catch (err) {
|
|
17282
|
-
recordInitFailure();
|
|
17283
17285
|
console.warn(
|
|
17284
17286
|
`[glasstrace] Unexpected init error: ${err instanceof Error ? err.message : String(err)}`
|
|
17285
17287
|
);
|
|
@@ -17309,6 +17311,16 @@ function getClaimResult() {
|
|
|
17309
17311
|
function _setCurrentConfig(config2) {
|
|
17310
17312
|
currentConfig = config2;
|
|
17311
17313
|
}
|
|
17314
|
+
function consumeRateLimitFlag() {
|
|
17315
|
+
if (rateLimitBackoff) {
|
|
17316
|
+
rateLimitBackoff = false;
|
|
17317
|
+
return true;
|
|
17318
|
+
}
|
|
17319
|
+
return false;
|
|
17320
|
+
}
|
|
17321
|
+
function didLastInitSucceed() {
|
|
17322
|
+
return lastInitSucceeded;
|
|
17323
|
+
}
|
|
17312
17324
|
|
|
17313
17325
|
// src/span-processor.ts
|
|
17314
17326
|
var GlasstraceSpanProcessor = class {
|
|
@@ -17345,6 +17357,7 @@ var GlasstraceExporter = class {
|
|
|
17345
17357
|
environment;
|
|
17346
17358
|
endpointUrl;
|
|
17347
17359
|
createDelegateFn;
|
|
17360
|
+
verbose;
|
|
17348
17361
|
delegate = null;
|
|
17349
17362
|
delegateKey = null;
|
|
17350
17363
|
pendingBatches = [];
|
|
@@ -17357,6 +17370,7 @@ var GlasstraceExporter = class {
|
|
|
17357
17370
|
this.environment = options.environment;
|
|
17358
17371
|
this.endpointUrl = options.endpointUrl;
|
|
17359
17372
|
this.createDelegateFn = options.createDelegate;
|
|
17373
|
+
this.verbose = options.verbose ?? false;
|
|
17360
17374
|
}
|
|
17361
17375
|
export(spans, resultCallback) {
|
|
17362
17376
|
const currentKey = this.getApiKey();
|
|
@@ -17365,11 +17379,16 @@ var GlasstraceExporter = class {
|
|
|
17365
17379
|
return;
|
|
17366
17380
|
}
|
|
17367
17381
|
const enrichedSpans = spans.map((span) => this.enrichSpan(span));
|
|
17382
|
+
if (this.verbose) {
|
|
17383
|
+
sdkLog("info", `[glasstrace:diag] Export batch: ${enrichedSpans.length} spans`);
|
|
17384
|
+
}
|
|
17368
17385
|
const exporter = this.ensureDelegate();
|
|
17369
17386
|
if (exporter) {
|
|
17370
17387
|
exporter.export(enrichedSpans, (result) => {
|
|
17371
17388
|
if (result.code !== 0) {
|
|
17372
17389
|
sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
|
|
17390
|
+
} else if (this.verbose) {
|
|
17391
|
+
sdkLog("info", `[glasstrace:diag] Export success: ${enrichedSpans.length} spans delivered`);
|
|
17373
17392
|
}
|
|
17374
17393
|
resultCallback(result);
|
|
17375
17394
|
});
|
|
@@ -17462,6 +17481,21 @@ var GlasstraceExporter = class {
|
|
|
17462
17481
|
if (statusCode !== void 0) {
|
|
17463
17482
|
extra[ATTR.HTTP_STATUS_CODE] = statusCode;
|
|
17464
17483
|
}
|
|
17484
|
+
if (method && span.status?.code === SpanStatusCode.ERROR) {
|
|
17485
|
+
if (statusCode === void 0 || statusCode === 0 || statusCode === 200) {
|
|
17486
|
+
const httpErrorType = attrs["error.type"];
|
|
17487
|
+
if (typeof httpErrorType === "string") {
|
|
17488
|
+
const parsed = parseInt(httpErrorType, 10);
|
|
17489
|
+
if (!isNaN(parsed) && parsed >= 400 && parsed <= 599) {
|
|
17490
|
+
extra[ATTR.HTTP_STATUS_CODE] = parsed;
|
|
17491
|
+
} else {
|
|
17492
|
+
extra[ATTR.HTTP_STATUS_CODE] = 500;
|
|
17493
|
+
}
|
|
17494
|
+
} else {
|
|
17495
|
+
extra[ATTR.HTTP_STATUS_CODE] = 500;
|
|
17496
|
+
}
|
|
17497
|
+
}
|
|
17498
|
+
}
|
|
17465
17499
|
if (span.startTime && span.endTime) {
|
|
17466
17500
|
const [startSec, startNano] = span.startTime;
|
|
17467
17501
|
const [endSec, endNano] = span.endTime;
|
|
@@ -17541,11 +17575,17 @@ var GlasstraceExporter = class {
|
|
|
17541
17575
|
bufferSpans(spans, resultCallback) {
|
|
17542
17576
|
this.pendingBatches.push({ spans, resultCallback });
|
|
17543
17577
|
this.pendingSpanCount += spans.length;
|
|
17578
|
+
if (this.verbose) {
|
|
17579
|
+
sdkLog("info", `[glasstrace:diag] Buffering ${spans.length} spans (key pending, total: ${this.pendingSpanCount})`);
|
|
17580
|
+
}
|
|
17544
17581
|
while (this.pendingSpanCount > MAX_PENDING_SPANS && this.pendingBatches.length > 1) {
|
|
17545
17582
|
const evicted = this.pendingBatches.shift();
|
|
17546
17583
|
this.pendingSpanCount -= evicted.spans.length;
|
|
17547
17584
|
recordSpansDropped(evicted.spans.length);
|
|
17548
17585
|
evicted.resultCallback({ code: 0 });
|
|
17586
|
+
if (this.verbose) {
|
|
17587
|
+
sdkLog("info", `[glasstrace:diag] Buffer overflow: evicted ${evicted.spans.length} spans (total pending: ${this.pendingSpanCount})`);
|
|
17588
|
+
}
|
|
17549
17589
|
if (!this.overflowLogged) {
|
|
17550
17590
|
this.overflowLogged = true;
|
|
17551
17591
|
console.warn(
|
|
@@ -17584,6 +17624,8 @@ var GlasstraceExporter = class {
|
|
|
17584
17624
|
exporter.export(enriched, (result) => {
|
|
17585
17625
|
if (result.code !== 0) {
|
|
17586
17626
|
sdkLog("warn", `[glasstrace] Span export failed: ${result.error?.message ?? "unknown error"}`);
|
|
17627
|
+
} else if (this.verbose) {
|
|
17628
|
+
sdkLog("info", `[glasstrace:diag] Flush export success: ${enriched.length} spans delivered`);
|
|
17587
17629
|
}
|
|
17588
17630
|
batch.resultCallback(result);
|
|
17589
17631
|
});
|
|
@@ -20383,7 +20425,8 @@ async function configureOtel(config2, sessionManager) {
|
|
|
20383
20425
|
getConfig: () => getActiveConfig(),
|
|
20384
20426
|
environment: config2.environment,
|
|
20385
20427
|
endpointUrl: exporterUrl,
|
|
20386
|
-
createDelegate: createOtlpExporter
|
|
20428
|
+
createDelegate: createOtlpExporter,
|
|
20429
|
+
verbose: config2.verbose
|
|
20387
20430
|
});
|
|
20388
20431
|
_activeExporter = glasstraceExporter;
|
|
20389
20432
|
const vercelOtel = await tryImport("@vercel/otel");
|
|
@@ -20426,6 +20469,9 @@ async function configureOtel(config2, sessionManager) {
|
|
|
20426
20469
|
const processor = new BatchSpanProcessor(glasstraceExporter, {
|
|
20427
20470
|
scheduledDelayMillis: 1e3
|
|
20428
20471
|
});
|
|
20472
|
+
if (config2.verbose) {
|
|
20473
|
+
sdkLog("info", "[glasstrace:diag] BatchSpanProcessor configured: scheduledDelayMillis=1000");
|
|
20474
|
+
}
|
|
20429
20475
|
const provider = new BasicTracerProvider({
|
|
20430
20476
|
spanProcessors: [processor]
|
|
20431
20477
|
});
|
|
@@ -20435,6 +20481,112 @@ async function configureOtel(config2, sessionManager) {
|
|
|
20435
20481
|
|
|
20436
20482
|
// src/register.ts
|
|
20437
20483
|
init_console_capture();
|
|
20484
|
+
|
|
20485
|
+
// src/heartbeat.ts
|
|
20486
|
+
init_console_capture();
|
|
20487
|
+
var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
20488
|
+
var BACKOFF_BASE_MS = HEARTBEAT_INTERVAL_MS;
|
|
20489
|
+
var BACKOFF_MAX_MS = 30 * 60 * 1e3;
|
|
20490
|
+
var BACKOFF_JITTER = 0.2;
|
|
20491
|
+
var heartbeatTimer = null;
|
|
20492
|
+
var heartbeatGeneration = 0;
|
|
20493
|
+
var backoffAttempts = 0;
|
|
20494
|
+
var backoffUntil = 0;
|
|
20495
|
+
var tickInProgress = false;
|
|
20496
|
+
var _shutdownHandler2 = null;
|
|
20497
|
+
function startHeartbeat(config2, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
20498
|
+
if (heartbeatTimer !== null) return;
|
|
20499
|
+
heartbeatGeneration = generation;
|
|
20500
|
+
heartbeatTimer = setInterval(() => {
|
|
20501
|
+
void heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition);
|
|
20502
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
20503
|
+
heartbeatTimer.unref();
|
|
20504
|
+
registerShutdownHandlers(config2, anonKey, sdkVersion);
|
|
20505
|
+
if (config2.verbose) {
|
|
20506
|
+
sdkLog("info", "[glasstrace] Heartbeat started (5-minute interval).");
|
|
20507
|
+
}
|
|
20508
|
+
}
|
|
20509
|
+
function stopHeartbeat() {
|
|
20510
|
+
if (heartbeatTimer !== null) {
|
|
20511
|
+
clearInterval(heartbeatTimer);
|
|
20512
|
+
heartbeatTimer = null;
|
|
20513
|
+
}
|
|
20514
|
+
removeShutdownHandlers();
|
|
20515
|
+
}
|
|
20516
|
+
async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
20517
|
+
if (tickInProgress) return;
|
|
20518
|
+
tickInProgress = true;
|
|
20519
|
+
try {
|
|
20520
|
+
if (generation !== heartbeatGeneration) {
|
|
20521
|
+
stopHeartbeat();
|
|
20522
|
+
return;
|
|
20523
|
+
}
|
|
20524
|
+
if (Date.now() < backoffUntil) {
|
|
20525
|
+
if (config2.verbose) {
|
|
20526
|
+
sdkLog("info", "[glasstrace] Heartbeat skipped (rate-limit backoff).");
|
|
20527
|
+
}
|
|
20528
|
+
return;
|
|
20529
|
+
}
|
|
20530
|
+
const healthReport = collectHealthReport(sdkVersion);
|
|
20531
|
+
const initResult = await performInit(config2, anonKey, sdkVersion, healthReport);
|
|
20532
|
+
if (generation !== heartbeatGeneration) return;
|
|
20533
|
+
if (initResult === null && consumeRateLimitFlag()) {
|
|
20534
|
+
backoffAttempts++;
|
|
20535
|
+
const delay = Math.min(
|
|
20536
|
+
BACKOFF_BASE_MS * Math.pow(2, backoffAttempts - 1),
|
|
20537
|
+
BACKOFF_MAX_MS
|
|
20538
|
+
);
|
|
20539
|
+
const jitter = delay * BACKOFF_JITTER * (Math.random() * 2 - 1);
|
|
20540
|
+
backoffUntil = Date.now() + delay + jitter;
|
|
20541
|
+
if (config2.verbose) {
|
|
20542
|
+
sdkLog("info", `[glasstrace] Heartbeat backing off for ${Math.round((delay + jitter) / 1e3)}s.`);
|
|
20543
|
+
}
|
|
20544
|
+
} else {
|
|
20545
|
+
backoffAttempts = 0;
|
|
20546
|
+
backoffUntil = 0;
|
|
20547
|
+
}
|
|
20548
|
+
if (initResult?.claimResult) {
|
|
20549
|
+
onClaimTransition(initResult.claimResult.newApiKey);
|
|
20550
|
+
}
|
|
20551
|
+
if (config2.verbose) {
|
|
20552
|
+
sdkLog("info", "[glasstrace] Heartbeat completed.");
|
|
20553
|
+
}
|
|
20554
|
+
} finally {
|
|
20555
|
+
tickInProgress = false;
|
|
20556
|
+
}
|
|
20557
|
+
}
|
|
20558
|
+
function registerShutdownHandlers(config2, anonKey, sdkVersion) {
|
|
20559
|
+
if (typeof process === "undefined" || typeof process.once !== "function") {
|
|
20560
|
+
return;
|
|
20561
|
+
}
|
|
20562
|
+
let shutdownFired = false;
|
|
20563
|
+
const handler = (signal) => {
|
|
20564
|
+
if (shutdownFired) return;
|
|
20565
|
+
shutdownFired = true;
|
|
20566
|
+
if (heartbeatTimer !== null) {
|
|
20567
|
+
clearInterval(heartbeatTimer);
|
|
20568
|
+
heartbeatTimer = null;
|
|
20569
|
+
}
|
|
20570
|
+
const healthReport = collectHealthReport(sdkVersion);
|
|
20571
|
+
void performInit(config2, anonKey, sdkVersion, healthReport).catch(() => {
|
|
20572
|
+
}).finally(() => {
|
|
20573
|
+
removeShutdownHandlers();
|
|
20574
|
+
process.kill(process.pid, signal);
|
|
20575
|
+
});
|
|
20576
|
+
};
|
|
20577
|
+
_shutdownHandler2 = handler;
|
|
20578
|
+
process.once("SIGTERM", _shutdownHandler2);
|
|
20579
|
+
process.once("SIGINT", _shutdownHandler2);
|
|
20580
|
+
}
|
|
20581
|
+
function removeShutdownHandlers() {
|
|
20582
|
+
if (_shutdownHandler2 && typeof process !== "undefined") {
|
|
20583
|
+
process.removeListener("SIGTERM", _shutdownHandler2);
|
|
20584
|
+
process.removeListener("SIGINT", _shutdownHandler2);
|
|
20585
|
+
_shutdownHandler2 = null;
|
|
20586
|
+
}
|
|
20587
|
+
}
|
|
20588
|
+
|
|
20589
|
+
// src/register.ts
|
|
20438
20590
|
var consoleCaptureInstalled = false;
|
|
20439
20591
|
var discoveryHandler = null;
|
|
20440
20592
|
var isRegistered = false;
|
|
@@ -20587,14 +20739,20 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
20587
20739
|
if (config2.verbose) {
|
|
20588
20740
|
console.info("[glasstrace] Background init firing.");
|
|
20589
20741
|
}
|
|
20590
|
-
const healthReport = collectHealthReport("0.12.
|
|
20591
|
-
const initResult = await performInit(config2, anonKeyForInit, "0.12.
|
|
20742
|
+
const healthReport = collectHealthReport("0.12.5");
|
|
20743
|
+
const initResult = await performInit(config2, anonKeyForInit, "0.12.5", healthReport);
|
|
20592
20744
|
if (generation !== registrationGeneration) return;
|
|
20593
20745
|
if (initResult?.claimResult) {
|
|
20594
20746
|
setResolvedApiKey(initResult.claimResult.newApiKey);
|
|
20595
20747
|
notifyApiKeyResolved();
|
|
20596
20748
|
}
|
|
20597
20749
|
maybeInstallConsoleCapture();
|
|
20750
|
+
if (didLastInitSucceed()) {
|
|
20751
|
+
startHeartbeat(config2, anonKeyForInit, "0.12.5", generation, (newApiKey) => {
|
|
20752
|
+
setResolvedApiKey(newApiKey);
|
|
20753
|
+
notifyApiKeyResolved();
|
|
20754
|
+
});
|
|
20755
|
+
}
|
|
20598
20756
|
}
|
|
20599
20757
|
function getDiscoveryHandler() {
|
|
20600
20758
|
return discoveryHandler;
|