@glasstrace/sdk 1.3.3 → 1.3.4
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 +88 -0
- package/dist/{chunk-XNKG4WNQ.js → chunk-XFNK4YEW.js} +33 -7
- package/dist/chunk-XFNK4YEW.js.map +1 -0
- package/dist/cli/init.cjs +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/index.cjs +32 -6
- 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 +32 -6
- 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,94 @@ 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
|
+
Next 16 (`next build && next start`) registers an OpenTelemetry
|
|
169
|
+
TracerProvider before user code runs. When `registerGlasstrace()` then
|
|
170
|
+
detects that provider, the SDK attempts to attach its span processor to
|
|
171
|
+
the existing pipeline. On most providers this auto-attach succeeds and
|
|
172
|
+
no further action is required; on a small number of provider shapes —
|
|
173
|
+
including Next 16's production-runtime provider in some versions — the
|
|
174
|
+
provider exposes no injection point and auto-attach returns
|
|
175
|
+
unsuccessfully. In that case spans flow through the existing pipeline
|
|
176
|
+
without reaching the Glasstrace exporter, so no traces appear in MCP
|
|
177
|
+
queries or the dashboard.
|
|
178
|
+
|
|
179
|
+
The SDK signals this case in three ways:
|
|
180
|
+
|
|
181
|
+
1. **Log line.** The SDK logs a guidance message at `warn` level in
|
|
182
|
+
development and `error` level under `NODE_ENV=production`:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
[glasstrace] An existing OTel TracerProvider is registered but
|
|
186
|
+
Glasstrace could not auto-attach its span processor.
|
|
187
|
+
Add Glasstrace to your provider configuration:
|
|
188
|
+
...
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
2. **Programmatic signal.** `getStatus().tracing === "not-configured"`
|
|
192
|
+
after `registerGlasstrace()` has resolved indicates spans are not
|
|
193
|
+
reaching the Glasstrace exporter. Poll this from a health endpoint
|
|
194
|
+
or a startup readiness check:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { getStatus } from "@glasstrace/sdk";
|
|
198
|
+
|
|
199
|
+
const { tracing } = getStatus();
|
|
200
|
+
if (tracing === "not-configured") {
|
|
201
|
+
// Spans are not being exported. Apply the manual workaround below.
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
3. **CLI bridge.** `.glasstrace/runtime-state.json` carries a
|
|
206
|
+
structured `lastError` record that downstream tooling (custom
|
|
207
|
+
dashboards, CI assertions, the `npx @glasstrace/sdk status`
|
|
208
|
+
command in future releases) can surface verbatim:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"otel": { "state": "COEXISTENCE_FAILED", "scenario": "C/F" },
|
|
213
|
+
"lastError": {
|
|
214
|
+
"category": "auto-attach-returned-null",
|
|
215
|
+
"message": "tryAutoAttachGlasstraceProcessor returned null — ...",
|
|
216
|
+
"timestamp": "2026-05-04T12:34:56.789Z",
|
|
217
|
+
"providerClass": "BasicTracerProvider"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The `providerClass` field is the constructor name of the existing
|
|
223
|
+
provider's delegate. URLs, headers, and credentials are never
|
|
224
|
+
captured.
|
|
225
|
+
|
|
226
|
+
### Manual workaround
|
|
227
|
+
|
|
228
|
+
When auto-attach cannot succeed, register Glasstrace's span processor
|
|
229
|
+
on the provider you already own:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
|
|
233
|
+
import { createGlasstraceSpanProcessor } from "@glasstrace/sdk";
|
|
234
|
+
|
|
235
|
+
const provider = new BasicTracerProvider({
|
|
236
|
+
spanProcessors: [
|
|
237
|
+
// ... your existing processors,
|
|
238
|
+
createGlasstraceSpanProcessor(),
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
`createGlasstraceSpanProcessor()` produces a processor with the same
|
|
244
|
+
branded exporter the auto-attach path uses, so duplicate
|
|
245
|
+
`registerGlasstrace()` calls remain idempotent. `registerGlasstrace()`
|
|
246
|
+
is still required when wiring the processor manually — it handles the
|
|
247
|
+
init handshake, anonymous-key resolution, session management, and
|
|
248
|
+
discovery endpoint, none of which are owned by the span processor.
|
|
249
|
+
|
|
250
|
+
A future SDK release may extend the auto-attach detection to recognize
|
|
251
|
+
additional Next 16 provider shapes; until that ships, the manual path
|
|
252
|
+
above is the production-supported integration.
|
|
253
|
+
|
|
166
254
|
## Capturing error response bodies
|
|
167
255
|
|
|
168
256
|
When debugging a 4xx or 5xx, the response body is often the most useful
|
|
@@ -3763,11 +3763,27 @@ async function runCoexistencePath(existingProvider, config) {
|
|
|
3763
3763
|
setOtelState(OtelState.COEXISTENCE_FAILED);
|
|
3764
3764
|
emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
|
|
3765
3765
|
emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
|
|
3766
|
+
emitLifecycleEvent("otel:failed", {
|
|
3767
|
+
category: "auto-attach-returned-null",
|
|
3768
|
+
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.",
|
|
3769
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3770
|
+
providerClass: readProviderClass(existingProvider)
|
|
3771
|
+
});
|
|
3766
3772
|
const coreState = getCoreState();
|
|
3767
3773
|
if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
|
|
3768
3774
|
setCoreState(CoreState.ACTIVE_DEGRADED);
|
|
3769
3775
|
}
|
|
3770
3776
|
}
|
|
3777
|
+
function readProviderClass(tracerProvider) {
|
|
3778
|
+
try {
|
|
3779
|
+
const proxy = tracerProvider;
|
|
3780
|
+
const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
|
|
3781
|
+
const name = delegate?.constructor?.name;
|
|
3782
|
+
return typeof name === "string" && name.length > 0 ? name : void 0;
|
|
3783
|
+
} catch {
|
|
3784
|
+
return void 0;
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3771
3787
|
async function runRegistrationPath(config, sessionManager) {
|
|
3772
3788
|
const exporterUrl = `${config.endpoint}/v1/traces`;
|
|
3773
3789
|
const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
|
|
@@ -4152,6 +4168,7 @@ import { join } from "node:path";
|
|
|
4152
4168
|
var _projectRoot = null;
|
|
4153
4169
|
var _sdkVersion = "unknown";
|
|
4154
4170
|
var _lastScenario;
|
|
4171
|
+
var _lastError;
|
|
4155
4172
|
var _debounceTimer = null;
|
|
4156
4173
|
var _started = false;
|
|
4157
4174
|
function startRuntimeStateWriter(options) {
|
|
@@ -4174,6 +4191,10 @@ function startRuntimeStateWriter(options) {
|
|
|
4174
4191
|
_lastScenario = scenario;
|
|
4175
4192
|
debouncedWrite();
|
|
4176
4193
|
});
|
|
4194
|
+
onLifecycleEvent("otel:failed", (payload) => {
|
|
4195
|
+
_lastError = { ...payload };
|
|
4196
|
+
debouncedWrite();
|
|
4197
|
+
});
|
|
4177
4198
|
onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
|
|
4178
4199
|
onLifecycleEvent("auth:claim_started", () => debouncedWrite());
|
|
4179
4200
|
onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
|
|
@@ -4201,6 +4222,9 @@ function writeStateNow() {
|
|
|
4201
4222
|
auth: { state: state.auth },
|
|
4202
4223
|
otel: { state: state.otel, scenario: _lastScenario }
|
|
4203
4224
|
};
|
|
4225
|
+
if (_lastError) {
|
|
4226
|
+
runtimeState.lastError = _lastError;
|
|
4227
|
+
}
|
|
4204
4228
|
const dir = join(_projectRoot, ".glasstrace");
|
|
4205
4229
|
const filePath = join(dir, "runtime-state.json");
|
|
4206
4230
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -4245,7 +4269,7 @@ function registerGlasstrace(options) {
|
|
|
4245
4269
|
setCoreState(CoreState.REGISTERING);
|
|
4246
4270
|
startRuntimeStateWriter({
|
|
4247
4271
|
projectRoot: process.cwd(),
|
|
4248
|
-
sdkVersion: "1.3.
|
|
4272
|
+
sdkVersion: "1.3.4"
|
|
4249
4273
|
});
|
|
4250
4274
|
const config = resolveConfig(options);
|
|
4251
4275
|
if (config.verbose) {
|
|
@@ -4411,8 +4435,8 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4411
4435
|
if (config.verbose) {
|
|
4412
4436
|
console.info("[glasstrace] Background init firing.");
|
|
4413
4437
|
}
|
|
4414
|
-
const healthReport = collectHealthReport("1.3.
|
|
4415
|
-
const initResult = await performInit(config, anonKeyForInit, "1.3.
|
|
4438
|
+
const healthReport = collectHealthReport("1.3.4");
|
|
4439
|
+
const initResult = await performInit(config, anonKeyForInit, "1.3.4", healthReport);
|
|
4416
4440
|
if (generation !== registrationGeneration) return;
|
|
4417
4441
|
const currentState = getCoreState();
|
|
4418
4442
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -4435,7 +4459,7 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4435
4459
|
}
|
|
4436
4460
|
maybeInstallConsoleCapture();
|
|
4437
4461
|
if (didLastInitSucceed()) {
|
|
4438
|
-
startHeartbeat(config, anonKeyForInit, "1.3.
|
|
4462
|
+
startHeartbeat(config, anonKeyForInit, "1.3.4", generation, (newApiKey, accountId) => {
|
|
4439
4463
|
setAuthState(AuthState.CLAIMING);
|
|
4440
4464
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
4441
4465
|
setResolvedApiKey(newApiKey);
|
|
@@ -4572,9 +4596,11 @@ This message will not appear once Glasstrace is added to your provider config.`
|
|
|
4572
4596
|
}
|
|
4573
4597
|
function emitGuidanceMessage() {
|
|
4574
4598
|
const isSentry = detectSentry();
|
|
4599
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
4600
|
+
const level = isProduction ? "error" : "warn";
|
|
4575
4601
|
if (isSentry) {
|
|
4576
4602
|
sdkLog(
|
|
4577
|
-
|
|
4603
|
+
level,
|
|
4578
4604
|
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4579
4605
|
Add Glasstrace to your Sentry config:
|
|
4580
4606
|
|
|
@@ -4587,7 +4613,7 @@ Add Glasstrace to your Sentry config:
|
|
|
4587
4613
|
);
|
|
4588
4614
|
} else {
|
|
4589
4615
|
sdkLog(
|
|
4590
|
-
|
|
4616
|
+
level,
|
|
4591
4617
|
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4592
4618
|
Add Glasstrace to your provider configuration:
|
|
4593
4619
|
|
|
@@ -4833,4 +4859,4 @@ export {
|
|
|
4833
4859
|
withGlasstraceConfig,
|
|
4834
4860
|
captureError
|
|
4835
4861
|
};
|
|
4836
|
-
//# sourceMappingURL=chunk-
|
|
4862
|
+
//# sourceMappingURL=chunk-XFNK4YEW.js.map
|