@glasstrace/sdk 0.12.1 → 0.12.2

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.d.cts CHANGED
@@ -307,7 +307,7 @@ interface InitClaimResult {
307
307
  * or request failure). Callers that do not need claim information
308
308
  * can safely ignore the return value.
309
309
  */
310
- declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<InitClaimResult | null>;
310
+ declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string, healthReport?: SdkHealthReport | null): Promise<InitClaimResult | null>;
311
311
  /**
312
312
  * Returns the current capture config from the three-tier fallback chain:
313
313
  * 1. In-memory config from latest init response
package/dist/index.d.ts CHANGED
@@ -307,7 +307,7 @@ interface InitClaimResult {
307
307
  * or request failure). Callers that do not need claim information
308
308
  * can safely ignore the return value.
309
309
  */
310
- declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<InitClaimResult | null>;
310
+ declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string, healthReport?: SdkHealthReport | null): Promise<InitClaimResult | null>;
311
311
  /**
312
312
  * Returns the current capture config from the three-tier fallback chain:
313
313
  * 1. In-memory config from latest init response
package/dist/index.js CHANGED
@@ -173,6 +173,58 @@ function classifyFetchTarget(url) {
173
173
  return "unknown";
174
174
  }
175
175
 
176
+ // src/health-collector.ts
177
+ var tracesExported = 0;
178
+ var tracesDropped = 0;
179
+ var initFailures = 0;
180
+ var lastConfigSyncAt = null;
181
+ function recordSpansExported(count) {
182
+ if (!Number.isFinite(count) || count < 0 || !Number.isInteger(count)) return;
183
+ tracesExported += count;
184
+ }
185
+ function recordSpansDropped(count) {
186
+ if (!Number.isFinite(count) || count < 0 || !Number.isInteger(count)) return;
187
+ tracesDropped += count;
188
+ }
189
+ function recordInitFailure() {
190
+ try {
191
+ initFailures += 1;
192
+ } catch {
193
+ }
194
+ }
195
+ function recordConfigSync(timestamp) {
196
+ try {
197
+ lastConfigSyncAt = timestamp;
198
+ } catch {
199
+ }
200
+ }
201
+ function collectHealthReport(sdkVersion) {
202
+ try {
203
+ const now = Date.now();
204
+ const configAge = lastConfigSyncAt !== null ? Math.max(0, now - lastConfigSyncAt) : 0;
205
+ return {
206
+ tracesExportedSinceLastInit: tracesExported,
207
+ tracesDropped,
208
+ initFailures,
209
+ configAge: Math.round(configAge),
210
+ sdkVersion
211
+ };
212
+ } catch {
213
+ return null;
214
+ }
215
+ }
216
+ function acknowledgeHealthReport(report) {
217
+ const exp = Math.max(0, report.tracesExportedSinceLastInit);
218
+ const expVal = tracesExported - exp;
219
+ tracesExported = Number.isFinite(expVal) ? Math.max(0, expVal) : tracesExported;
220
+ const drop = Math.max(0, report.tracesDropped);
221
+ const dropVal = tracesDropped - drop;
222
+ tracesDropped = Number.isFinite(dropVal) ? Math.max(0, dropVal) : tracesDropped;
223
+ const fail = Math.max(0, report.initFailures);
224
+ const failVal = initFailures - fail;
225
+ initFailures = Number.isFinite(failVal) ? Math.max(0, failVal) : initFailures;
226
+ }
227
+
176
228
  // src/init-client.ts
177
229
  var GLASSTRACE_DIR = ".glasstrace";
178
230
  var CONFIG_FILE = "config";
@@ -222,6 +274,7 @@ function loadCachedConfig(projectRoot) {
222
274
  }
223
275
  const result = SdkInitResponseSchema.safeParse(cached.response);
224
276
  if (result.success) {
277
+ recordConfigSync(cached.cachedAt);
225
278
  return result.data;
226
279
  }
227
280
  console.warn("[glasstrace] Cached config failed validation. Using defaults.");
@@ -372,7 +425,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
372
425
  } catch {
373
426
  }
374
427
  }
375
- async function performInit(config, anonKey, sdkVersion) {
428
+ async function performInit(config, anonKey, sdkVersion, healthReport) {
376
429
  if (rateLimitBackoff) {
377
430
  rateLimitBackoff = false;
378
431
  return null;
@@ -391,12 +444,16 @@ async function performInit(config, anonKey, sdkVersion) {
391
444
  anonKey,
392
445
  sdkVersion,
393
446
  void 0,
394
- void 0,
447
+ healthReport ?? void 0,
395
448
  void 0,
396
449
  controller.signal
397
450
  );
398
451
  clearTimeout(timeoutId);
399
452
  currentConfig = result;
453
+ recordConfigSync(Date.now());
454
+ if (healthReport) {
455
+ acknowledgeHealthReport(healthReport);
456
+ }
400
457
  await saveCachedConfig(result);
401
458
  if (result.claimResult) {
402
459
  try {
@@ -408,6 +465,7 @@ async function performInit(config, anonKey, sdkVersion) {
408
465
  return null;
409
466
  } catch (err) {
410
467
  clearTimeout(timeoutId);
468
+ recordInitFailure();
411
469
  if (err instanceof DOMException && err.name === "AbortError") {
412
470
  console.warn("[glasstrace] ingestion_unreachable: Init request timed out.");
413
471
  return null;
@@ -442,6 +500,7 @@ async function performInit(config, anonKey, sdkVersion) {
442
500
  return null;
443
501
  }
444
502
  } catch (err) {
503
+ recordInitFailure();
445
504
  console.warn(
446
505
  `[glasstrace] Unexpected init error: ${err instanceof Error ? err.message : String(err)}`
447
506
  );
@@ -527,7 +586,9 @@ var GlasstraceExporter = class {
527
586
  const exporter = this.ensureDelegate();
528
587
  if (exporter) {
529
588
  exporter.export(enrichedSpans, resultCallback);
589
+ recordSpansExported(enrichedSpans.length);
530
590
  } else {
591
+ recordSpansDropped(enrichedSpans.length);
531
592
  resultCallback({ code: 0 });
532
593
  }
533
594
  }
@@ -546,6 +607,7 @@ var GlasstraceExporter = class {
546
607
  console.warn(
547
608
  `[glasstrace] Shutdown with ${this.pendingSpanCount} buffered spans \u2014 API key never resolved, spans lost.`
548
609
  );
610
+ recordSpansDropped(this.pendingSpanCount);
549
611
  for (const batch of this.pendingBatches) {
550
612
  batch.resultCallback({ code: 0 });
551
613
  }
@@ -688,6 +750,7 @@ var GlasstraceExporter = class {
688
750
  while (this.pendingSpanCount > MAX_PENDING_SPANS && this.pendingBatches.length > 1) {
689
751
  const evicted = this.pendingBatches.shift();
690
752
  this.pendingSpanCount -= evicted.spans.length;
753
+ recordSpansDropped(evicted.spans.length);
691
754
  evicted.resultCallback({ code: 0 });
692
755
  if (!this.overflowLogged) {
693
756
  this.overflowLogged = true;
@@ -709,9 +772,12 @@ var GlasstraceExporter = class {
709
772
  if (this.pendingBatches.length === 0) return;
710
773
  const exporter = this.ensureDelegate();
711
774
  if (!exporter) {
775
+ let discardedCount = 0;
712
776
  for (const batch of this.pendingBatches) {
777
+ discardedCount += batch.spans.length;
713
778
  batch.resultCallback({ code: 0 });
714
779
  }
780
+ recordSpansDropped(discardedCount);
715
781
  this.pendingBatches = [];
716
782
  this.pendingSpanCount = 0;
717
783
  return;
@@ -722,6 +788,7 @@ var GlasstraceExporter = class {
722
788
  for (const batch of batches) {
723
789
  const enriched = batch.spans.map((span) => this.enrichSpan(span));
724
790
  exporter.export(enriched, batch.resultCallback);
791
+ recordSpansExported(enriched.length);
725
792
  }
726
793
  }
727
794
  };
@@ -3672,7 +3739,8 @@ async function backgroundInit(config, anonKeyForInit, generation) {
3672
3739
  if (config.verbose) {
3673
3740
  console.info("[glasstrace] Background init firing.");
3674
3741
  }
3675
- const initResult = await performInit(config, anonKeyForInit, "0.12.1");
3742
+ const healthReport = collectHealthReport("0.12.2");
3743
+ const initResult = await performInit(config, anonKeyForInit, "0.12.2", healthReport);
3676
3744
  if (generation !== registrationGeneration) return;
3677
3745
  if (initResult?.claimResult) {
3678
3746
  setResolvedApiKey(initResult.claimResult.newApiKey);