@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/README.md +94 -0
- package/dist/{chunk-XNKG4WNQ.js → chunk-EK6MYHR2.js} +58 -10
- package/dist/chunk-EK6MYHR2.js.map +1 -0
- package/dist/cli/init.cjs +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/index.cjs +57 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1 -1
- package/dist/node-entry.cjs +57 -9
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-XNKG4WNQ.js.map +0 -1
package/README.md
CHANGED
|
@@ -163,6 +163,100 @@ GLASSTRACE_SUPPRESS_ACTION_NUDGE=1
|
|
|
163
163
|
The nudge never fires in production (detected via `NODE_ENV` or
|
|
164
164
|
`VERCEL_ENV`) unless `GLASSTRACE_FORCE_ENABLE=true` is also set.
|
|
165
165
|
|
|
166
|
+
## Production deployment under Next 16
|
|
167
|
+
|
|
168
|
+
As of `@glasstrace/sdk@1.3.5`, auto-attach detection now classifies the
|
|
169
|
+
SDK's own bundled proxy correctly under bundler minification (DISC-1556
|
|
170
|
+
— verified against the `clean-next-sdk130` validation fixture). The
|
|
171
|
+
manual integration documented below remains supported for users who
|
|
172
|
+
prefer explicit configuration.
|
|
173
|
+
|
|
174
|
+
Next 16 (`next build && next start`) registers an OpenTelemetry
|
|
175
|
+
TracerProvider before user code runs. When `registerGlasstrace()` then
|
|
176
|
+
detects that provider, the SDK attempts to attach its span processor to
|
|
177
|
+
the existing pipeline. On most providers this auto-attach succeeds and
|
|
178
|
+
no further action is required; on a small number of provider shapes —
|
|
179
|
+
including Next 16's production-runtime provider in some versions — the
|
|
180
|
+
provider exposes no injection point and auto-attach returns
|
|
181
|
+
unsuccessfully. In that case spans flow through the existing pipeline
|
|
182
|
+
without reaching the Glasstrace exporter, so no traces appear in MCP
|
|
183
|
+
queries or the dashboard.
|
|
184
|
+
|
|
185
|
+
The SDK signals this case in three ways:
|
|
186
|
+
|
|
187
|
+
1. **Log line.** The SDK logs a guidance message at `warn` level in
|
|
188
|
+
development and `error` level under `NODE_ENV=production`:
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
[glasstrace] An existing OTel TracerProvider is registered but
|
|
192
|
+
Glasstrace could not auto-attach its span processor.
|
|
193
|
+
Add Glasstrace to your provider configuration:
|
|
194
|
+
...
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
2. **Programmatic signal.** `getStatus().tracing === "not-configured"`
|
|
198
|
+
after `registerGlasstrace()` has resolved indicates spans are not
|
|
199
|
+
reaching the Glasstrace exporter. Poll this from a health endpoint
|
|
200
|
+
or a startup readiness check:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { getStatus } from "@glasstrace/sdk";
|
|
204
|
+
|
|
205
|
+
const { tracing } = getStatus();
|
|
206
|
+
if (tracing === "not-configured") {
|
|
207
|
+
// Spans are not being exported. Apply the manual workaround below.
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
3. **CLI bridge.** `.glasstrace/runtime-state.json` carries a
|
|
212
|
+
structured `lastError` record that downstream tooling (custom
|
|
213
|
+
dashboards, CI assertions, the `npx @glasstrace/sdk status`
|
|
214
|
+
command in future releases) can surface verbatim:
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"otel": { "state": "COEXISTENCE_FAILED", "scenario": "C/F" },
|
|
219
|
+
"lastError": {
|
|
220
|
+
"category": "auto-attach-returned-null",
|
|
221
|
+
"message": "tryAutoAttachGlasstraceProcessor returned null — ...",
|
|
222
|
+
"timestamp": "2026-05-04T12:34:56.789Z",
|
|
223
|
+
"providerClass": "BasicTracerProvider"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The `providerClass` field is the constructor name of the existing
|
|
229
|
+
provider's delegate. URLs, headers, and credentials are never
|
|
230
|
+
captured.
|
|
231
|
+
|
|
232
|
+
### Manual workaround
|
|
233
|
+
|
|
234
|
+
When auto-attach cannot succeed, register Glasstrace's span processor
|
|
235
|
+
on the provider you already own:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
|
|
239
|
+
import { createGlasstraceSpanProcessor } from "@glasstrace/sdk";
|
|
240
|
+
|
|
241
|
+
const provider = new BasicTracerProvider({
|
|
242
|
+
spanProcessors: [
|
|
243
|
+
// ... your existing processors,
|
|
244
|
+
createGlasstraceSpanProcessor(),
|
|
245
|
+
],
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`createGlasstraceSpanProcessor()` produces a processor with the same
|
|
250
|
+
branded exporter the auto-attach path uses, so duplicate
|
|
251
|
+
`registerGlasstrace()` calls remain idempotent. `registerGlasstrace()`
|
|
252
|
+
is still required when wiring the processor manually — it handles the
|
|
253
|
+
init handshake, anonymous-key resolution, session management, and
|
|
254
|
+
discovery endpoint, none of which are owned by the span processor.
|
|
255
|
+
|
|
256
|
+
A future SDK release may extend the auto-attach detection to recognize
|
|
257
|
+
additional Next 16 provider shapes; until that ships, the manual path
|
|
258
|
+
above is the production-supported integration.
|
|
259
|
+
|
|
166
260
|
## Capturing error response bodies
|
|
167
261
|
|
|
168
262
|
When debugging a 4xx or 5xx, the response body is often the most useful
|
|
@@ -3671,6 +3671,27 @@ var OTLPTraceExporter = class extends OTLPExporterBase {
|
|
|
3671
3671
|
}
|
|
3672
3672
|
};
|
|
3673
3673
|
|
|
3674
|
+
// src/proxy-detection.ts
|
|
3675
|
+
function isProxyTracerProvider(value) {
|
|
3676
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
3677
|
+
return false;
|
|
3678
|
+
}
|
|
3679
|
+
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";
|
|
3680
|
+
}
|
|
3681
|
+
function isProxyTracer(value, ownerProvider) {
|
|
3682
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
3683
|
+
return false;
|
|
3684
|
+
}
|
|
3685
|
+
const structurallyShaped = "_getTracer" in value && typeof value._getTracer === "function" && "startSpan" in value && typeof value.startSpan === "function" && "startActiveSpan" in value && typeof value.startActiveSpan === "function";
|
|
3686
|
+
if (!structurallyShaped) {
|
|
3687
|
+
return false;
|
|
3688
|
+
}
|
|
3689
|
+
if (!Object.hasOwn(value, "_provider")) {
|
|
3690
|
+
return false;
|
|
3691
|
+
}
|
|
3692
|
+
return value._provider === ownerProvider;
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3674
3695
|
// src/otel-config.ts
|
|
3675
3696
|
var resolvedApiKey = API_KEY_PENDING;
|
|
3676
3697
|
var activeExporter = null;
|
|
@@ -3709,7 +3730,7 @@ async function configureOtel(config, sessionManager) {
|
|
|
3709
3730
|
});
|
|
3710
3731
|
const existingProvider = trace.getTracerProvider();
|
|
3711
3732
|
const probeTracer = existingProvider.getTracer("glasstrace-probe");
|
|
3712
|
-
const anotherProviderRegistered = probeTracer
|
|
3733
|
+
const anotherProviderRegistered = !isProxyTracerProvider(existingProvider) || !isProxyTracer(probeTracer, existingProvider);
|
|
3713
3734
|
if (anotherProviderRegistered) {
|
|
3714
3735
|
setCoexistenceState("coexisting");
|
|
3715
3736
|
await runCoexistencePath(existingProvider, config);
|
|
@@ -3763,11 +3784,27 @@ async function runCoexistencePath(existingProvider, config) {
|
|
|
3763
3784
|
setOtelState(OtelState.COEXISTENCE_FAILED);
|
|
3764
3785
|
emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
|
|
3765
3786
|
emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
|
|
3787
|
+
emitLifecycleEvent("otel:failed", {
|
|
3788
|
+
category: "auto-attach-returned-null",
|
|
3789
|
+
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.",
|
|
3790
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3791
|
+
providerClass: readProviderClass(existingProvider)
|
|
3792
|
+
});
|
|
3766
3793
|
const coreState = getCoreState();
|
|
3767
3794
|
if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
|
|
3768
3795
|
setCoreState(CoreState.ACTIVE_DEGRADED);
|
|
3769
3796
|
}
|
|
3770
3797
|
}
|
|
3798
|
+
function readProviderClass(tracerProvider) {
|
|
3799
|
+
try {
|
|
3800
|
+
const proxy = tracerProvider;
|
|
3801
|
+
const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
|
|
3802
|
+
const name = delegate?.constructor?.name;
|
|
3803
|
+
return typeof name === "string" && name.length > 0 ? name : void 0;
|
|
3804
|
+
} catch {
|
|
3805
|
+
return void 0;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3771
3808
|
async function runRegistrationPath(config, sessionManager) {
|
|
3772
3809
|
const exporterUrl = `${config.endpoint}/v1/traces`;
|
|
3773
3810
|
const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
|
|
@@ -4152,6 +4189,7 @@ import { join } from "node:path";
|
|
|
4152
4189
|
var _projectRoot = null;
|
|
4153
4190
|
var _sdkVersion = "unknown";
|
|
4154
4191
|
var _lastScenario;
|
|
4192
|
+
var _lastError;
|
|
4155
4193
|
var _debounceTimer = null;
|
|
4156
4194
|
var _started = false;
|
|
4157
4195
|
function startRuntimeStateWriter(options) {
|
|
@@ -4174,6 +4212,10 @@ function startRuntimeStateWriter(options) {
|
|
|
4174
4212
|
_lastScenario = scenario;
|
|
4175
4213
|
debouncedWrite();
|
|
4176
4214
|
});
|
|
4215
|
+
onLifecycleEvent("otel:failed", (payload) => {
|
|
4216
|
+
_lastError = { ...payload };
|
|
4217
|
+
debouncedWrite();
|
|
4218
|
+
});
|
|
4177
4219
|
onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
|
|
4178
4220
|
onLifecycleEvent("auth:claim_started", () => debouncedWrite());
|
|
4179
4221
|
onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
|
|
@@ -4201,6 +4243,9 @@ function writeStateNow() {
|
|
|
4201
4243
|
auth: { state: state.auth },
|
|
4202
4244
|
otel: { state: state.otel, scenario: _lastScenario }
|
|
4203
4245
|
};
|
|
4246
|
+
if (_lastError) {
|
|
4247
|
+
runtimeState.lastError = _lastError;
|
|
4248
|
+
}
|
|
4204
4249
|
const dir = join(_projectRoot, ".glasstrace");
|
|
4205
4250
|
const filePath = join(dir, "runtime-state.json");
|
|
4206
4251
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -4245,7 +4290,7 @@ function registerGlasstrace(options) {
|
|
|
4245
4290
|
setCoreState(CoreState.REGISTERING);
|
|
4246
4291
|
startRuntimeStateWriter({
|
|
4247
4292
|
projectRoot: process.cwd(),
|
|
4248
|
-
sdkVersion: "1.3.
|
|
4293
|
+
sdkVersion: "1.3.5"
|
|
4249
4294
|
});
|
|
4250
4295
|
const config = resolveConfig(options);
|
|
4251
4296
|
if (config.verbose) {
|
|
@@ -4261,8 +4306,9 @@ function registerGlasstrace(options) {
|
|
|
4261
4306
|
if (config.verbose) {
|
|
4262
4307
|
console.info("[glasstrace] Not production-disabled.");
|
|
4263
4308
|
}
|
|
4264
|
-
const
|
|
4265
|
-
const
|
|
4309
|
+
const existingTracerProvider = trace.getTracerProvider();
|
|
4310
|
+
const existingProbe = existingTracerProvider.getTracer("glasstrace-probe");
|
|
4311
|
+
const anotherProviderRegistered = !isProxyTracerProvider(existingTracerProvider) || !isProxyTracer(existingProbe, existingTracerProvider);
|
|
4266
4312
|
if (anotherProviderRegistered) {
|
|
4267
4313
|
setCoexistenceState("coexisting");
|
|
4268
4314
|
}
|
|
@@ -4411,8 +4457,8 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4411
4457
|
if (config.verbose) {
|
|
4412
4458
|
console.info("[glasstrace] Background init firing.");
|
|
4413
4459
|
}
|
|
4414
|
-
const healthReport = collectHealthReport("1.3.
|
|
4415
|
-
const initResult = await performInit(config, anonKeyForInit, "1.3.
|
|
4460
|
+
const healthReport = collectHealthReport("1.3.5");
|
|
4461
|
+
const initResult = await performInit(config, anonKeyForInit, "1.3.5", healthReport);
|
|
4416
4462
|
if (generation !== registrationGeneration) return;
|
|
4417
4463
|
const currentState = getCoreState();
|
|
4418
4464
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -4435,7 +4481,7 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4435
4481
|
}
|
|
4436
4482
|
maybeInstallConsoleCapture();
|
|
4437
4483
|
if (didLastInitSucceed()) {
|
|
4438
|
-
startHeartbeat(config, anonKeyForInit, "1.3.
|
|
4484
|
+
startHeartbeat(config, anonKeyForInit, "1.3.5", generation, (newApiKey, accountId) => {
|
|
4439
4485
|
setAuthState(AuthState.CLAIMING);
|
|
4440
4486
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
4441
4487
|
setResolvedApiKey(newApiKey);
|
|
@@ -4572,9 +4618,11 @@ This message will not appear once Glasstrace is added to your provider config.`
|
|
|
4572
4618
|
}
|
|
4573
4619
|
function emitGuidanceMessage() {
|
|
4574
4620
|
const isSentry = detectSentry();
|
|
4621
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
4622
|
+
const level = isProduction ? "error" : "warn";
|
|
4575
4623
|
if (isSentry) {
|
|
4576
4624
|
sdkLog(
|
|
4577
|
-
|
|
4625
|
+
level,
|
|
4578
4626
|
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4579
4627
|
Add Glasstrace to your Sentry config:
|
|
4580
4628
|
|
|
@@ -4587,7 +4635,7 @@ Add Glasstrace to your Sentry config:
|
|
|
4587
4635
|
);
|
|
4588
4636
|
} else {
|
|
4589
4637
|
sdkLog(
|
|
4590
|
-
|
|
4638
|
+
level,
|
|
4591
4639
|
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4592
4640
|
Add Glasstrace to your provider configuration:
|
|
4593
4641
|
|
|
@@ -4833,4 +4881,4 @@ export {
|
|
|
4833
4881
|
withGlasstraceConfig,
|
|
4834
4882
|
captureError
|
|
4835
4883
|
};
|
|
4836
|
-
//# sourceMappingURL=chunk-
|
|
4884
|
+
//# sourceMappingURL=chunk-EK6MYHR2.js.map
|