@glasstrace/sdk 0.13.5 → 0.14.0
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/{chunk-DF52INSK.js → chunk-ECEN724Y.js} +2 -2
- package/dist/{chunk-7MHQRVVW.js → chunk-ERGEG4ZQ.js} +2 -3
- package/dist/chunk-ERGEG4ZQ.js.map +1 -0
- package/dist/{chunk-AMFO5UL4.js → chunk-UPS5BGER.js} +2 -2
- package/dist/{chunk-UJ74MD4Y.js → chunk-YMEXDDTA.js} +7 -3
- package/dist/{chunk-UJ74MD4Y.js.map → chunk-YMEXDDTA.js.map} +1 -1
- package/dist/cli/init.cjs +68 -3
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +3 -3
- package/dist/cli/mcp-add.cjs +2 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +2 -2
- package/dist/cli/status.cjs +65 -1
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.d.cts +22 -1
- package/dist/cli/status.d.ts +22 -1
- package/dist/cli/status.js +65 -1
- package/dist/cli/status.js.map +1 -1
- package/dist/index.cjs +825 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -2
- package/dist/index.d.ts +71 -2
- package/dist/index.js +815 -64
- package/dist/index.js.map +1 -1
- package/dist/{source-map-uploader-EWA2XQI4.js → source-map-uploader-W6VPGY26.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-7MHQRVVW.js.map +0 -1
- /package/dist/{chunk-DF52INSK.js.map → chunk-ECEN724Y.js.map} +0 -0
- /package/dist/{chunk-AMFO5UL4.js.map → chunk-UPS5BGER.js.map} +0 -0
- /package/dist/{source-map-uploader-EWA2XQI4.js.map → source-map-uploader-W6VPGY26.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -13,23 +13,23 @@ import {
|
|
|
13
13
|
uploadSourceMaps,
|
|
14
14
|
uploadSourceMapsAuto,
|
|
15
15
|
uploadSourceMapsPresigned
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ERGEG4ZQ.js";
|
|
17
17
|
import {
|
|
18
18
|
buildImportGraph,
|
|
19
19
|
discoverTestFiles,
|
|
20
20
|
extractImports
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-UPS5BGER.js";
|
|
22
22
|
import {
|
|
23
23
|
getOrCreateAnonKey,
|
|
24
24
|
readAnonKey
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-ECEN724Y.js";
|
|
26
26
|
import {
|
|
27
27
|
DEFAULT_CAPTURE_CONFIG,
|
|
28
28
|
GLASSTRACE_ATTRIBUTE_NAMES,
|
|
29
29
|
SdkCachedConfigSchema,
|
|
30
30
|
SdkInitResponseSchema,
|
|
31
31
|
SessionIdSchema
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-YMEXDDTA.js";
|
|
33
33
|
import {
|
|
34
34
|
DiagLogLevel,
|
|
35
35
|
INVALID_SPAN_CONTEXT,
|
|
@@ -325,7 +325,6 @@ async function sendInitRequest(config, anonKey, sdkVersion, importGraph, healthR
|
|
|
325
325
|
throw new Error("No API key available for init request");
|
|
326
326
|
}
|
|
327
327
|
const payload = {
|
|
328
|
-
apiKey: effectiveKey,
|
|
329
328
|
sdkVersion
|
|
330
329
|
};
|
|
331
330
|
if (config.apiKey && anonKey) {
|
|
@@ -562,7 +561,7 @@ init_esm_shims();
|
|
|
562
561
|
var GlasstraceSpanProcessor = class {
|
|
563
562
|
wrappedProcessor;
|
|
564
563
|
/* eslint-disable @typescript-eslint/no-unused-vars -- backward compat signature */
|
|
565
|
-
constructor(wrappedProcessor,
|
|
564
|
+
constructor(wrappedProcessor, _sessionManager2, _apiKey, _getConfig, _environment) {
|
|
566
565
|
this.wrappedProcessor = wrappedProcessor;
|
|
567
566
|
}
|
|
568
567
|
onStart(span, parentContext) {
|
|
@@ -591,6 +590,7 @@ var GlasstraceExporter = class {
|
|
|
591
590
|
environment;
|
|
592
591
|
endpointUrl;
|
|
593
592
|
createDelegateFn;
|
|
593
|
+
verbose;
|
|
594
594
|
delegate = null;
|
|
595
595
|
delegateKey = null;
|
|
596
596
|
pendingBatches = [];
|
|
@@ -603,6 +603,8 @@ var GlasstraceExporter = class {
|
|
|
603
603
|
this.environment = options.environment;
|
|
604
604
|
this.endpointUrl = options.endpointUrl;
|
|
605
605
|
this.createDelegateFn = options.createDelegate;
|
|
606
|
+
this.verbose = options.verbose ?? false;
|
|
607
|
+
this[/* @__PURE__ */ Symbol.for("glasstrace.exporter")] = true;
|
|
606
608
|
}
|
|
607
609
|
export(spans, resultCallback) {
|
|
608
610
|
const currentKey = this.getApiKey();
|
|
@@ -700,6 +702,22 @@ var GlasstraceExporter = class {
|
|
|
700
702
|
if (route) {
|
|
701
703
|
extra[ATTR.ROUTE] = route;
|
|
702
704
|
}
|
|
705
|
+
const rawUrl = attrs["http.url"] ?? attrs["url.full"] ?? attrs["http.target"];
|
|
706
|
+
const trpcUrl = typeof rawUrl === "string" ? rawUrl : void 0;
|
|
707
|
+
if (trpcUrl) {
|
|
708
|
+
const trpcMatch = trpcUrl.match(/\/api\/trpc\/([^/?#]+)/);
|
|
709
|
+
if (trpcMatch) {
|
|
710
|
+
let procedure;
|
|
711
|
+
try {
|
|
712
|
+
procedure = decodeURIComponent(trpcMatch[1]);
|
|
713
|
+
} catch {
|
|
714
|
+
procedure = trpcMatch[1];
|
|
715
|
+
}
|
|
716
|
+
if (procedure) {
|
|
717
|
+
extra[ATTR.TRPC_PROCEDURE] = procedure;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
703
721
|
const method = attrs["http.method"] ?? attrs["http.request.method"];
|
|
704
722
|
if (method) {
|
|
705
723
|
extra[ATTR.HTTP_METHOD] = method;
|
|
@@ -708,7 +726,17 @@ var GlasstraceExporter = class {
|
|
|
708
726
|
if (statusCode !== void 0) {
|
|
709
727
|
extra[ATTR.HTTP_STATUS_CODE] = statusCode;
|
|
710
728
|
}
|
|
711
|
-
|
|
729
|
+
const isErrorByStatus = span.status?.code === SpanStatusCode.ERROR;
|
|
730
|
+
const isErrorByEvent = hasExceptionEvent(span);
|
|
731
|
+
const isErrorByAttrs = typeof attrs["exception.type"] === "string" || typeof attrs["exception.message"] === "string";
|
|
732
|
+
const statusNotExplicitlyOK = span.status?.code !== SpanStatusCode.OK;
|
|
733
|
+
if (this.verbose && method) {
|
|
734
|
+
sdkLog(
|
|
735
|
+
"info",
|
|
736
|
+
`[glasstrace] enrichSpan "${name}": status.code=${span.status?.code}, http.status_code=${statusCode}, isErrorByStatus=${isErrorByStatus}, isErrorByEvent=${isErrorByEvent}, isErrorByAttrs=${isErrorByAttrs}`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
if (method && statusNotExplicitlyOK && (isErrorByStatus || isErrorByEvent || isErrorByAttrs)) {
|
|
712
740
|
if (statusCode === void 0 || statusCode === 0 || statusCode === 200) {
|
|
713
741
|
const httpErrorType = attrs["error.type"];
|
|
714
742
|
if (typeof httpErrorType === "string") {
|
|
@@ -721,6 +749,12 @@ var GlasstraceExporter = class {
|
|
|
721
749
|
} else {
|
|
722
750
|
extra[ATTR.HTTP_STATUS_CODE] = 500;
|
|
723
751
|
}
|
|
752
|
+
if (this.verbose) {
|
|
753
|
+
sdkLog(
|
|
754
|
+
"info",
|
|
755
|
+
`[glasstrace] enrichSpan "${name}": inferred status_code=${extra[ATTR.HTTP_STATUS_CODE]} (was ${statusCode}), error.type=${attrs["error.type"]}`
|
|
756
|
+
);
|
|
757
|
+
}
|
|
724
758
|
}
|
|
725
759
|
}
|
|
726
760
|
if (span.startTime && span.endTime) {
|
|
@@ -731,19 +765,39 @@ var GlasstraceExporter = class {
|
|
|
731
765
|
extra[ATTR.HTTP_DURATION_MS] = durationMs;
|
|
732
766
|
}
|
|
733
767
|
}
|
|
768
|
+
const eventDetails = statusNotExplicitlyOK ? getExceptionEventDetails(span) : { type: void 0, message: void 0 };
|
|
734
769
|
const errorMessage = attrs["exception.message"];
|
|
735
770
|
if (typeof errorMessage === "string") {
|
|
736
771
|
extra[ATTR.ERROR_MESSAGE] = errorMessage;
|
|
772
|
+
} else if (eventDetails.message) {
|
|
773
|
+
extra[ATTR.ERROR_MESSAGE] = eventDetails.message;
|
|
737
774
|
}
|
|
738
775
|
const errorType = attrs["exception.type"];
|
|
739
776
|
if (typeof errorType === "string") {
|
|
740
777
|
extra[ATTR.ERROR_CODE] = errorType;
|
|
741
778
|
extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(errorType);
|
|
779
|
+
} else if (eventDetails.type) {
|
|
780
|
+
extra[ATTR.ERROR_CODE] = eventDetails.type;
|
|
781
|
+
extra[ATTR.ERROR_CATEGORY] = deriveErrorCategory(eventDetails.type);
|
|
782
|
+
}
|
|
783
|
+
if (this.verbose && (extra[ATTR.ERROR_MESSAGE] || extra[ATTR.ERROR_CODE])) {
|
|
784
|
+
const msgSource = typeof errorMessage === "string" ? "attrs" : eventDetails.message ? "event" : "none";
|
|
785
|
+
const typeSource = typeof errorType === "string" ? "attrs" : eventDetails.type ? "event" : "none";
|
|
786
|
+
sdkLog(
|
|
787
|
+
"info",
|
|
788
|
+
`[glasstrace] enrichSpan "${name}": error.message source=${msgSource}, error.code source=${typeSource}`
|
|
789
|
+
);
|
|
742
790
|
}
|
|
743
791
|
const errorField = attrs["error.field"];
|
|
744
792
|
if (typeof errorField === "string") {
|
|
745
793
|
extra[ATTR.ERROR_FIELD] = errorField;
|
|
746
794
|
}
|
|
795
|
+
if (this.getConfig().errorResponseBodies) {
|
|
796
|
+
const responseBody = attrs["glasstrace.internal.response_body"];
|
|
797
|
+
if (typeof responseBody === "string") {
|
|
798
|
+
extra[ATTR.ERROR_RESPONSE_BODY] = responseBody.slice(0, 500);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
747
801
|
const spanAny = span;
|
|
748
802
|
const instrumentationName = spanAny.instrumentationScope?.name ?? spanAny.instrumentationLibrary?.name ?? "";
|
|
749
803
|
const ormProvider = deriveOrmProvider(instrumentationName);
|
|
@@ -861,6 +915,21 @@ function createEnrichedSpan(span, extra) {
|
|
|
861
915
|
}
|
|
862
916
|
});
|
|
863
917
|
}
|
|
918
|
+
function hasExceptionEvent(span) {
|
|
919
|
+
return span.events?.some((e) => e.name === "exception") ?? false;
|
|
920
|
+
}
|
|
921
|
+
function getExceptionEventDetails(span) {
|
|
922
|
+
const event = span.events?.find((e) => e.name === "exception");
|
|
923
|
+
if (!event?.attributes) {
|
|
924
|
+
return { type: void 0, message: void 0 };
|
|
925
|
+
}
|
|
926
|
+
const type = event.attributes["exception.type"];
|
|
927
|
+
const message = event.attributes["exception.message"];
|
|
928
|
+
return {
|
|
929
|
+
type: typeof type === "string" ? type : void 0,
|
|
930
|
+
message: typeof message === "string" ? message : void 0
|
|
931
|
+
};
|
|
932
|
+
}
|
|
864
933
|
function deriveOrmProvider(instrumentationName) {
|
|
865
934
|
const lower = instrumentationName.toLowerCase();
|
|
866
935
|
if (lower.includes("prisma")) {
|
|
@@ -3707,10 +3776,458 @@ var BasicTracerProvider = class {
|
|
|
3707
3776
|
}
|
|
3708
3777
|
};
|
|
3709
3778
|
|
|
3779
|
+
// src/lifecycle.ts
|
|
3780
|
+
init_esm_shims();
|
|
3781
|
+
import { EventEmitter } from "events";
|
|
3782
|
+
var CoreState = {
|
|
3783
|
+
IDLE: "IDLE",
|
|
3784
|
+
REGISTERING: "REGISTERING",
|
|
3785
|
+
KEY_PENDING: "KEY_PENDING",
|
|
3786
|
+
KEY_RESOLVED: "KEY_RESOLVED",
|
|
3787
|
+
ACTIVE: "ACTIVE",
|
|
3788
|
+
ACTIVE_DEGRADED: "ACTIVE_DEGRADED",
|
|
3789
|
+
SHUTTING_DOWN: "SHUTTING_DOWN",
|
|
3790
|
+
SHUTDOWN: "SHUTDOWN",
|
|
3791
|
+
PRODUCTION_DISABLED: "PRODUCTION_DISABLED",
|
|
3792
|
+
REGISTRATION_FAILED: "REGISTRATION_FAILED"
|
|
3793
|
+
};
|
|
3794
|
+
var AuthState = {
|
|
3795
|
+
ANONYMOUS: "ANONYMOUS",
|
|
3796
|
+
AUTHENTICATED: "AUTHENTICATED",
|
|
3797
|
+
CLAIMING: "CLAIMING",
|
|
3798
|
+
CLAIMED: "CLAIMED"
|
|
3799
|
+
};
|
|
3800
|
+
var OtelState = {
|
|
3801
|
+
UNCONFIGURED: "UNCONFIGURED",
|
|
3802
|
+
CONFIGURING: "CONFIGURING",
|
|
3803
|
+
OWNS_PROVIDER: "OWNS_PROVIDER",
|
|
3804
|
+
AUTO_ATTACHED: "AUTO_ATTACHED",
|
|
3805
|
+
PROCESSOR_PRESENT: "PROCESSOR_PRESENT",
|
|
3806
|
+
COEXISTENCE_FAILED: "COEXISTENCE_FAILED"
|
|
3807
|
+
};
|
|
3808
|
+
var VALID_CORE_TRANSITIONS = {
|
|
3809
|
+
[CoreState.IDLE]: [CoreState.REGISTERING, CoreState.REGISTRATION_FAILED, CoreState.SHUTTING_DOWN],
|
|
3810
|
+
[CoreState.REGISTERING]: [
|
|
3811
|
+
CoreState.KEY_PENDING,
|
|
3812
|
+
CoreState.PRODUCTION_DISABLED,
|
|
3813
|
+
CoreState.REGISTRATION_FAILED,
|
|
3814
|
+
CoreState.SHUTTING_DOWN
|
|
3815
|
+
],
|
|
3816
|
+
[CoreState.KEY_PENDING]: [
|
|
3817
|
+
CoreState.KEY_RESOLVED,
|
|
3818
|
+
CoreState.REGISTRATION_FAILED,
|
|
3819
|
+
CoreState.SHUTTING_DOWN
|
|
3820
|
+
],
|
|
3821
|
+
[CoreState.KEY_RESOLVED]: [
|
|
3822
|
+
CoreState.ACTIVE,
|
|
3823
|
+
CoreState.ACTIVE_DEGRADED,
|
|
3824
|
+
CoreState.SHUTTING_DOWN
|
|
3825
|
+
],
|
|
3826
|
+
[CoreState.ACTIVE]: [
|
|
3827
|
+
CoreState.ACTIVE_DEGRADED,
|
|
3828
|
+
CoreState.SHUTTING_DOWN
|
|
3829
|
+
],
|
|
3830
|
+
[CoreState.ACTIVE_DEGRADED]: [
|
|
3831
|
+
CoreState.ACTIVE,
|
|
3832
|
+
CoreState.SHUTTING_DOWN
|
|
3833
|
+
],
|
|
3834
|
+
[CoreState.SHUTTING_DOWN]: [CoreState.SHUTDOWN],
|
|
3835
|
+
[CoreState.SHUTDOWN]: [],
|
|
3836
|
+
[CoreState.PRODUCTION_DISABLED]: [],
|
|
3837
|
+
[CoreState.REGISTRATION_FAILED]: []
|
|
3838
|
+
};
|
|
3839
|
+
var VALID_AUTH_TRANSITIONS = {
|
|
3840
|
+
[AuthState.ANONYMOUS]: [AuthState.CLAIMING],
|
|
3841
|
+
[AuthState.AUTHENTICATED]: [AuthState.CLAIMING],
|
|
3842
|
+
[AuthState.CLAIMING]: [AuthState.CLAIMED],
|
|
3843
|
+
[AuthState.CLAIMED]: [AuthState.CLAIMING]
|
|
3844
|
+
};
|
|
3845
|
+
var VALID_OTEL_TRANSITIONS = {
|
|
3846
|
+
[OtelState.UNCONFIGURED]: [OtelState.CONFIGURING],
|
|
3847
|
+
[OtelState.CONFIGURING]: [
|
|
3848
|
+
OtelState.OWNS_PROVIDER,
|
|
3849
|
+
OtelState.AUTO_ATTACHED,
|
|
3850
|
+
OtelState.PROCESSOR_PRESENT,
|
|
3851
|
+
OtelState.COEXISTENCE_FAILED
|
|
3852
|
+
],
|
|
3853
|
+
[OtelState.OWNS_PROVIDER]: [],
|
|
3854
|
+
[OtelState.AUTO_ATTACHED]: [],
|
|
3855
|
+
[OtelState.PROCESSOR_PRESENT]: [],
|
|
3856
|
+
[OtelState.COEXISTENCE_FAILED]: []
|
|
3857
|
+
};
|
|
3858
|
+
var _coreState = CoreState.IDLE;
|
|
3859
|
+
var _authState = AuthState.ANONYMOUS;
|
|
3860
|
+
var _otelState = OtelState.UNCONFIGURED;
|
|
3861
|
+
var _emitter = new EventEmitter();
|
|
3862
|
+
var _logger = null;
|
|
3863
|
+
var _initialized = false;
|
|
3864
|
+
var _initWarned = false;
|
|
3865
|
+
var _coreReadyEmitted = false;
|
|
3866
|
+
var _authInitialized = false;
|
|
3867
|
+
var _emitting = false;
|
|
3868
|
+
function initLifecycle(options) {
|
|
3869
|
+
if (_initialized) {
|
|
3870
|
+
options.logger("warn", "[glasstrace] initLifecycle() called twice \u2014 ignored.");
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
_logger = options.logger;
|
|
3874
|
+
_initialized = true;
|
|
3875
|
+
}
|
|
3876
|
+
function warnIfNotInitialized() {
|
|
3877
|
+
if (!_initialized && !_initWarned) {
|
|
3878
|
+
_initWarned = true;
|
|
3879
|
+
console.warn(
|
|
3880
|
+
"[glasstrace] Lifecycle state changed before initLifecycle() was called. Logger not available \u2014 errors will be silent."
|
|
3881
|
+
);
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
function setCoreState(to) {
|
|
3885
|
+
warnIfNotInitialized();
|
|
3886
|
+
const from = _coreState;
|
|
3887
|
+
if (from === to) return;
|
|
3888
|
+
const valid = VALID_CORE_TRANSITIONS[from];
|
|
3889
|
+
if (!valid.includes(to)) {
|
|
3890
|
+
_logger?.(
|
|
3891
|
+
"warn",
|
|
3892
|
+
`[glasstrace] Invalid core state transition: ${from} \u2192 ${to}. Ignored.`
|
|
3893
|
+
);
|
|
3894
|
+
return;
|
|
3895
|
+
}
|
|
3896
|
+
_coreState = to;
|
|
3897
|
+
if (_emitting) return;
|
|
3898
|
+
_emitting = true;
|
|
3899
|
+
try {
|
|
3900
|
+
emitSafe("core:state_changed", { from, to });
|
|
3901
|
+
const current = _coreState;
|
|
3902
|
+
if (!_coreReadyEmitted && (current === CoreState.ACTIVE || current === CoreState.ACTIVE_DEGRADED)) {
|
|
3903
|
+
_coreReadyEmitted = true;
|
|
3904
|
+
emitSafe("core:ready", {});
|
|
3905
|
+
}
|
|
3906
|
+
if (current === CoreState.SHUTTING_DOWN) {
|
|
3907
|
+
emitSafe("core:shutdown_started", {});
|
|
3908
|
+
}
|
|
3909
|
+
if (current === CoreState.SHUTDOWN) {
|
|
3910
|
+
emitSafe("core:shutdown_completed", {});
|
|
3911
|
+
}
|
|
3912
|
+
} finally {
|
|
3913
|
+
_emitting = false;
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
function initAuthState(state) {
|
|
3917
|
+
if (_authInitialized) {
|
|
3918
|
+
_logger?.(
|
|
3919
|
+
"warn",
|
|
3920
|
+
"[glasstrace] initAuthState() called after auth state already initialized. Ignored."
|
|
3921
|
+
);
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3924
|
+
_authInitialized = true;
|
|
3925
|
+
_authState = state;
|
|
3926
|
+
}
|
|
3927
|
+
function setAuthState(to) {
|
|
3928
|
+
warnIfNotInitialized();
|
|
3929
|
+
const from = _authState;
|
|
3930
|
+
if (from === to) return;
|
|
3931
|
+
const valid = VALID_AUTH_TRANSITIONS[from];
|
|
3932
|
+
if (!valid.includes(to)) {
|
|
3933
|
+
_logger?.(
|
|
3934
|
+
"warn",
|
|
3935
|
+
`[glasstrace] Invalid auth state transition: ${from} \u2192 ${to}. Ignored.`
|
|
3936
|
+
);
|
|
3937
|
+
return;
|
|
3938
|
+
}
|
|
3939
|
+
_authState = to;
|
|
3940
|
+
}
|
|
3941
|
+
function setOtelState(to) {
|
|
3942
|
+
warnIfNotInitialized();
|
|
3943
|
+
const from = _otelState;
|
|
3944
|
+
if (from === to) return;
|
|
3945
|
+
const valid = VALID_OTEL_TRANSITIONS[from];
|
|
3946
|
+
if (!valid.includes(to)) {
|
|
3947
|
+
_logger?.(
|
|
3948
|
+
"warn",
|
|
3949
|
+
`[glasstrace] Invalid OTel state transition: ${from} \u2192 ${to}. Ignored.`
|
|
3950
|
+
);
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
_otelState = to;
|
|
3954
|
+
}
|
|
3955
|
+
function getCoreState() {
|
|
3956
|
+
return _coreState;
|
|
3957
|
+
}
|
|
3958
|
+
function getSdkState() {
|
|
3959
|
+
return {
|
|
3960
|
+
core: _coreState,
|
|
3961
|
+
auth: _authState,
|
|
3962
|
+
otel: _otelState
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
function onLifecycleEvent(event, listener) {
|
|
3966
|
+
_emitter.on(event, listener);
|
|
3967
|
+
}
|
|
3968
|
+
function emitLifecycleEvent(event, payload) {
|
|
3969
|
+
emitSafe(event, payload);
|
|
3970
|
+
}
|
|
3971
|
+
function offLifecycleEvent(event, listener) {
|
|
3972
|
+
_emitter.off(event, listener);
|
|
3973
|
+
}
|
|
3974
|
+
function emitSafe(event, payload) {
|
|
3975
|
+
const listeners = _emitter.listeners(event);
|
|
3976
|
+
for (const listener of listeners) {
|
|
3977
|
+
try {
|
|
3978
|
+
const result = listener(payload);
|
|
3979
|
+
if (result && typeof result.catch === "function") {
|
|
3980
|
+
result.catch((err) => {
|
|
3981
|
+
_logger?.(
|
|
3982
|
+
"error",
|
|
3983
|
+
`[glasstrace] Async error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
|
|
3984
|
+
);
|
|
3985
|
+
});
|
|
3986
|
+
}
|
|
3987
|
+
} catch (err) {
|
|
3988
|
+
_logger?.(
|
|
3989
|
+
"error",
|
|
3990
|
+
`[glasstrace] Error in lifecycle event listener for "${event}": ${err instanceof Error ? err.message : String(err)}`
|
|
3991
|
+
);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
function isReady() {
|
|
3996
|
+
return _coreState === CoreState.ACTIVE || _coreState === CoreState.ACTIVE_DEGRADED;
|
|
3997
|
+
}
|
|
3998
|
+
function waitForReady(timeoutMs = 3e4) {
|
|
3999
|
+
if (isReady()) {
|
|
4000
|
+
return Promise.resolve();
|
|
4001
|
+
}
|
|
4002
|
+
if (_coreState === CoreState.PRODUCTION_DISABLED || _coreState === CoreState.REGISTRATION_FAILED || _coreState === CoreState.SHUTTING_DOWN || _coreState === CoreState.SHUTDOWN) {
|
|
4003
|
+
return Promise.reject(new Error(`SDK is in terminal state: ${_coreState}`));
|
|
4004
|
+
}
|
|
4005
|
+
return new Promise((resolve2, reject) => {
|
|
4006
|
+
let settled = false;
|
|
4007
|
+
const listener = ({ to }) => {
|
|
4008
|
+
if (settled) return;
|
|
4009
|
+
if (to === CoreState.ACTIVE || to === CoreState.ACTIVE_DEGRADED) {
|
|
4010
|
+
settled = true;
|
|
4011
|
+
offLifecycleEvent("core:state_changed", listener);
|
|
4012
|
+
resolve2();
|
|
4013
|
+
} else if (to === CoreState.PRODUCTION_DISABLED || to === CoreState.REGISTRATION_FAILED || to === CoreState.SHUTTING_DOWN || to === CoreState.SHUTDOWN) {
|
|
4014
|
+
settled = true;
|
|
4015
|
+
offLifecycleEvent("core:state_changed", listener);
|
|
4016
|
+
reject(new Error(`SDK reached terminal state: ${to}`));
|
|
4017
|
+
}
|
|
4018
|
+
};
|
|
4019
|
+
onLifecycleEvent("core:state_changed", listener);
|
|
4020
|
+
if (timeoutMs > 0) {
|
|
4021
|
+
const timer = setTimeout(() => {
|
|
4022
|
+
if (settled) return;
|
|
4023
|
+
settled = true;
|
|
4024
|
+
offLifecycleEvent("core:state_changed", listener);
|
|
4025
|
+
reject(new Error(`waitForReady timed out after ${timeoutMs}ms (state: ${_coreState})`));
|
|
4026
|
+
}, timeoutMs);
|
|
4027
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
4028
|
+
timer.unref();
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
});
|
|
4032
|
+
}
|
|
4033
|
+
function getStatus() {
|
|
4034
|
+
let mode;
|
|
4035
|
+
if (_coreState === CoreState.PRODUCTION_DISABLED) {
|
|
4036
|
+
mode = "disabled";
|
|
4037
|
+
} else if (_authState === AuthState.CLAIMING || _authState === AuthState.CLAIMED) {
|
|
4038
|
+
mode = "claiming";
|
|
4039
|
+
} else if (_authState === AuthState.AUTHENTICATED) {
|
|
4040
|
+
mode = "authenticated";
|
|
4041
|
+
} else {
|
|
4042
|
+
mode = "anonymous";
|
|
4043
|
+
}
|
|
4044
|
+
let tracing;
|
|
4045
|
+
if (_otelState === OtelState.COEXISTENCE_FAILED || _otelState === OtelState.UNCONFIGURED || _otelState === OtelState.CONFIGURING) {
|
|
4046
|
+
tracing = "not-configured";
|
|
4047
|
+
} else if (_coreState === CoreState.ACTIVE_DEGRADED) {
|
|
4048
|
+
tracing = "degraded";
|
|
4049
|
+
} else if (_otelState === OtelState.AUTO_ATTACHED || _otelState === OtelState.PROCESSOR_PRESENT) {
|
|
4050
|
+
tracing = "coexistence";
|
|
4051
|
+
} else {
|
|
4052
|
+
tracing = "active";
|
|
4053
|
+
}
|
|
4054
|
+
return {
|
|
4055
|
+
ready: isReady(),
|
|
4056
|
+
mode,
|
|
4057
|
+
tracing
|
|
4058
|
+
};
|
|
4059
|
+
}
|
|
4060
|
+
var _shutdownHooks = [];
|
|
4061
|
+
var _signalHandlersRegistered = false;
|
|
4062
|
+
var _signalHandler = null;
|
|
4063
|
+
var _beforeExitRegistered = false;
|
|
4064
|
+
var _beforeExitHandler = null;
|
|
4065
|
+
var _shutdownExecuted = false;
|
|
4066
|
+
function registerShutdownHook(hook) {
|
|
4067
|
+
_shutdownHooks.push(hook);
|
|
4068
|
+
_shutdownHooks.sort((a, b) => a.priority - b.priority);
|
|
4069
|
+
}
|
|
4070
|
+
async function executeShutdown(timeoutMs = 5e3) {
|
|
4071
|
+
if (_shutdownExecuted) return;
|
|
4072
|
+
_shutdownExecuted = true;
|
|
4073
|
+
setCoreState(CoreState.SHUTTING_DOWN);
|
|
4074
|
+
for (const hook of _shutdownHooks) {
|
|
4075
|
+
try {
|
|
4076
|
+
const hookPromise = hook.fn();
|
|
4077
|
+
hookPromise.catch(() => {
|
|
4078
|
+
});
|
|
4079
|
+
await Promise.race([
|
|
4080
|
+
hookPromise,
|
|
4081
|
+
new Promise((_, reject) => {
|
|
4082
|
+
const timer = setTimeout(() => reject(new Error(`Shutdown hook "${hook.name}" timed out`)), timeoutMs);
|
|
4083
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
4084
|
+
timer.unref();
|
|
4085
|
+
}
|
|
4086
|
+
})
|
|
4087
|
+
]);
|
|
4088
|
+
} catch (err) {
|
|
4089
|
+
_logger?.(
|
|
4090
|
+
"warn",
|
|
4091
|
+
`[glasstrace] Shutdown hook "${hook.name}" failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4092
|
+
);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
setCoreState(CoreState.SHUTDOWN);
|
|
4096
|
+
}
|
|
4097
|
+
function registerSignalHandlers() {
|
|
4098
|
+
if (_signalHandlersRegistered) return;
|
|
4099
|
+
if (typeof process === "undefined" || typeof process.once !== "function") return;
|
|
4100
|
+
_signalHandlersRegistered = true;
|
|
4101
|
+
const handler = (signal) => {
|
|
4102
|
+
void executeShutdown().finally(() => {
|
|
4103
|
+
if (_signalHandler) {
|
|
4104
|
+
process.removeListener("SIGTERM", _signalHandler);
|
|
4105
|
+
process.removeListener("SIGINT", _signalHandler);
|
|
4106
|
+
}
|
|
4107
|
+
process.kill(process.pid, signal);
|
|
4108
|
+
});
|
|
4109
|
+
};
|
|
4110
|
+
_signalHandler = handler;
|
|
4111
|
+
process.once("SIGTERM", handler);
|
|
4112
|
+
process.once("SIGINT", handler);
|
|
4113
|
+
}
|
|
4114
|
+
function registerBeforeExitTrigger() {
|
|
4115
|
+
if (_beforeExitRegistered) return;
|
|
4116
|
+
if (typeof process === "undefined" || typeof process.once !== "function") return;
|
|
4117
|
+
_beforeExitRegistered = true;
|
|
4118
|
+
const handler = () => {
|
|
4119
|
+
void executeShutdown();
|
|
4120
|
+
};
|
|
4121
|
+
_beforeExitHandler = handler;
|
|
4122
|
+
process.once("beforeExit", handler);
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
// src/coexistence.ts
|
|
4126
|
+
init_esm_shims();
|
|
4127
|
+
function createGlasstraceSpanProcessor(options) {
|
|
4128
|
+
const config = resolveConfig(options);
|
|
4129
|
+
const exporterUrl = `${config.endpoint}/v1/traces`;
|
|
4130
|
+
const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
|
|
4131
|
+
const exporter = new GlasstraceExporter({
|
|
4132
|
+
getApiKey: getResolvedApiKey,
|
|
4133
|
+
sessionManager: getSessionManager(),
|
|
4134
|
+
getConfig: () => getActiveConfig(),
|
|
4135
|
+
environment: config.environment,
|
|
4136
|
+
endpointUrl: exporterUrl,
|
|
4137
|
+
createDelegate: createOtlpExporter
|
|
4138
|
+
});
|
|
4139
|
+
registerExporterForKeyNotification(exporter);
|
|
4140
|
+
return new BatchSpanProcessor(exporter, {
|
|
4141
|
+
scheduledDelayMillis: 1e3
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
function emitNudgeMessage() {
|
|
4145
|
+
const isSentry = detectSentry();
|
|
4146
|
+
if (isSentry) {
|
|
4147
|
+
sdkLog(
|
|
4148
|
+
"info",
|
|
4149
|
+
`[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
|
|
4150
|
+
For a cleaner setup, add Glasstrace to your Sentry config:
|
|
4151
|
+
|
|
4152
|
+
import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
|
|
4153
|
+
|
|
4154
|
+
Sentry.init({
|
|
4155
|
+
dsn: '...',
|
|
4156
|
+
openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
|
|
4157
|
+
});
|
|
4158
|
+
|
|
4159
|
+
This message will not appear once Glasstrace is added to your provider config.`
|
|
4160
|
+
);
|
|
4161
|
+
} else {
|
|
4162
|
+
sdkLog(
|
|
4163
|
+
"info",
|
|
4164
|
+
`[glasstrace] Detected existing OTel provider \u2014 auto-attached Glasstrace span processor.
|
|
4165
|
+
For a cleaner setup, add Glasstrace to your provider config:
|
|
4166
|
+
|
|
4167
|
+
import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
|
|
4168
|
+
|
|
4169
|
+
const provider = new BasicTracerProvider({
|
|
4170
|
+
spanProcessors: [
|
|
4171
|
+
// ... your existing processors,
|
|
4172
|
+
createGlasstraceSpanProcessor(),
|
|
4173
|
+
],
|
|
4174
|
+
});
|
|
4175
|
+
|
|
4176
|
+
This message will not appear once Glasstrace is added to your provider config.`
|
|
4177
|
+
);
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
function emitGuidanceMessage() {
|
|
4181
|
+
const isSentry = detectSentry();
|
|
4182
|
+
if (isSentry) {
|
|
4183
|
+
sdkLog(
|
|
4184
|
+
"warn",
|
|
4185
|
+
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4186
|
+
Add Glasstrace to your Sentry config:
|
|
4187
|
+
|
|
4188
|
+
import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
|
|
4189
|
+
|
|
4190
|
+
Sentry.init({
|
|
4191
|
+
dsn: '...',
|
|
4192
|
+
openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
|
|
4193
|
+
});`
|
|
4194
|
+
);
|
|
4195
|
+
} else {
|
|
4196
|
+
sdkLog(
|
|
4197
|
+
"warn",
|
|
4198
|
+
`[glasstrace] An existing OTel TracerProvider is registered but Glasstrace could not auto-attach its span processor.
|
|
4199
|
+
Add Glasstrace to your provider configuration:
|
|
4200
|
+
|
|
4201
|
+
import { createGlasstraceSpanProcessor } from '@glasstrace/sdk';
|
|
4202
|
+
|
|
4203
|
+
const provider = new BasicTracerProvider({
|
|
4204
|
+
spanProcessors: [
|
|
4205
|
+
// ... your existing processors,
|
|
4206
|
+
createGlasstraceSpanProcessor(),
|
|
4207
|
+
],
|
|
4208
|
+
});`
|
|
4209
|
+
);
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
function detectSentry() {
|
|
4213
|
+
try {
|
|
4214
|
+
__require.resolve("@sentry/node");
|
|
4215
|
+
return true;
|
|
4216
|
+
} catch {
|
|
4217
|
+
try {
|
|
4218
|
+
__require.resolve("@sentry/nextjs");
|
|
4219
|
+
return true;
|
|
4220
|
+
} catch {
|
|
4221
|
+
return false;
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
|
|
3710
4226
|
// src/otel-config.ts
|
|
3711
4227
|
var _resolvedApiKey = API_KEY_PENDING;
|
|
3712
4228
|
var _activeExporter = null;
|
|
3713
|
-
var
|
|
4229
|
+
var _additionalExporters = [];
|
|
4230
|
+
var _injectedProcessor = null;
|
|
3714
4231
|
function setResolvedApiKey(key) {
|
|
3715
4232
|
_resolvedApiKey = key;
|
|
3716
4233
|
}
|
|
@@ -3719,6 +4236,12 @@ function getResolvedApiKey() {
|
|
|
3719
4236
|
}
|
|
3720
4237
|
function notifyApiKeyResolved() {
|
|
3721
4238
|
_activeExporter?.notifyKeyResolved();
|
|
4239
|
+
for (const exporter of _additionalExporters) {
|
|
4240
|
+
exporter.notifyKeyResolved();
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
function registerExporterForKeyNotification(exporter) {
|
|
4244
|
+
_additionalExporters.push(exporter);
|
|
3722
4245
|
}
|
|
3723
4246
|
async function tryImport(moduleId) {
|
|
3724
4247
|
try {
|
|
@@ -3727,34 +4250,65 @@ async function tryImport(moduleId) {
|
|
|
3727
4250
|
return null;
|
|
3728
4251
|
}
|
|
3729
4252
|
}
|
|
3730
|
-
function
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
4253
|
+
function tryInjectProcessor(tracerProvider, glasstraceExporter) {
|
|
4254
|
+
try {
|
|
4255
|
+
const proxy = tracerProvider;
|
|
4256
|
+
const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
|
|
4257
|
+
const withAdd = delegate;
|
|
4258
|
+
if (typeof withAdd.addSpanProcessor === "function") {
|
|
4259
|
+
if (typeof withAdd.getActiveSpanProcessor === "function") {
|
|
4260
|
+
const active = withAdd.getActiveSpanProcessor();
|
|
4261
|
+
const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
|
|
4262
|
+
const processors = active?._spanProcessors;
|
|
4263
|
+
if (Array.isArray(processors) && processors.some((p) => {
|
|
4264
|
+
const exp = p._exporter;
|
|
4265
|
+
return exp?.[brand] === true;
|
|
4266
|
+
})) {
|
|
4267
|
+
return "already_present";
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
const processor2 = new BatchSpanProcessor(glasstraceExporter, {
|
|
4271
|
+
scheduledDelayMillis: 1e3
|
|
4272
|
+
});
|
|
4273
|
+
withAdd.addSpanProcessor(processor2);
|
|
4274
|
+
_injectedProcessor = processor2;
|
|
4275
|
+
return "v1_public";
|
|
4276
|
+
}
|
|
4277
|
+
const provider = delegate;
|
|
4278
|
+
const multiProcessor = provider._activeSpanProcessor;
|
|
4279
|
+
if (!multiProcessor || !Array.isArray(multiProcessor._spanProcessors)) {
|
|
4280
|
+
return null;
|
|
4281
|
+
}
|
|
4282
|
+
const processor = new BatchSpanProcessor(glasstraceExporter, {
|
|
4283
|
+
scheduledDelayMillis: 1e3
|
|
4284
|
+
});
|
|
4285
|
+
multiProcessor._spanProcessors.push(processor);
|
|
4286
|
+
_injectedProcessor = processor;
|
|
4287
|
+
return "v2_private";
|
|
4288
|
+
} catch {
|
|
4289
|
+
return null;
|
|
3737
4290
|
}
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
4291
|
+
}
|
|
4292
|
+
function isGlasstraceProcessorPresent(tracerProvider) {
|
|
4293
|
+
try {
|
|
4294
|
+
const proxy = tracerProvider;
|
|
4295
|
+
const delegate = typeof proxy.getDelegate === "function" ? proxy.getDelegate() : tracerProvider;
|
|
4296
|
+
const provider = delegate;
|
|
4297
|
+
const processors = provider._activeSpanProcessor?._spanProcessors;
|
|
4298
|
+
if (!Array.isArray(processors)) {
|
|
4299
|
+
return false;
|
|
4300
|
+
}
|
|
4301
|
+
const brand = /* @__PURE__ */ Symbol.for("glasstrace.exporter");
|
|
4302
|
+
return processors.some((p) => {
|
|
4303
|
+
const exporter = p._exporter;
|
|
4304
|
+
return exporter?.[brand] === true;
|
|
3750
4305
|
});
|
|
3751
|
-
}
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
process.once("SIGTERM", handler);
|
|
3755
|
-
process.once("SIGINT", handler);
|
|
4306
|
+
} catch {
|
|
4307
|
+
return false;
|
|
4308
|
+
}
|
|
3756
4309
|
}
|
|
3757
4310
|
async function configureOtel(config, sessionManager) {
|
|
4311
|
+
setOtelState(OtelState.CONFIGURING);
|
|
3758
4312
|
const exporterUrl = `${config.endpoint}/v1/traces`;
|
|
3759
4313
|
const createOtlpExporter = (url, headers) => new OTLPTraceExporter({ url, headers });
|
|
3760
4314
|
const glasstraceExporter = new GlasstraceExporter({
|
|
@@ -3763,32 +4317,91 @@ async function configureOtel(config, sessionManager) {
|
|
|
3763
4317
|
getConfig: () => getActiveConfig(),
|
|
3764
4318
|
environment: config.environment,
|
|
3765
4319
|
endpointUrl: exporterUrl,
|
|
3766
|
-
createDelegate: createOtlpExporter
|
|
4320
|
+
createDelegate: createOtlpExporter,
|
|
4321
|
+
verbose: config.verbose
|
|
3767
4322
|
});
|
|
3768
4323
|
_activeExporter = glasstraceExporter;
|
|
4324
|
+
await new Promise((resolve2) => {
|
|
4325
|
+
if (typeof setImmediate === "function") {
|
|
4326
|
+
setImmediate(resolve2);
|
|
4327
|
+
} else {
|
|
4328
|
+
setTimeout(resolve2, 0);
|
|
4329
|
+
}
|
|
4330
|
+
});
|
|
4331
|
+
const existingProvider = trace.getTracerProvider();
|
|
4332
|
+
const probeTracer = existingProvider.getTracer("glasstrace-probe");
|
|
4333
|
+
const anotherProviderRegistered = probeTracer.constructor.name !== "ProxyTracer";
|
|
4334
|
+
if (anotherProviderRegistered) {
|
|
4335
|
+
if (isGlasstraceProcessorPresent(existingProvider)) {
|
|
4336
|
+
if (config.verbose) {
|
|
4337
|
+
sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present.");
|
|
4338
|
+
}
|
|
4339
|
+
_activeExporter = null;
|
|
4340
|
+
setOtelState(OtelState.PROCESSOR_PRESENT);
|
|
4341
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
const injectionMethod = tryInjectProcessor(existingProvider, glasstraceExporter);
|
|
4345
|
+
if (injectionMethod === "already_present") {
|
|
4346
|
+
if (config.verbose) {
|
|
4347
|
+
sdkLog("info", "[glasstrace] Existing provider detected \u2014 Glasstrace processor already present (v1 check).");
|
|
4348
|
+
}
|
|
4349
|
+
_activeExporter = null;
|
|
4350
|
+
setOtelState(OtelState.PROCESSOR_PRESENT);
|
|
4351
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.PROCESSOR_PRESENT, scenario: "B-clean" });
|
|
4352
|
+
return;
|
|
4353
|
+
}
|
|
4354
|
+
if (injectionMethod) {
|
|
4355
|
+
if (config.verbose) {
|
|
4356
|
+
sdkLog("info", "[glasstrace] Existing provider detected \u2014 auto-attaching Glasstrace processor.");
|
|
4357
|
+
}
|
|
4358
|
+
registerShutdownHook({
|
|
4359
|
+
name: "coexistence-flush",
|
|
4360
|
+
priority: 5,
|
|
4361
|
+
fn: async () => {
|
|
4362
|
+
if (_injectedProcessor) {
|
|
4363
|
+
await _injectedProcessor.forceFlush();
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
});
|
|
4367
|
+
registerBeforeExitTrigger();
|
|
4368
|
+
const scenario = injectionMethod === "v1_public" ? "D1" : "B-auto";
|
|
4369
|
+
setOtelState(OtelState.AUTO_ATTACHED);
|
|
4370
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.AUTO_ATTACHED, scenario });
|
|
4371
|
+
emitLifecycleEvent("otel:injection_succeeded", { method: injectionMethod });
|
|
4372
|
+
emitNudgeMessage();
|
|
4373
|
+
return;
|
|
4374
|
+
}
|
|
4375
|
+
if (config.verbose) {
|
|
4376
|
+
sdkLog("info", "[glasstrace] Existing provider detected \u2014 could not auto-attach.");
|
|
4377
|
+
}
|
|
4378
|
+
emitGuidanceMessage();
|
|
4379
|
+
_activeExporter = null;
|
|
4380
|
+
setOtelState(OtelState.COEXISTENCE_FAILED);
|
|
4381
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.COEXISTENCE_FAILED, scenario: "C/F" });
|
|
4382
|
+
emitLifecycleEvent("otel:injection_failed", { reason: "provider internals inaccessible" });
|
|
4383
|
+
const coreState = getCoreState();
|
|
4384
|
+
if (coreState === CoreState.ACTIVE || coreState === CoreState.KEY_RESOLVED) {
|
|
4385
|
+
setCoreState(CoreState.ACTIVE_DEGRADED);
|
|
4386
|
+
}
|
|
4387
|
+
return;
|
|
4388
|
+
}
|
|
3769
4389
|
const vercelOtel = await tryImport("@vercel/otel");
|
|
3770
4390
|
if (vercelOtel && typeof vercelOtel.registerOTel === "function") {
|
|
3771
4391
|
const otelConfig = {
|
|
3772
4392
|
serviceName: "glasstrace-sdk",
|
|
3773
4393
|
traceExporter: glasstraceExporter
|
|
3774
4394
|
};
|
|
3775
|
-
const
|
|
3776
|
-
if (
|
|
3777
|
-
const PrismaInstrumentation =
|
|
4395
|
+
const prismaModule2 = await tryImport("@prisma/instrumentation");
|
|
4396
|
+
if (prismaModule2) {
|
|
4397
|
+
const PrismaInstrumentation = prismaModule2.PrismaInstrumentation;
|
|
3778
4398
|
if (PrismaInstrumentation) {
|
|
3779
4399
|
otelConfig.instrumentations = [new PrismaInstrumentation()];
|
|
3780
4400
|
}
|
|
3781
4401
|
}
|
|
3782
4402
|
vercelOtel.registerOTel(otelConfig);
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
const existingProvider = trace.getTracerProvider();
|
|
3786
|
-
const probeTracer = existingProvider.getTracer("glasstrace-probe");
|
|
3787
|
-
if (probeTracer.constructor.name !== "ProxyTracer") {
|
|
3788
|
-
console.warn(
|
|
3789
|
-
"[glasstrace] An existing OpenTelemetry TracerProvider is already registered. Glasstrace will not overwrite it. To use Glasstrace alongside another tracing tool, add GlasstraceExporter as an additional span processor on your existing provider."
|
|
3790
|
-
);
|
|
3791
|
-
_activeExporter = null;
|
|
4403
|
+
setOtelState(OtelState.OWNS_PROVIDER);
|
|
4404
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "E" });
|
|
3792
4405
|
return;
|
|
3793
4406
|
}
|
|
3794
4407
|
if (config.verbose) {
|
|
@@ -3810,7 +4423,29 @@ async function configureOtel(config, sessionManager) {
|
|
|
3810
4423
|
spanProcessors: [processor]
|
|
3811
4424
|
});
|
|
3812
4425
|
trace.setGlobalTracerProvider(provider);
|
|
3813
|
-
|
|
4426
|
+
registerShutdownHook({
|
|
4427
|
+
name: "otel-provider-shutdown",
|
|
4428
|
+
priority: 0,
|
|
4429
|
+
fn: async () => {
|
|
4430
|
+
await provider.shutdown();
|
|
4431
|
+
}
|
|
4432
|
+
});
|
|
4433
|
+
registerSignalHandlers();
|
|
4434
|
+
registerBeforeExitTrigger();
|
|
4435
|
+
const prismaModule = await tryImport("@prisma/instrumentation");
|
|
4436
|
+
if (prismaModule) {
|
|
4437
|
+
const PrismaInstrumentation = prismaModule.PrismaInstrumentation;
|
|
4438
|
+
if (PrismaInstrumentation) {
|
|
4439
|
+
try {
|
|
4440
|
+
const inst = new PrismaInstrumentation();
|
|
4441
|
+
inst.setTracerProvider(provider);
|
|
4442
|
+
inst.enable();
|
|
4443
|
+
} catch {
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
setOtelState(OtelState.OWNS_PROVIDER);
|
|
4448
|
+
emitLifecycleEvent("otel:configured", { state: OtelState.OWNS_PROVIDER, scenario: "A" });
|
|
3814
4449
|
}
|
|
3815
4450
|
|
|
3816
4451
|
// src/context-manager.ts
|
|
@@ -3855,7 +4490,7 @@ var heartbeatGeneration = 0;
|
|
|
3855
4490
|
var backoffAttempts = 0;
|
|
3856
4491
|
var backoffUntil = 0;
|
|
3857
4492
|
var tickInProgress = false;
|
|
3858
|
-
var
|
|
4493
|
+
var _shutdownHandler = null;
|
|
3859
4494
|
function startHeartbeat(config, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
3860
4495
|
if (heartbeatTimer !== null) return;
|
|
3861
4496
|
heartbeatGeneration = generation;
|
|
@@ -3908,7 +4543,7 @@ async function heartbeatTick(config, anonKey, sdkVersion, generation, onClaimTra
|
|
|
3908
4543
|
backoffUntil = 0;
|
|
3909
4544
|
}
|
|
3910
4545
|
if (initResult?.claimResult) {
|
|
3911
|
-
onClaimTransition(initResult.claimResult.newApiKey);
|
|
4546
|
+
onClaimTransition(initResult.claimResult.newApiKey, initResult.claimResult.accountId);
|
|
3912
4547
|
}
|
|
3913
4548
|
if (config.verbose) {
|
|
3914
4549
|
sdkLog("info", "[glasstrace] Heartbeat completed.");
|
|
@@ -3936,39 +4571,124 @@ function registerShutdownHandlers(config, anonKey, sdkVersion) {
|
|
|
3936
4571
|
process.kill(process.pid, signal);
|
|
3937
4572
|
});
|
|
3938
4573
|
};
|
|
3939
|
-
|
|
3940
|
-
process.once("SIGTERM",
|
|
3941
|
-
process.once("SIGINT",
|
|
4574
|
+
_shutdownHandler = handler;
|
|
4575
|
+
process.once("SIGTERM", _shutdownHandler);
|
|
4576
|
+
process.once("SIGINT", _shutdownHandler);
|
|
3942
4577
|
}
|
|
3943
4578
|
function removeShutdownHandlers() {
|
|
3944
|
-
if (
|
|
3945
|
-
process.removeListener("SIGTERM",
|
|
3946
|
-
process.removeListener("SIGINT",
|
|
3947
|
-
|
|
4579
|
+
if (_shutdownHandler && typeof process !== "undefined") {
|
|
4580
|
+
process.removeListener("SIGTERM", _shutdownHandler);
|
|
4581
|
+
process.removeListener("SIGINT", _shutdownHandler);
|
|
4582
|
+
_shutdownHandler = null;
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
// src/runtime-state.ts
|
|
4587
|
+
init_esm_shims();
|
|
4588
|
+
import { writeFileSync, renameSync, mkdirSync } from "fs";
|
|
4589
|
+
import { join } from "path";
|
|
4590
|
+
var _projectRoot = null;
|
|
4591
|
+
var _sdkVersion = "unknown";
|
|
4592
|
+
var _lastScenario;
|
|
4593
|
+
var _debounceTimer = null;
|
|
4594
|
+
var _started = false;
|
|
4595
|
+
function startRuntimeStateWriter(options) {
|
|
4596
|
+
if (_started) return;
|
|
4597
|
+
_started = true;
|
|
4598
|
+
_projectRoot = options.projectRoot;
|
|
4599
|
+
_sdkVersion = options.sdkVersion;
|
|
4600
|
+
onLifecycleEvent("core:state_changed", ({ to }) => {
|
|
4601
|
+
if (to === CoreState.SHUTDOWN) {
|
|
4602
|
+
writeStateNow();
|
|
4603
|
+
} else {
|
|
4604
|
+
debouncedWrite();
|
|
4605
|
+
}
|
|
4606
|
+
});
|
|
4607
|
+
onLifecycleEvent("otel:configured", ({ scenario }) => {
|
|
4608
|
+
_lastScenario = scenario;
|
|
4609
|
+
debouncedWrite();
|
|
4610
|
+
});
|
|
4611
|
+
onLifecycleEvent("auth:key_resolved", () => debouncedWrite());
|
|
4612
|
+
onLifecycleEvent("auth:claim_started", () => debouncedWrite());
|
|
4613
|
+
onLifecycleEvent("auth:claim_completed", () => debouncedWrite());
|
|
4614
|
+
writeStateNow();
|
|
4615
|
+
}
|
|
4616
|
+
function debouncedWrite() {
|
|
4617
|
+
if (_debounceTimer) return;
|
|
4618
|
+
_debounceTimer = setTimeout(() => {
|
|
4619
|
+
_debounceTimer = null;
|
|
4620
|
+
writeStateNow();
|
|
4621
|
+
}, 1e3);
|
|
4622
|
+
if (typeof _debounceTimer === "object" && "unref" in _debounceTimer) {
|
|
4623
|
+
_debounceTimer.unref();
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
function writeStateNow() {
|
|
4627
|
+
if (!_projectRoot) return;
|
|
4628
|
+
try {
|
|
4629
|
+
const state = getSdkState();
|
|
4630
|
+
const runtimeState = {
|
|
4631
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4632
|
+
pid: process.pid,
|
|
4633
|
+
sdkVersion: _sdkVersion,
|
|
4634
|
+
core: { state: state.core },
|
|
4635
|
+
auth: { state: state.auth },
|
|
4636
|
+
otel: { state: state.otel, scenario: _lastScenario }
|
|
4637
|
+
};
|
|
4638
|
+
const dir = join(_projectRoot, ".glasstrace");
|
|
4639
|
+
const filePath = join(dir, "runtime-state.json");
|
|
4640
|
+
const tmpPath = join(dir, "runtime-state.json.tmp");
|
|
4641
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
4642
|
+
writeFileSync(tmpPath, JSON.stringify(runtimeState, null, 2) + "\n", {
|
|
4643
|
+
mode: 384
|
|
4644
|
+
});
|
|
4645
|
+
renameSync(tmpPath, filePath);
|
|
4646
|
+
} catch (err) {
|
|
4647
|
+
sdkLog(
|
|
4648
|
+
"warn",
|
|
4649
|
+
`[glasstrace] Failed to write runtime state: ${err instanceof Error ? err.message : String(err)}`
|
|
4650
|
+
);
|
|
3948
4651
|
}
|
|
3949
4652
|
}
|
|
3950
4653
|
|
|
3951
4654
|
// src/register.ts
|
|
4655
|
+
function maskKey(key) {
|
|
4656
|
+
if (key.length <= 12) return key.slice(0, 4) + "...";
|
|
4657
|
+
return key.slice(0, 8) + "..." + key.slice(-4);
|
|
4658
|
+
}
|
|
3952
4659
|
var consoleCaptureInstalled = false;
|
|
3953
4660
|
var discoveryHandler = null;
|
|
3954
|
-
var isRegistered = false;
|
|
3955
4661
|
var registrationGeneration = 0;
|
|
4662
|
+
var _sessionManager = null;
|
|
4663
|
+
function getSessionManager() {
|
|
4664
|
+
if (!_sessionManager) {
|
|
4665
|
+
_sessionManager = new SessionManager();
|
|
4666
|
+
}
|
|
4667
|
+
return _sessionManager;
|
|
4668
|
+
}
|
|
3956
4669
|
function registerGlasstrace(options) {
|
|
3957
4670
|
try {
|
|
3958
|
-
if (
|
|
4671
|
+
if (getCoreState() !== CoreState.IDLE) {
|
|
3959
4672
|
return;
|
|
3960
4673
|
}
|
|
4674
|
+
initLifecycle({ logger: sdkLog });
|
|
3961
4675
|
if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
|
|
3962
4676
|
console.warn(
|
|
3963
4677
|
"[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
|
|
3964
4678
|
);
|
|
3965
4679
|
return;
|
|
3966
4680
|
}
|
|
4681
|
+
setCoreState(CoreState.REGISTERING);
|
|
4682
|
+
startRuntimeStateWriter({
|
|
4683
|
+
projectRoot: process.cwd(),
|
|
4684
|
+
sdkVersion: "0.14.0"
|
|
4685
|
+
});
|
|
3967
4686
|
const config = resolveConfig(options);
|
|
3968
4687
|
if (config.verbose) {
|
|
3969
4688
|
console.info("[glasstrace] Config resolved.");
|
|
3970
4689
|
}
|
|
3971
4690
|
if (isProductionDisabled(config)) {
|
|
4691
|
+
setCoreState(CoreState.PRODUCTION_DISABLED);
|
|
3972
4692
|
console.warn(
|
|
3973
4693
|
"[glasstrace] Disabled in production. Set GLASSTRACE_FORCE_ENABLE=true to override."
|
|
3974
4694
|
);
|
|
@@ -3979,8 +4699,13 @@ function registerGlasstrace(options) {
|
|
|
3979
4699
|
}
|
|
3980
4700
|
const anonymous = isAnonymousMode(config);
|
|
3981
4701
|
let effectiveKey = config.apiKey;
|
|
4702
|
+
initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
|
|
3982
4703
|
if (effectiveKey) {
|
|
3983
4704
|
setResolvedApiKey(effectiveKey);
|
|
4705
|
+
emitLifecycleEvent("auth:key_resolved", {
|
|
4706
|
+
key: maskKey(effectiveKey),
|
|
4707
|
+
mode: anonymous ? "anonymous" : "dev"
|
|
4708
|
+
});
|
|
3984
4709
|
}
|
|
3985
4710
|
if (config.verbose) {
|
|
3986
4711
|
console.info(
|
|
@@ -3996,11 +4721,11 @@ function registerGlasstrace(options) {
|
|
|
3996
4721
|
`[glasstrace] Cached config ${cachedInitResponse ? "loaded and applied" : "not found"}.`
|
|
3997
4722
|
);
|
|
3998
4723
|
}
|
|
3999
|
-
const sessionManager =
|
|
4724
|
+
const sessionManager = getSessionManager();
|
|
4000
4725
|
if (config.verbose) {
|
|
4001
4726
|
console.info("[glasstrace] SessionManager created.");
|
|
4002
4727
|
}
|
|
4003
|
-
|
|
4728
|
+
setCoreState(CoreState.KEY_PENDING);
|
|
4004
4729
|
const currentGeneration = registrationGeneration;
|
|
4005
4730
|
const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
|
|
4006
4731
|
const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
|
|
@@ -4053,6 +4778,7 @@ function registerGlasstrace(options) {
|
|
|
4053
4778
|
resolvedAnonKey = anonKey;
|
|
4054
4779
|
setResolvedApiKey(anonKey);
|
|
4055
4780
|
notifyApiKeyResolved();
|
|
4781
|
+
emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
|
|
4056
4782
|
effectiveKey = anonKey;
|
|
4057
4783
|
if (currentGeneration !== registrationGeneration) return;
|
|
4058
4784
|
discoveryHandler = createDiscoveryHandler(
|
|
@@ -4074,6 +4800,7 @@ function registerGlasstrace(options) {
|
|
|
4074
4800
|
const anonKey = await getOrCreateAnonKey();
|
|
4075
4801
|
setResolvedApiKey(anonKey);
|
|
4076
4802
|
notifyApiKeyResolved();
|
|
4803
|
+
emitLifecycleEvent("auth:key_resolved", { key: maskKey(anonKey), mode: "anonymous" });
|
|
4077
4804
|
effectiveKey = anonKey;
|
|
4078
4805
|
if (currentGeneration !== registrationGeneration) return;
|
|
4079
4806
|
await backgroundInit(config, anonKey, currentGeneration);
|
|
@@ -4106,6 +4833,7 @@ function registerGlasstrace(options) {
|
|
|
4106
4833
|
console.info("[glasstrace] Import graph building skipped.");
|
|
4107
4834
|
}
|
|
4108
4835
|
} catch (err) {
|
|
4836
|
+
setCoreState(CoreState.REGISTRATION_FAILED);
|
|
4109
4837
|
console.warn(
|
|
4110
4838
|
`[glasstrace] Registration failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4111
4839
|
);
|
|
@@ -4115,18 +4843,37 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4115
4843
|
if (config.verbose) {
|
|
4116
4844
|
console.info("[glasstrace] Background init firing.");
|
|
4117
4845
|
}
|
|
4118
|
-
const healthReport = collectHealthReport("0.
|
|
4119
|
-
const initResult = await performInit(config, anonKeyForInit, "0.
|
|
4846
|
+
const healthReport = collectHealthReport("0.14.0");
|
|
4847
|
+
const initResult = await performInit(config, anonKeyForInit, "0.14.0", healthReport);
|
|
4120
4848
|
if (generation !== registrationGeneration) return;
|
|
4849
|
+
const currentState = getCoreState();
|
|
4850
|
+
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
4851
|
+
return;
|
|
4852
|
+
}
|
|
4853
|
+
if (currentState === CoreState.KEY_PENDING) {
|
|
4854
|
+
setCoreState(CoreState.KEY_RESOLVED);
|
|
4855
|
+
}
|
|
4856
|
+
if (getCoreState() === CoreState.KEY_RESOLVED) {
|
|
4857
|
+
setCoreState(didLastInitSucceed() ? CoreState.ACTIVE : CoreState.ACTIVE_DEGRADED);
|
|
4858
|
+
}
|
|
4121
4859
|
if (initResult?.claimResult) {
|
|
4122
|
-
|
|
4860
|
+
const { newApiKey, accountId } = initResult.claimResult;
|
|
4861
|
+
setAuthState(AuthState.CLAIMING);
|
|
4862
|
+
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
4863
|
+
setResolvedApiKey(newApiKey);
|
|
4123
4864
|
notifyApiKeyResolved();
|
|
4865
|
+
setAuthState(AuthState.CLAIMED);
|
|
4866
|
+
emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
|
|
4124
4867
|
}
|
|
4125
4868
|
maybeInstallConsoleCapture();
|
|
4126
4869
|
if (didLastInitSucceed()) {
|
|
4127
|
-
startHeartbeat(config, anonKeyForInit, "0.
|
|
4870
|
+
startHeartbeat(config, anonKeyForInit, "0.14.0", generation, (newApiKey, accountId) => {
|
|
4871
|
+
setAuthState(AuthState.CLAIMING);
|
|
4872
|
+
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
4128
4873
|
setResolvedApiKey(newApiKey);
|
|
4129
4874
|
notifyApiKeyResolved();
|
|
4875
|
+
setAuthState(AuthState.CLAIMED);
|
|
4876
|
+
emitLifecycleEvent("auth:claim_completed", { newKey: maskKey(newApiKey), accountId });
|
|
4130
4877
|
});
|
|
4131
4878
|
}
|
|
4132
4879
|
}
|
|
@@ -4197,7 +4944,7 @@ async function handleSourceMapUpload(distDir) {
|
|
|
4197
4944
|
);
|
|
4198
4945
|
return;
|
|
4199
4946
|
}
|
|
4200
|
-
const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-
|
|
4947
|
+
const { discoverSourceMapFiles: discoverSourceMapFiles2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-W6VPGY26.js");
|
|
4201
4948
|
const files = await discoverSourceMapFiles2(distDir);
|
|
4202
4949
|
if (files.length === 0) {
|
|
4203
4950
|
console.info("[glasstrace] No source map files found. Skipping upload.");
|
|
@@ -4248,6 +4995,7 @@ export {
|
|
|
4248
4995
|
collectSourceMaps,
|
|
4249
4996
|
computeBuildHash,
|
|
4250
4997
|
createDiscoveryHandler,
|
|
4998
|
+
createGlasstraceSpanProcessor,
|
|
4251
4999
|
deriveSessionId,
|
|
4252
5000
|
discoverSourceMapFiles,
|
|
4253
5001
|
discoverTestFiles,
|
|
@@ -4258,8 +5006,10 @@ export {
|
|
|
4258
5006
|
getLinkedAccountId,
|
|
4259
5007
|
getOrCreateAnonKey,
|
|
4260
5008
|
getOrigin,
|
|
5009
|
+
getStatus,
|
|
4261
5010
|
isAnonymousMode,
|
|
4262
5011
|
isProductionDisabled,
|
|
5012
|
+
isReady,
|
|
4263
5013
|
loadCachedConfig,
|
|
4264
5014
|
performInit,
|
|
4265
5015
|
readAnonKey,
|
|
@@ -4271,6 +5021,7 @@ export {
|
|
|
4271
5021
|
uploadSourceMaps,
|
|
4272
5022
|
uploadSourceMapsAuto,
|
|
4273
5023
|
uploadSourceMapsPresigned,
|
|
5024
|
+
waitForReady,
|
|
4274
5025
|
withGlasstraceConfig
|
|
4275
5026
|
};
|
|
4276
5027
|
//# sourceMappingURL=index.js.map
|