@glasstrace/sdk 1.3.3 → 1.3.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.d.cts CHANGED
@@ -351,6 +351,25 @@ declare function waitForReady(timeoutMs?: number): Promise<void>;
351
351
  /**
352
352
  * Simplified public state query for external consumers.
353
353
  * Hides implementation details like coexistence scenarios.
354
+ *
355
+ * The returned `tracing` field is the canonical user-observable signal
356
+ * for OTel coexistence outcomes:
357
+ *
358
+ * - `"active"` — the SDK owns the OTel provider and is exporting spans.
359
+ * - `"coexistence"` — another OTel provider was detected and the SDK
360
+ * either auto-attached its span processor or found one already
361
+ * present. Spans are exported through the existing pipeline.
362
+ * - `"degraded"` — the SDK is exporting but the core lifecycle entered
363
+ * `ACTIVE_DEGRADED` (e.g., a non-fatal export failure).
364
+ * - `"not-configured"` — the SDK could not configure tracing. Covers
365
+ * `OtelState.UNCONFIGURED`, `OtelState.CONFIGURING`, and
366
+ * `OtelState.COEXISTENCE_FAILED` (the DISC-1556 Next 16 production
367
+ * "auto-attach returned null" path). When the value is
368
+ * `"not-configured"` after `registerGlasstrace()` has resolved,
369
+ * spans are NOT reaching the Glasstrace exporter and the manual
370
+ * `createGlasstraceSpanProcessor()` workaround should be applied.
371
+ * See `runtime-state.json`'s `lastError` field for the structured
372
+ * failure record.
354
373
  */
355
374
  declare function getStatus(): {
356
375
  ready: boolean;
package/dist/index.d.ts CHANGED
@@ -351,6 +351,25 @@ declare function waitForReady(timeoutMs?: number): Promise<void>;
351
351
  /**
352
352
  * Simplified public state query for external consumers.
353
353
  * Hides implementation details like coexistence scenarios.
354
+ *
355
+ * The returned `tracing` field is the canonical user-observable signal
356
+ * for OTel coexistence outcomes:
357
+ *
358
+ * - `"active"` — the SDK owns the OTel provider and is exporting spans.
359
+ * - `"coexistence"` — another OTel provider was detected and the SDK
360
+ * either auto-attached its span processor or found one already
361
+ * present. Spans are exported through the existing pipeline.
362
+ * - `"degraded"` — the SDK is exporting but the core lifecycle entered
363
+ * `ACTIVE_DEGRADED` (e.g., a non-fatal export failure).
364
+ * - `"not-configured"` — the SDK could not configure tracing. Covers
365
+ * `OtelState.UNCONFIGURED`, `OtelState.CONFIGURING`, and
366
+ * `OtelState.COEXISTENCE_FAILED` (the DISC-1556 Next 16 production
367
+ * "auto-attach returned null" path). When the value is
368
+ * `"not-configured"` after `registerGlasstrace()` has resolved,
369
+ * spans are NOT reaching the Glasstrace exporter and the manual
370
+ * `createGlasstraceSpanProcessor()` workaround should be applied.
371
+ * See `runtime-state.json`'s `lastError` field for the structured
372
+ * failure record.
354
373
  */
355
374
  declare function getStatus(): {
356
375
  ready: boolean;
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  registerGlasstrace,
13
13
  waitForReady,
14
14
  withGlasstraceConfig
15
- } from "./chunk-XNKG4WNQ.js";
15
+ } from "./chunk-EK6MYHR2.js";
16
16
  import {
17
17
  GlasstraceSpanProcessor,
18
18
  SdkError,
@@ -22112,9 +22112,11 @@ This message will not appear once Glasstrace is added to your provider config.`
22112
22112
  }
22113
22113
  function emitGuidanceMessage() {
22114
22114
  const isSentry = detectSentry();
22115
+ const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
22116
+ const level = isProduction ? "error" : "warn";
22115
22117
  if (isSentry) {
22116
22118
  sdkLog(
22117
- "warn",
22119
+ level,
22118
22120
  `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
22119
22121
  Add Glasstrace to your Sentry config:
22120
22122
 
@@ -22127,7 +22129,7 @@ Add Glasstrace to your Sentry config:
22127
22129
  );
22128
22130
  } else {
22129
22131
  sdkLog(
22130
- "warn",
22132
+ level,
22131
22133
  `[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
22132
22134
  Add Glasstrace to your provider configuration:
22133
22135
 
@@ -22162,6 +22164,27 @@ function detectSentry() {
22162
22164
  }
22163
22165
  }
22164
22166
 
22167
+ // src/proxy-detection.ts
22168
+ function isProxyTracerProvider(value) {
22169
+ if (value === null || value === void 0 || typeof value !== "object") {
22170
+ return false;
22171
+ }
22172
+ return "getTracer" in value && typeof value.getTracer === "function" && "getDelegate" in value && typeof value.getDelegate === "function" && "setDelegate" in value && typeof value.setDelegate === "function" && "getDelegateTracer" in value && typeof value.getDelegateTracer === "function";
22173
+ }
22174
+ function isProxyTracer(value, ownerProvider) {
22175
+ if (value === null || value === void 0 || typeof value !== "object") {
22176
+ return false;
22177
+ }
22178
+ const structurallyShaped = "_getTracer" in value && typeof value._getTracer === "function" && "startSpan" in value && typeof value.startSpan === "function" && "startActiveSpan" in value && typeof value.startActiveSpan === "function";
22179
+ if (!structurallyShaped) {
22180
+ return false;
22181
+ }
22182
+ if (!Object.hasOwn(value, "_provider")) {
22183
+ return false;
22184
+ }
22185
+ return value._provider === ownerProvider;
22186
+ }
22187
+
22165
22188
  // src/otel-config.ts
22166
22189
  var resolvedApiKey = API_KEY_PENDING;
22167
22190
  var activeExporter = null;
@@ -22200,7 +22223,7 @@ async function configureOtel(config2, sessionManager) {
22200
22223
  });
22201
22224
  const existingProvider = trace.getTracerProvider();
22202
22225
  const probeTracer = existingProvider.getTracer("glasstrace-probe");
22203
- const anotherProviderRegistered = probeTracer.constructor.name !== "ProxyTracer";
22226
+ const anotherProviderRegistered = !isProxyTracerProvider(existingProvider) || !isProxyTracer(probeTracer, existingProvider);
22204
22227
  if (anotherProviderRegistered) {
22205
22228
  setCoexistenceState("coexisting");
22206
22229
  await runCoexistencePath(existingProvider, config2);
@@ -22254,11 +22277,27 @@ async function runCoexistencePath(existingProvider, config2) {
22254
22277
  setOtelState(OtelState.COEXISTENCE_FAILED);
22255
22278
  emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
22256
22279
  emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
22280
+ emitLifecycleEvent("otel:failed", {
22281
+ category: "auto-attach-returned-null",
22282
+ message: "tryAutoAttachGlasstraceProcessor returned null \u2014 the existing OTel TracerProvider exposed no injection point. Spans are not reaching the Glasstrace exporter. Apply the manual createGlasstraceSpanProcessor() workaround documented in the SDK README.",
22283
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
22284
+ providerClass: readProviderClass(existingProvider)
22285
+ });
22257
22286
  const coreState = getCoreState();
22258
22287
  if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
22259
22288
  setCoreState(CoreState.ACTIVE_DEGRADED);
22260
22289
  }
22261
22290
  }
22291
+ function readProviderClass(tracerProvider) {
22292
+ try {
22293
+ const proxy = tracerProvider;
22294
+ const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
22295
+ const name = delegate?.constructor?.name;
22296
+ return typeof name === "string" && name.length > 0 ? name : void 0;
22297
+ } catch {
22298
+ return void 0;
22299
+ }
22300
+ }
22262
22301
  async function runRegistrationPath(config2, sessionManager) {
22263
22302
  const exporterUrl = `${config2.endpoint}/v1/traces`;
22264
22303
  const createOtlpExporter = (url2, headers) => new OTLPTraceExporter({ url: url2, headers });
@@ -22561,6 +22600,7 @@ init_console_capture();
22561
22600
  var _projectRoot = null;
22562
22601
  var _sdkVersion = "unknown";
22563
22602
  var _lastScenario;
22603
+ var _lastError;
22564
22604
  var _debounceTimer = null;
22565
22605
  var _started = false;
22566
22606
  function startRuntimeStateWriter(options) {
@@ -22583,6 +22623,10 @@ function startRuntimeStateWriter(options) {
22583
22623
  _lastScenario = scenario;
22584
22624
  debouncedWrite();
22585
22625
  });
22626
+ onLifecycleEvent("otel:failed", (payload) => {
22627
+ _lastError = { ...payload };
22628
+ debouncedWrite();
22629
+ });
22586
22630
  onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
22587
22631
  onLifecycleEvent("auth:claim_started", () => debouncedWrite());
22588
22632
  onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
@@ -22610,6 +22654,9 @@ function writeStateNow() {
22610
22654
  auth: { state: state.auth },
22611
22655
  otel: { state: state.otel, scenario: _lastScenario }
22612
22656
  };
22657
+ if (_lastError) {
22658
+ runtimeState.lastError = _lastError;
22659
+ }
22613
22660
  const dir = (0, import_node_path.join)(_projectRoot, ".glasstrace");
22614
22661
  const filePath = (0, import_node_path.join)(dir, "runtime-state.json");
22615
22662
  (0, import_node_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
@@ -22654,7 +22701,7 @@ function registerGlasstrace(options) {
22654
22701
  setCoreState(CoreState.REGISTERING);
22655
22702
  startRuntimeStateWriter({
22656
22703
  projectRoot: process.cwd(),
22657
- sdkVersion: "1.3.3"
22704
+ sdkVersion: "1.3.5"
22658
22705
  });
22659
22706
  const config2 = resolveConfig(options);
22660
22707
  if (config2.verbose) {
@@ -22670,8 +22717,9 @@ function registerGlasstrace(options) {
22670
22717
  if (config2.verbose) {
22671
22718
  console.info("[glasstrace] Not production-disabled.");
22672
22719
  }
22673
- const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
22674
- const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
22720
+ const existingTracerProvider = trace.getTracerProvider();
22721
+ const existingProbe = existingTracerProvider.getTracer("glasstrace-probe");
22722
+ const anotherProviderRegistered = !isProxyTracerProvider(existingTracerProvider) || !isProxyTracer(existingProbe, existingTracerProvider);
22675
22723
  if (anotherProviderRegistered) {
22676
22724
  setCoexistenceState("coexisting");
22677
22725
  }
@@ -22820,8 +22868,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
22820
22868
  if (config2.verbose) {
22821
22869
  console.info("[glasstrace] Background init firing.");
22822
22870
  }
22823
- const healthReport = collectHealthReport("1.3.3");
22824
- const initResult = await performInit(config2, anonKeyForInit, "1.3.3", healthReport);
22871
+ const healthReport = collectHealthReport("1.3.5");
22872
+ const initResult = await performInit(config2, anonKeyForInit, "1.3.5", healthReport);
22825
22873
  if (generation !== registrationGeneration) return;
22826
22874
  const currentState = getCoreState();
22827
22875
  if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
@@ -22844,7 +22892,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
22844
22892
  }
22845
22893
  maybeInstallConsoleCapture();
22846
22894
  if (didLastInitSucceed()) {
22847
- startHeartbeat(config2, anonKeyForInit, "1.3.3", generation, (newApiKey, accountId) => {
22895
+ startHeartbeat(config2, anonKeyForInit, "1.3.5", generation, (newApiKey, accountId) => {
22848
22896
  setAuthState(AuthState.CLAIMING);
22849
22897
  emitLifecycleEvent("auth:claim_started", { accountId });
22850
22898
  setResolvedApiKey(newApiKey);