raindrop-ai 0.2.1 → 0.2.2-otelv2
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 +34 -0
- package/dist/{chunk-UTCK3OAC.mjs → chunk-2EGS66V2.mjs} +624 -65
- package/dist/index.d.mts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +645 -63
- package/dist/index.mjs +29 -2
- package/dist/tracing/index.d.mts +16 -1
- package/dist/tracing/index.d.ts +16 -1
- package/dist/tracing/index.js +620 -63
- package/dist/tracing/index.mjs +1 -1
- package/package.json +9 -5
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/lib/inject-als.ts
|
|
2
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
3
|
+
if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
|
|
4
|
+
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// ../core/dist/chunk-ITAZONWL.js
|
|
2
8
|
function normalizeFeatureFlags(input) {
|
|
3
9
|
if (Array.isArray(input)) {
|
|
4
10
|
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
@@ -393,10 +399,175 @@ var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
|
393
399
|
"ai.response.providerMetadata"
|
|
394
400
|
];
|
|
395
401
|
var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
|
|
402
|
+
function getAsyncLocalStorageCtor() {
|
|
403
|
+
return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
|
|
404
|
+
}
|
|
405
|
+
function getWeakRefCtor() {
|
|
406
|
+
const ctor = globalThis.WeakRef;
|
|
407
|
+
return typeof ctor === "function" ? ctor : void 0;
|
|
408
|
+
}
|
|
409
|
+
var MAX_BINDING_STACK = 128;
|
|
410
|
+
var EMPTY_STACK = [];
|
|
411
|
+
var RoutingContextStorage = class {
|
|
412
|
+
constructor() {
|
|
413
|
+
this._als = null;
|
|
414
|
+
this._enterWithUsable = false;
|
|
415
|
+
this._syncStack = EMPTY_STACK;
|
|
416
|
+
this._adoptionChecked = false;
|
|
417
|
+
this._warnedNoAmbientBind = false;
|
|
418
|
+
}
|
|
419
|
+
maybeAdoptAsyncLocalStorage() {
|
|
420
|
+
if (this._adoptionChecked) return;
|
|
421
|
+
this._adoptionChecked = true;
|
|
422
|
+
const Ctor = getAsyncLocalStorageCtor();
|
|
423
|
+
if (!Ctor) return;
|
|
424
|
+
const als = new Ctor();
|
|
425
|
+
try {
|
|
426
|
+
als.run(EMPTY_STACK, () => {
|
|
427
|
+
});
|
|
428
|
+
} catch (e) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
this._als = als;
|
|
432
|
+
if (typeof als.enterWith === "function") {
|
|
433
|
+
try {
|
|
434
|
+
als.enterWith(EMPTY_STACK);
|
|
435
|
+
this._enterWithUsable = true;
|
|
436
|
+
} catch (e) {
|
|
437
|
+
this._enterWithUsable = false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
getStack() {
|
|
442
|
+
var _a;
|
|
443
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
444
|
+
if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
|
|
445
|
+
return this._syncStack;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Persist an ambient stack mutation. Returns false when an ALS is adopted but
|
|
449
|
+
* `enterWith` is unusable (workerd): callers must NOT fall back to the
|
|
450
|
+
* process-shared sync stack, since concurrent isolates would cross-stamp.
|
|
451
|
+
*/
|
|
452
|
+
setAmbientStack(stack) {
|
|
453
|
+
if (this._als) {
|
|
454
|
+
if (!this._enterWithUsable) return false;
|
|
455
|
+
this._als.enterWith(stack);
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
this._syncStack = stack;
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
push(binding) {
|
|
462
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
463
|
+
if (this._als && !this._enterWithUsable) {
|
|
464
|
+
this.warnNoAmbientBindOnce();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
let stack = this.getStack();
|
|
468
|
+
if (stack.length >= MAX_BINDING_STACK) {
|
|
469
|
+
stack = stack.filter((b) => b.isLive());
|
|
470
|
+
if (stack.length >= MAX_BINDING_STACK) {
|
|
471
|
+
stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
this.setAmbientStack([...stack, binding]);
|
|
475
|
+
}
|
|
476
|
+
remove(binding) {
|
|
477
|
+
binding.markDead();
|
|
478
|
+
const stack = this.getStack();
|
|
479
|
+
const pruned = stack.filter((b) => b !== binding && b.isLive());
|
|
480
|
+
if (pruned.length !== stack.length) {
|
|
481
|
+
this.setAmbientStack(pruned);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
runWith(binding, callback) {
|
|
485
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
486
|
+
if (this._als) {
|
|
487
|
+
return this._als.run([...this.getStack(), binding], callback);
|
|
488
|
+
}
|
|
489
|
+
const previous = this._syncStack;
|
|
490
|
+
this._syncStack = [...previous, binding];
|
|
491
|
+
try {
|
|
492
|
+
return callback();
|
|
493
|
+
} finally {
|
|
494
|
+
this._syncStack = previous;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
current() {
|
|
498
|
+
const stack = this.getStack();
|
|
499
|
+
if (stack.length === 0) return void 0;
|
|
500
|
+
const top = stack[stack.length - 1];
|
|
501
|
+
if (top.isLive()) return top;
|
|
502
|
+
const pruned = stack.filter((b) => b.isLive());
|
|
503
|
+
this.setAmbientStack(pruned);
|
|
504
|
+
return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
|
|
505
|
+
}
|
|
506
|
+
warnNoAmbientBindOnce() {
|
|
507
|
+
if (this._warnedNoAmbientBind) return;
|
|
508
|
+
this._warnedNoAmbientBind = true;
|
|
509
|
+
console.warn(
|
|
510
|
+
"[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime."
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
|
|
515
|
+
function routingStorage() {
|
|
516
|
+
const holder = globalThis;
|
|
517
|
+
let storage = holder[ROUTING_STORAGE_KEY];
|
|
518
|
+
if (!storage) {
|
|
519
|
+
storage = new RoutingContextStorage();
|
|
520
|
+
holder[ROUTING_STORAGE_KEY] = storage;
|
|
521
|
+
}
|
|
522
|
+
return storage;
|
|
523
|
+
}
|
|
524
|
+
function makeBoundContext(binding, owner) {
|
|
525
|
+
const WeakRefCtor = owner !== void 0 ? getWeakRefCtor() : void 0;
|
|
526
|
+
const ref = WeakRefCtor && owner !== void 0 ? new WeakRefCtor(owner) : void 0;
|
|
527
|
+
let dead = false;
|
|
528
|
+
return {
|
|
529
|
+
projectId: binding.projectId,
|
|
530
|
+
authHint: binding.authHint,
|
|
531
|
+
isLive() {
|
|
532
|
+
if (dead) return false;
|
|
533
|
+
return ref === void 0 || ref.deref() !== void 0;
|
|
534
|
+
},
|
|
535
|
+
markDead() {
|
|
536
|
+
dead = true;
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function bindRoutingContext(binding, owner) {
|
|
541
|
+
const bound = makeBoundContext(binding, owner);
|
|
542
|
+
try {
|
|
543
|
+
routingStorage().push(bound);
|
|
544
|
+
} catch (e) {
|
|
545
|
+
}
|
|
546
|
+
return bound;
|
|
547
|
+
}
|
|
548
|
+
function unbindRoutingContext(bound) {
|
|
549
|
+
if (!bound || !isBoundContext(bound)) return;
|
|
550
|
+
try {
|
|
551
|
+
routingStorage().remove(bound);
|
|
552
|
+
} catch (e) {
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function withRoutingContext(binding, callback) {
|
|
556
|
+
const bound = makeBoundContext(binding);
|
|
557
|
+
return routingStorage().runWith(bound, callback);
|
|
558
|
+
}
|
|
559
|
+
function currentRoutingBinding() {
|
|
560
|
+
const bound = routingStorage().current();
|
|
561
|
+
if (!bound) return void 0;
|
|
562
|
+
return { projectId: bound.projectId, authHint: bound.authHint };
|
|
563
|
+
}
|
|
564
|
+
function isBoundContext(value) {
|
|
565
|
+
return typeof value.isLive === "function";
|
|
566
|
+
}
|
|
396
567
|
|
|
397
568
|
// ../core/dist/index.node.js
|
|
398
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
399
|
-
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE =
|
|
569
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
570
|
+
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage2;
|
|
400
571
|
var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
|
|
401
572
|
"OpenTelemetry SDK Context Key SUPPRESS_TRACING"
|
|
402
573
|
);
|
|
@@ -426,7 +597,7 @@ installTracingSuppressionHook();
|
|
|
426
597
|
// package.json
|
|
427
598
|
var package_default = {
|
|
428
599
|
name: "raindrop-ai",
|
|
429
|
-
version: "0.2.
|
|
600
|
+
version: "0.2.2",
|
|
430
601
|
main: "dist/index.js",
|
|
431
602
|
module: "dist/index.mjs",
|
|
432
603
|
types: "dist/index.d.ts",
|
|
@@ -492,6 +663,7 @@ var package_default = {
|
|
|
492
663
|
dependencies: {
|
|
493
664
|
"@opentelemetry/api": "^1.9.0",
|
|
494
665
|
"@opentelemetry/exporter-trace-otlp-http": "^0.57.2",
|
|
666
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.57.2",
|
|
495
667
|
"@traceloop/node-server-sdk": "0.19.0-otel-v1",
|
|
496
668
|
weakref: "^0.2.1",
|
|
497
669
|
zod: "^3.23.8"
|
|
@@ -523,6 +695,7 @@ var package_default = {
|
|
|
523
695
|
"@traceloop/instrumentation-together",
|
|
524
696
|
"@opentelemetry/instrumentation",
|
|
525
697
|
"@opentelemetry/exporter-trace-otlp-http",
|
|
698
|
+
"@opentelemetry/exporter-trace-otlp-proto",
|
|
526
699
|
"@opentelemetry/sdk-trace-base"
|
|
527
700
|
],
|
|
528
701
|
noExternal: [
|
|
@@ -537,6 +710,190 @@ var package_default = {
|
|
|
537
710
|
}
|
|
538
711
|
};
|
|
539
712
|
|
|
713
|
+
// src/tracing/multi-project.ts
|
|
714
|
+
import { createHash } from "crypto";
|
|
715
|
+
import { OTLPTraceExporter as OTLPProtoTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
|
|
716
|
+
var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
|
|
717
|
+
var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
|
|
718
|
+
var EXPORT_SUCCESS = 0;
|
|
719
|
+
var EXPORT_FAILED = 1;
|
|
720
|
+
function authHintForKey(writeKey) {
|
|
721
|
+
if (!writeKey) return void 0;
|
|
722
|
+
return createHash("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
|
|
723
|
+
}
|
|
724
|
+
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.multiProjectState");
|
|
725
|
+
function getState() {
|
|
726
|
+
const holder = globalThis;
|
|
727
|
+
let state = holder[STATE_KEY];
|
|
728
|
+
if (!state) {
|
|
729
|
+
state = {
|
|
730
|
+
foreignClientSeen: false,
|
|
731
|
+
seenClientHints: /* @__PURE__ */ new Set(),
|
|
732
|
+
ownerAuthHint: void 0,
|
|
733
|
+
ownerProjectId: void 0,
|
|
734
|
+
pipelineClaimed: false,
|
|
735
|
+
traceloopConfiguredWithoutClaim: false,
|
|
736
|
+
multiKeyWarned: false,
|
|
737
|
+
pendingMultiKeyWarning: false
|
|
738
|
+
};
|
|
739
|
+
holder[STATE_KEY] = state;
|
|
740
|
+
}
|
|
741
|
+
return state;
|
|
742
|
+
}
|
|
743
|
+
function emitMultiKeyWarningOnce() {
|
|
744
|
+
const state = getState();
|
|
745
|
+
if (state.multiKeyWarned) return;
|
|
746
|
+
state.multiKeyWarned = true;
|
|
747
|
+
state.pendingMultiKeyWarning = false;
|
|
748
|
+
console.warn(
|
|
749
|
+
"[raindrop] Multiple API keys detected in one process. The OTel export guard now requires positive attribution: spans not bound to any client (no begin()/asCurrent()) are dropped, and spans bound to a non-owner key are dropped. Manual events are unaffected."
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
function registerClientKey(authHint, tracingEnabled = false) {
|
|
753
|
+
if (!authHint) return;
|
|
754
|
+
const state = getState();
|
|
755
|
+
state.seenClientHints.add(authHint);
|
|
756
|
+
if (state.seenClientHints.size > 1) {
|
|
757
|
+
state.foreignClientSeen = true;
|
|
758
|
+
if (tracingEnabled || state.pipelineClaimed) {
|
|
759
|
+
emitMultiKeyWarningOnce();
|
|
760
|
+
} else {
|
|
761
|
+
state.pendingMultiKeyWarning = true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
function markForeignClient() {
|
|
766
|
+
getState().foreignClientSeen = true;
|
|
767
|
+
}
|
|
768
|
+
function foreignClientSeen() {
|
|
769
|
+
return getState().foreignClientSeen;
|
|
770
|
+
}
|
|
771
|
+
function stampSpan(span, projectId, authHint) {
|
|
772
|
+
try {
|
|
773
|
+
if (projectId) {
|
|
774
|
+
span.setAttribute(PROJECT_ID_SPAN_ATTRIBUTE, projectId);
|
|
775
|
+
}
|
|
776
|
+
if (authHint && foreignClientSeen()) {
|
|
777
|
+
span.setAttribute(AUTH_HINT_SPAN_ATTRIBUTE, authHint);
|
|
778
|
+
}
|
|
779
|
+
} catch (e) {
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
var RaindropContextSpanProcessor = class {
|
|
783
|
+
onStart(span) {
|
|
784
|
+
try {
|
|
785
|
+
const bound = currentRoutingBinding();
|
|
786
|
+
if (!bound) return;
|
|
787
|
+
stampSpan(span, bound.projectId, bound.authHint);
|
|
788
|
+
} catch (e) {
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
onEnd() {
|
|
792
|
+
}
|
|
793
|
+
async forceFlush() {
|
|
794
|
+
}
|
|
795
|
+
async shutdown() {
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
var GuardedSpanExporter = class {
|
|
799
|
+
constructor(inner, ownerAuthHint) {
|
|
800
|
+
this.droppedTotal = 0;
|
|
801
|
+
this.inner = inner;
|
|
802
|
+
this.ownerAuthHint = ownerAuthHint;
|
|
803
|
+
}
|
|
804
|
+
partition(spans) {
|
|
805
|
+
var _a;
|
|
806
|
+
const allowed = [];
|
|
807
|
+
let dropped = 0;
|
|
808
|
+
const requirePositive = foreignClientSeen();
|
|
809
|
+
for (const span of spans) {
|
|
810
|
+
const attrs = (_a = span.attributes) != null ? _a : {};
|
|
811
|
+
const hint = attrs[AUTH_HINT_SPAN_ATTRIBUTE];
|
|
812
|
+
const keep = requirePositive ? hint === this.ownerAuthHint : hint === void 0 || hint === this.ownerAuthHint;
|
|
813
|
+
if (keep) {
|
|
814
|
+
allowed.push(span);
|
|
815
|
+
} else {
|
|
816
|
+
dropped += 1;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return { allowed, dropped };
|
|
820
|
+
}
|
|
821
|
+
warnDropped(dropped) {
|
|
822
|
+
this.droppedTotal += dropped;
|
|
823
|
+
const total = this.droppedTotal;
|
|
824
|
+
rateLimitedLog(
|
|
825
|
+
"js-sdk.multi-project.dropped",
|
|
826
|
+
() => console.warn(
|
|
827
|
+
`[raindrop] Dropped ${dropped} span(s) produced under a different API key than the tracing pipeline's (total dropped: ${total}). One process has ONE OTel pipeline authenticating with the first tracing-enabled client's key; tracing for a different key/org in the same process is unsupported \u2014 run it in its own process. Manual events (track_ai/begin/finish/signals/identify) are unaffected.`
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
export(spans, resultCallback) {
|
|
832
|
+
let allowed;
|
|
833
|
+
let dropped;
|
|
834
|
+
try {
|
|
835
|
+
({ allowed, dropped } = this.partition(spans));
|
|
836
|
+
} catch (e) {
|
|
837
|
+
if (foreignClientSeen()) {
|
|
838
|
+
this.warnDropped(spans.length);
|
|
839
|
+
resultCallback({ code: EXPORT_FAILED });
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
this.inner.export(spans, resultCallback);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (dropped) {
|
|
846
|
+
this.warnDropped(dropped);
|
|
847
|
+
}
|
|
848
|
+
if (allowed.length === 0) {
|
|
849
|
+
resultCallback({ code: EXPORT_SUCCESS });
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
this.inner.export(allowed, resultCallback);
|
|
853
|
+
}
|
|
854
|
+
shutdown() {
|
|
855
|
+
return this.inner.shutdown();
|
|
856
|
+
}
|
|
857
|
+
forceFlush() {
|
|
858
|
+
return this.inner.forceFlush ? this.inner.forceFlush() : Promise.resolve();
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
function buildGuardedExporter(baseUrl, headers, ownerAuthHint) {
|
|
862
|
+
const inner = new OTLPProtoTraceExporter({
|
|
863
|
+
url: `${baseUrl}/v1/traces`,
|
|
864
|
+
headers
|
|
865
|
+
});
|
|
866
|
+
return new GuardedSpanExporter(inner, ownerAuthHint);
|
|
867
|
+
}
|
|
868
|
+
function pipelineOwnerHint() {
|
|
869
|
+
return getState().ownerAuthHint;
|
|
870
|
+
}
|
|
871
|
+
function claimPipeline(authHint, projectId) {
|
|
872
|
+
const state = getState();
|
|
873
|
+
if (state.pipelineClaimed) {
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
state.pipelineClaimed = true;
|
|
877
|
+
state.ownerAuthHint = authHint;
|
|
878
|
+
state.ownerProjectId = projectId;
|
|
879
|
+
if (state.foreignClientSeen && state.pendingMultiKeyWarning) {
|
|
880
|
+
emitMultiKeyWarningOnce();
|
|
881
|
+
}
|
|
882
|
+
return true;
|
|
883
|
+
}
|
|
884
|
+
function releasePipelineClaim() {
|
|
885
|
+
const state = getState();
|
|
886
|
+
state.pipelineClaimed = false;
|
|
887
|
+
state.ownerAuthHint = void 0;
|
|
888
|
+
state.ownerProjectId = void 0;
|
|
889
|
+
}
|
|
890
|
+
function markTraceloopConfiguredWithoutClaim() {
|
|
891
|
+
getState().traceloopConfiguredWithoutClaim = true;
|
|
892
|
+
}
|
|
893
|
+
function traceloopConfiguredWithoutClaim() {
|
|
894
|
+
return getState().traceloopConfiguredWithoutClaim;
|
|
895
|
+
}
|
|
896
|
+
|
|
540
897
|
// src/tracing/tracer-core.ts
|
|
541
898
|
import { context as context4, SpanStatusCode as SpanStatusCode4, trace as trace4 } from "@opentelemetry/api";
|
|
542
899
|
import { OTLPTraceExporter as OTLPHttpTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
@@ -552,7 +909,7 @@ import {
|
|
|
552
909
|
AIPlatformInstrumentation,
|
|
553
910
|
VertexAIInstrumentation
|
|
554
911
|
} from "@traceloop/instrumentation-vertexai";
|
|
555
|
-
import * as
|
|
912
|
+
import * as traceloop4 from "@traceloop/node-server-sdk";
|
|
556
913
|
import { WeakValueMap } from "weakref";
|
|
557
914
|
|
|
558
915
|
// src/tracing/direct/http.ts
|
|
@@ -835,7 +1192,11 @@ var DirectTraceShipper = class {
|
|
|
835
1192
|
attrString2("traceloop.entity.input", params.input),
|
|
836
1193
|
attrString2("traceloop.entity.output", params.output),
|
|
837
1194
|
// Duration tracking
|
|
838
|
-
attrInt2("traceloop.entity.duration_ms", params.durationMs)
|
|
1195
|
+
attrInt2("traceloop.entity.duration_ms", params.durationMs),
|
|
1196
|
+
// Per-span project routing: the ingest boundary routes on this attribute
|
|
1197
|
+
// (org-validated) and falls back to the request's project header. Direct
|
|
1198
|
+
// spans ship on this instance's own key, so no cross-key auth hint.
|
|
1199
|
+
attrString2(PROJECT_ID_SPAN_ATTRIBUTE, this.projectId)
|
|
839
1200
|
];
|
|
840
1201
|
for (const [key, value] of Object.entries(params.properties)) {
|
|
841
1202
|
if (value === void 0) {
|
|
@@ -1139,12 +1500,27 @@ var DirectToolSpan = class {
|
|
|
1139
1500
|
}
|
|
1140
1501
|
};
|
|
1141
1502
|
var LiveInteraction = class {
|
|
1142
|
-
constructor(context5, traceId, analytics, directShipper) {
|
|
1503
|
+
constructor(context5, traceId, analytics, directShipper, routing) {
|
|
1143
1504
|
this.context = context5;
|
|
1144
1505
|
this.analytics = analytics;
|
|
1145
1506
|
this.tracer = trace2.getTracer("traceloop.tracer");
|
|
1146
1507
|
this.traceId = traceId;
|
|
1147
1508
|
this.directShipper = directShipper;
|
|
1509
|
+
this.routing = routing;
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Record the routing binding this interaction pushed onto the context stack
|
|
1513
|
+
* (via {@link bindRoutingContext} in `begin()`) so {@link finish} removes
|
|
1514
|
+
* exactly its own entry — non-LIFO safe, and leaving any still-open sibling's
|
|
1515
|
+
* binding intact.
|
|
1516
|
+
*/
|
|
1517
|
+
setBoundContext(bound) {
|
|
1518
|
+
this.boundContext = bound;
|
|
1519
|
+
}
|
|
1520
|
+
/** Stamp a manually-created OTel span with this interaction's routing. */
|
|
1521
|
+
stampRouting(span) {
|
|
1522
|
+
if (!this.routing) return;
|
|
1523
|
+
stampSpan(span, this.routing.projectId, this.routing.authHint);
|
|
1148
1524
|
}
|
|
1149
1525
|
ensureTraceId(preferred) {
|
|
1150
1526
|
if (preferred) {
|
|
@@ -1213,8 +1589,9 @@ var LiveInteraction = class {
|
|
|
1213
1589
|
context2.active(),
|
|
1214
1590
|
trace2.wrapSpanContext(spanContext)
|
|
1215
1591
|
);
|
|
1592
|
+
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
1216
1593
|
try {
|
|
1217
|
-
const result = await context2.with(wrappedContext,
|
|
1594
|
+
const result = await context2.with(wrappedContext, invoke);
|
|
1218
1595
|
const endTimeMs = Date.now();
|
|
1219
1596
|
this.directShipper.sendSpan({
|
|
1220
1597
|
name: taskName,
|
|
@@ -1249,11 +1626,17 @@ var LiveInteraction = class {
|
|
|
1249
1626
|
}
|
|
1250
1627
|
}
|
|
1251
1628
|
const wrappedFn = (...fnArgs) => {
|
|
1252
|
-
|
|
1253
|
-
const activeTraceId =
|
|
1629
|
+
const activeSpan = trace2.getSpan(context2.active());
|
|
1630
|
+
const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
|
|
1254
1631
|
if (activeTraceId) {
|
|
1255
1632
|
this.traceId = activeTraceId;
|
|
1256
1633
|
}
|
|
1634
|
+
if (activeSpan) {
|
|
1635
|
+
this.stampRouting(activeSpan);
|
|
1636
|
+
}
|
|
1637
|
+
if (this.routing) {
|
|
1638
|
+
return withRoutingContext(this.routing, () => fn.apply(thisArg, fnArgs));
|
|
1639
|
+
}
|
|
1257
1640
|
return fn.apply(thisArg, fnArgs);
|
|
1258
1641
|
};
|
|
1259
1642
|
return traceloop.withTask(
|
|
@@ -1265,7 +1648,6 @@ var LiveInteraction = class {
|
|
|
1265
1648
|
suppressTracing: params.suppressTracing
|
|
1266
1649
|
},
|
|
1267
1650
|
wrappedFn,
|
|
1268
|
-
void 0,
|
|
1269
1651
|
...args
|
|
1270
1652
|
);
|
|
1271
1653
|
}
|
|
@@ -1302,10 +1684,11 @@ var LiveInteraction = class {
|
|
|
1302
1684
|
context2.active(),
|
|
1303
1685
|
trace2.wrapSpanContext(spanContext)
|
|
1304
1686
|
);
|
|
1687
|
+
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
1305
1688
|
let result;
|
|
1306
1689
|
let error;
|
|
1307
1690
|
try {
|
|
1308
|
-
result = await context2.with(wrappedContext,
|
|
1691
|
+
result = await context2.with(wrappedContext, invoke);
|
|
1309
1692
|
} catch (err) {
|
|
1310
1693
|
error = err instanceof Error ? err.message : String(err);
|
|
1311
1694
|
const endTimeMs2 = Date.now();
|
|
@@ -1373,6 +1756,9 @@ var LiveInteraction = class {
|
|
|
1373
1756
|
const activeSpan = trace2.getSpan(context2.active());
|
|
1374
1757
|
const ctx = activeSpan == null ? void 0 : activeSpan.spanContext();
|
|
1375
1758
|
const liveSpanId = ctx && isValidSpanId(ctx.spanId) ? ctx.spanId : void 0;
|
|
1759
|
+
if (activeSpan) {
|
|
1760
|
+
this.stampRouting(activeSpan);
|
|
1761
|
+
}
|
|
1376
1762
|
emitLive({
|
|
1377
1763
|
type: "tool_start",
|
|
1378
1764
|
spanId: liveSpanId,
|
|
@@ -1381,7 +1767,7 @@ var LiveInteraction = class {
|
|
|
1381
1767
|
metadata: params.inputParameters ? { args: params.inputParameters } : void 0
|
|
1382
1768
|
});
|
|
1383
1769
|
try {
|
|
1384
|
-
const r = await fn.apply(thisArg, wrappedArgs);
|
|
1770
|
+
const r = this.routing ? await withRoutingContext(this.routing, () => fn.apply(thisArg, wrappedArgs)) : await fn.apply(thisArg, wrappedArgs);
|
|
1385
1771
|
emitLive({
|
|
1386
1772
|
type: "tool_result",
|
|
1387
1773
|
spanId: liveSpanId,
|
|
@@ -1417,7 +1803,6 @@ var LiveInteraction = class {
|
|
|
1417
1803
|
suppressTracing: params.suppressTracing
|
|
1418
1804
|
},
|
|
1419
1805
|
wrapped,
|
|
1420
|
-
void 0,
|
|
1421
1806
|
...args
|
|
1422
1807
|
);
|
|
1423
1808
|
}
|
|
@@ -1428,6 +1813,7 @@ var LiveInteraction = class {
|
|
|
1428
1813
|
setAssociationProperties(span, contextProperties);
|
|
1429
1814
|
span.setAttribute("traceloop.span.kind", "task");
|
|
1430
1815
|
setAssociationProperties(span, properties);
|
|
1816
|
+
this.stampRouting(span);
|
|
1431
1817
|
return span;
|
|
1432
1818
|
}
|
|
1433
1819
|
startToolSpan(params) {
|
|
@@ -1469,6 +1855,7 @@ var LiveInteraction = class {
|
|
|
1469
1855
|
setAssociationProperties(span, contextProperties);
|
|
1470
1856
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
1471
1857
|
setAssociationProperties(span, properties);
|
|
1858
|
+
this.stampRouting(span);
|
|
1472
1859
|
if (inputParameters !== void 0) {
|
|
1473
1860
|
span.setAttribute("traceloop.entity.input", serializeSpanValue(inputParameters));
|
|
1474
1861
|
}
|
|
@@ -1571,6 +1958,8 @@ var LiveInteraction = class {
|
|
|
1571
1958
|
}
|
|
1572
1959
|
async finish(resultEvent) {
|
|
1573
1960
|
var _a, _b, _c, _d;
|
|
1961
|
+
unbindRoutingContext(this.boundContext);
|
|
1962
|
+
this.boundContext = void 0;
|
|
1574
1963
|
if (!this.traceId) {
|
|
1575
1964
|
this.resolveLiveTraceId();
|
|
1576
1965
|
}
|
|
@@ -1658,6 +2047,7 @@ var LiveInteraction = class {
|
|
|
1658
2047
|
setAssociationProperties(span, contextProperties);
|
|
1659
2048
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
1660
2049
|
setAssociationProperties(span, properties);
|
|
2050
|
+
this.stampRouting(span);
|
|
1661
2051
|
if (input !== void 0) {
|
|
1662
2052
|
span.setAttribute("traceloop.entity.input", stringifyBounded(input));
|
|
1663
2053
|
}
|
|
@@ -1703,10 +2093,16 @@ var LiveInteraction = class {
|
|
|
1703
2093
|
import { context as context3, isValidSpanId as isValidSpanId2, SpanStatusCode as SpanStatusCode3, trace as trace3 } from "@opentelemetry/api";
|
|
1704
2094
|
import * as traceloop2 from "@traceloop/node-server-sdk";
|
|
1705
2095
|
var LiveTracer = class {
|
|
1706
|
-
constructor(globalProperties, directShipper) {
|
|
2096
|
+
constructor(globalProperties, directShipper, routing) {
|
|
1707
2097
|
this.tracer = trace3.getTracer("traceloop.tracer");
|
|
1708
2098
|
this.globalProperties = globalProperties || {};
|
|
1709
2099
|
this.directShipper = directShipper;
|
|
2100
|
+
this.routing = routing;
|
|
2101
|
+
}
|
|
2102
|
+
/** Stamp a manually-created OTel span with this tracer's client routing. */
|
|
2103
|
+
stampRouting(span) {
|
|
2104
|
+
if (!this.routing) return;
|
|
2105
|
+
stampSpan(span, this.routing.projectId, this.routing.authHint);
|
|
1710
2106
|
}
|
|
1711
2107
|
emitLiveEvent(event) {
|
|
1712
2108
|
var _a, _b;
|
|
@@ -1729,6 +2125,16 @@ var LiveTracer = class {
|
|
|
1729
2125
|
...params.properties || {}
|
|
1730
2126
|
};
|
|
1731
2127
|
const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
|
|
2128
|
+
const wrappedFn = (...fnArgs) => {
|
|
2129
|
+
const activeSpan = trace3.getSpan(context3.active());
|
|
2130
|
+
if (activeSpan) {
|
|
2131
|
+
this.stampRouting(activeSpan);
|
|
2132
|
+
}
|
|
2133
|
+
if (this.routing) {
|
|
2134
|
+
return withRoutingContext(this.routing, () => fn.apply(thisArg, fnArgs));
|
|
2135
|
+
}
|
|
2136
|
+
return fn.apply(thisArg, fnArgs);
|
|
2137
|
+
};
|
|
1732
2138
|
return traceloop2.withTask(
|
|
1733
2139
|
{
|
|
1734
2140
|
name: taskName,
|
|
@@ -1737,8 +2143,7 @@ var LiveTracer = class {
|
|
|
1737
2143
|
traceContent: params.traceContent,
|
|
1738
2144
|
suppressTracing: params.suppressTracing
|
|
1739
2145
|
},
|
|
1740
|
-
|
|
1741
|
-
thisArg,
|
|
2146
|
+
wrappedFn,
|
|
1742
2147
|
...args
|
|
1743
2148
|
);
|
|
1744
2149
|
}
|
|
@@ -1787,6 +2192,7 @@ var LiveTracer = class {
|
|
|
1787
2192
|
const span = this.tracer.startSpan(name, {
|
|
1788
2193
|
startTime: startTimeMs
|
|
1789
2194
|
});
|
|
2195
|
+
this.stampRouting(span);
|
|
1790
2196
|
Object.entries(this.globalProperties).forEach(([key, value]) => {
|
|
1791
2197
|
span.setAttribute("traceloop.association.properties." + key, String(value));
|
|
1792
2198
|
});
|
|
@@ -1831,6 +2237,59 @@ var LiveTracer = class {
|
|
|
1831
2237
|
}
|
|
1832
2238
|
};
|
|
1833
2239
|
|
|
2240
|
+
// src/tracing/exit-flush.ts
|
|
2241
|
+
import * as traceloop3 from "@traceloop/node-server-sdk";
|
|
2242
|
+
var STATE_KEY2 = /* @__PURE__ */ Symbol.for("raindrop.tracing.exitFlushState");
|
|
2243
|
+
function getState2() {
|
|
2244
|
+
const holder = globalThis;
|
|
2245
|
+
let state = holder[STATE_KEY2];
|
|
2246
|
+
if (!state) {
|
|
2247
|
+
state = {
|
|
2248
|
+
clientFlushers: /* @__PURE__ */ new Set(),
|
|
2249
|
+
pipelineFlushNeeded: false,
|
|
2250
|
+
handlerRegistered: false
|
|
2251
|
+
};
|
|
2252
|
+
holder[STATE_KEY2] = state;
|
|
2253
|
+
}
|
|
2254
|
+
return state;
|
|
2255
|
+
}
|
|
2256
|
+
function ensureExitHandler(state) {
|
|
2257
|
+
if (state.handlerRegistered) return;
|
|
2258
|
+
if (typeof process === "undefined" || typeof process.once !== "function") return;
|
|
2259
|
+
state.handlerRegistered = true;
|
|
2260
|
+
process.once("beforeExit", () => {
|
|
2261
|
+
void flushAll();
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
function registerClientFlusher(flush) {
|
|
2265
|
+
const state = getState2();
|
|
2266
|
+
state.clientFlushers.add(flush);
|
|
2267
|
+
ensureExitHandler(state);
|
|
2268
|
+
return () => {
|
|
2269
|
+
state.clientFlushers.delete(flush);
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
function markPipelineForExitFlush() {
|
|
2273
|
+
const state = getState2();
|
|
2274
|
+
state.pipelineFlushNeeded = true;
|
|
2275
|
+
ensureExitHandler(state);
|
|
2276
|
+
}
|
|
2277
|
+
async function flushAll() {
|
|
2278
|
+
const state = getState2();
|
|
2279
|
+
const tasks = [];
|
|
2280
|
+
for (const flush of state.clientFlushers) {
|
|
2281
|
+
tasks.push(Promise.resolve().then(flush).catch(() => {
|
|
2282
|
+
}));
|
|
2283
|
+
}
|
|
2284
|
+
if (state.pipelineFlushNeeded) {
|
|
2285
|
+
tasks.push(
|
|
2286
|
+
Promise.resolve().then(() => traceloop3.forceFlush()).catch(() => {
|
|
2287
|
+
})
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
await Promise.all(tasks);
|
|
2291
|
+
}
|
|
2292
|
+
|
|
1834
2293
|
// src/tracing/tracer-core.ts
|
|
1835
2294
|
if (localDebuggerEnabled()) {
|
|
1836
2295
|
if (!process.env.OTEL_EXPORTER_OTLP_PROTOCOL) {
|
|
@@ -1939,6 +2398,29 @@ function resolveLocalDebuggerExporterBaseUrl(baseUrlOpt) {
|
|
|
1939
2398
|
function createLocalDebuggerOtlpExporter(config) {
|
|
1940
2399
|
return new OTLPHttpTraceExporter(config);
|
|
1941
2400
|
}
|
|
2401
|
+
function parseTraceloopHeaders(value) {
|
|
2402
|
+
const headers = {};
|
|
2403
|
+
for (const entry of value.split(",")) {
|
|
2404
|
+
const keyPairPart = entry.split(";")[0];
|
|
2405
|
+
const sep = keyPairPart.indexOf("=");
|
|
2406
|
+
if (sep <= 0) continue;
|
|
2407
|
+
try {
|
|
2408
|
+
const key = decodeURIComponent(keyPairPart.slice(0, sep).trim());
|
|
2409
|
+
const val = decodeURIComponent(keyPairPart.slice(sep + 1).trim());
|
|
2410
|
+
if (key.length > 0 && val.length > 0) headers[key] = val;
|
|
2411
|
+
} catch (e) {
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
return headers;
|
|
2415
|
+
}
|
|
2416
|
+
function traceloopDefaultHeaders(writeKey) {
|
|
2417
|
+
const env = process.env.TRACELOOP_HEADERS;
|
|
2418
|
+
if (env) {
|
|
2419
|
+
const parsed = parseTraceloopHeaders(env);
|
|
2420
|
+
if (Object.keys(parsed).length > 0) return parsed;
|
|
2421
|
+
}
|
|
2422
|
+
return { Authorization: `Bearer ${writeKey}` };
|
|
2423
|
+
}
|
|
1942
2424
|
function createLocalDebuggerSpanProcessor(options) {
|
|
1943
2425
|
const localDebuggerUrl = resolveLocalDebuggerExporterBaseUrl(options.localDebuggerUrlOpt);
|
|
1944
2426
|
if (!localDebuggerUrl) {
|
|
@@ -1949,7 +2431,7 @@ function createLocalDebuggerSpanProcessor(options) {
|
|
|
1949
2431
|
headers: {}
|
|
1950
2432
|
});
|
|
1951
2433
|
try {
|
|
1952
|
-
return
|
|
2434
|
+
return traceloop4.createSpanProcessor({
|
|
1953
2435
|
apiKey: options.writeKey,
|
|
1954
2436
|
baseUrl: localDebuggerUrl,
|
|
1955
2437
|
disableBatch: options.disableBatching,
|
|
@@ -1965,12 +2447,6 @@ function createLocalDebuggerSpanProcessor(options) {
|
|
|
1965
2447
|
return void 0;
|
|
1966
2448
|
}
|
|
1967
2449
|
}
|
|
1968
|
-
function mergeWithBestEffortLocalDebuggerProcessor(processor, localDebuggerProcessor) {
|
|
1969
|
-
if (!localDebuggerProcessor) {
|
|
1970
|
-
return processor;
|
|
1971
|
-
}
|
|
1972
|
-
return new CompositeSpanProcessor(processor ? [processor] : [], [localDebuggerProcessor]);
|
|
1973
|
-
}
|
|
1974
2450
|
var warnedSpanNormalizeFailure = false;
|
|
1975
2451
|
var INVALID_OTEL_SPAN_ID = "0000000000000000";
|
|
1976
2452
|
function normalizeSpanForV1Exporter(span) {
|
|
@@ -2270,13 +2746,12 @@ function createManualInstrumentations(instrumentModules) {
|
|
|
2270
2746
|
}
|
|
2271
2747
|
return instrumentations;
|
|
2272
2748
|
}
|
|
2273
|
-
var activeInteractions = new WeakValueMap();
|
|
2274
|
-
var activeInteractionsByEventId = new WeakValueMap();
|
|
2275
2749
|
function getCurrentTraceId() {
|
|
2276
2750
|
var _a;
|
|
2277
2751
|
return (_a = trace4.getSpan(context4.active())) == null ? void 0 : _a.spanContext().traceId;
|
|
2278
2752
|
}
|
|
2279
2753
|
var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
2754
|
+
var _a;
|
|
2280
2755
|
process.env.TRACELOOP_TELEMETRY = "false";
|
|
2281
2756
|
const {
|
|
2282
2757
|
logLevel,
|
|
@@ -2291,12 +2766,15 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2291
2766
|
...otherOptions
|
|
2292
2767
|
} = options;
|
|
2293
2768
|
const cloudEnabledResolved = cloudEnabled != null ? cloudEnabled : true;
|
|
2769
|
+
const authHint = authHintForKey(writeKey);
|
|
2770
|
+
const clientTracingExports = !useExternalOtel && cloudEnabledResolved && tracingEnabled !== false;
|
|
2771
|
+
registerClientKey(authHint, clientTracingExports);
|
|
2294
2772
|
const withProjectIdHeaders = (existing) => {
|
|
2295
2773
|
if (!projectId) {
|
|
2296
2774
|
return existing;
|
|
2297
2775
|
}
|
|
2298
2776
|
return {
|
|
2299
|
-
|
|
2777
|
+
...traceloopDefaultHeaders(writeKey),
|
|
2300
2778
|
...existing != null ? existing : {},
|
|
2301
2779
|
...projectIdHeaders(projectId)
|
|
2302
2780
|
};
|
|
@@ -2318,9 +2796,12 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2318
2796
|
projectId
|
|
2319
2797
|
}) : void 0;
|
|
2320
2798
|
let traceloopInitialized = false;
|
|
2799
|
+
let claimedPipeline = false;
|
|
2800
|
+
const activeInteractions = new WeakValueMap();
|
|
2801
|
+
const activeInteractionsByEventId = new WeakValueMap();
|
|
2321
2802
|
try {
|
|
2322
2803
|
if (useExternalOtel) {
|
|
2323
|
-
|
|
2804
|
+
traceloop4.initialize({
|
|
2324
2805
|
baseUrl: apiUrl,
|
|
2325
2806
|
apiKey: writeKey,
|
|
2326
2807
|
logLevel,
|
|
@@ -2332,6 +2813,7 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2332
2813
|
// DO NOT create NodeSDK - customer has their own
|
|
2333
2814
|
});
|
|
2334
2815
|
traceloopInitialized = true;
|
|
2816
|
+
markTraceloopConfiguredWithoutClaim();
|
|
2335
2817
|
if (isDebug) {
|
|
2336
2818
|
console.log(
|
|
2337
2819
|
"[raindrop] External OTEL mode active. Add raindrop.createSpanProcessor() to your NodeSDK's spanProcessors. Register instrumentations (AnthropicInstrumentation, etc.) on your NodeSDK."
|
|
@@ -2348,12 +2830,12 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2348
2830
|
const localDebuggerProcessor = createLocalDebuggerSpanProcessor({
|
|
2349
2831
|
writeKey,
|
|
2350
2832
|
disableBatching,
|
|
2351
|
-
allowedInstrumentationLibraries:
|
|
2833
|
+
allowedInstrumentationLibraries: traceloop4.ALL_INSTRUMENTATION_LIBRARIES,
|
|
2352
2834
|
localDebuggerUrlOpt: localDebuggerUrl
|
|
2353
2835
|
});
|
|
2354
2836
|
if (!cloudEnabledResolved) {
|
|
2355
2837
|
if (localDebuggerProcessor) {
|
|
2356
|
-
|
|
2838
|
+
traceloop4.initialize({
|
|
2357
2839
|
baseUrl: apiUrl,
|
|
2358
2840
|
apiKey: writeKey,
|
|
2359
2841
|
...otherOptions,
|
|
@@ -2364,8 +2846,9 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2364
2846
|
processor: localDebuggerProcessor
|
|
2365
2847
|
});
|
|
2366
2848
|
traceloopInitialized = true;
|
|
2849
|
+
markTraceloopConfiguredWithoutClaim();
|
|
2367
2850
|
} else {
|
|
2368
|
-
|
|
2851
|
+
traceloop4.initialize({
|
|
2369
2852
|
baseUrl: apiUrl,
|
|
2370
2853
|
apiKey: writeKey,
|
|
2371
2854
|
logLevel,
|
|
@@ -2373,33 +2856,91 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2373
2856
|
tracingEnabled: false
|
|
2374
2857
|
});
|
|
2375
2858
|
traceloopInitialized = true;
|
|
2859
|
+
markTraceloopConfiguredWithoutClaim();
|
|
2376
2860
|
}
|
|
2861
|
+
} else if (tracingEnabled === false) {
|
|
2862
|
+
traceloopInitialized = false;
|
|
2377
2863
|
} else {
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
)
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
})
|
|
2394
|
-
|
|
2864
|
+
const claimed = claimPipeline(authHint, projectId);
|
|
2865
|
+
claimedPipeline = claimed;
|
|
2866
|
+
const ownerHint = pipelineOwnerHint();
|
|
2867
|
+
if (!claimed && authHint !== ownerHint) {
|
|
2868
|
+
markForeignClient();
|
|
2869
|
+
console.warn(
|
|
2870
|
+
"[raindrop] The OTel tracing pipeline is already initialized with a DIFFERENT api key. One process supports one tracing key/org: auto-instrumented spans from this client will be dropped at export, and spans not bound to any client (no begin()/asCurrent()) will be dropped as unattributable (manual events are unaffected and route normally). Run this client in its own process for tracing."
|
|
2871
|
+
);
|
|
2872
|
+
}
|
|
2873
|
+
if (claimed && traceloopConfiguredWithoutClaim()) {
|
|
2874
|
+
releasePipelineClaim();
|
|
2875
|
+
claimedPipeline = false;
|
|
2876
|
+
console.warn(
|
|
2877
|
+
"[raindrop] Cannot initialize the cloud tracing pipeline: OpenTelemetry was already configured in this process by an earlier Raindrop client (external-OTEL mode, or a local-only/Workshop client with no write key). Traceloop's tracer provider is fixed once per process, so this client's auto-instrumented spans will NOT be exported. Construct the cloud tracing-enabled client FIRST, or run it in its own process. Manual events (track_ai/begin/finish/signals/identify) are unaffected."
|
|
2878
|
+
);
|
|
2879
|
+
} else if (claimed) {
|
|
2880
|
+
const exporterHeaders = (_a = withProjectIdHeaders(otherOptions.headers)) != null ? _a : traceloopDefaultHeaders(writeKey);
|
|
2881
|
+
let guardedExporter;
|
|
2882
|
+
try {
|
|
2883
|
+
const callerExporter = otherOptions.exporter;
|
|
2884
|
+
guardedExporter = callerExporter ? new GuardedSpanExporter(callerExporter, ownerHint) : buildGuardedExporter(apiUrl, exporterHeaders, ownerHint);
|
|
2885
|
+
} catch (guardError) {
|
|
2886
|
+
releasePipelineClaim();
|
|
2887
|
+
claimedPipeline = false;
|
|
2888
|
+
console.warn(
|
|
2889
|
+
`[raindrop] could not install the guarded span exporter (${guardError instanceof Error ? guardError.message : guardError}); disabling tracing rather than running an unguarded pipeline. Manual events are unaffected.`
|
|
2890
|
+
);
|
|
2891
|
+
}
|
|
2892
|
+
if (guardedExporter) {
|
|
2893
|
+
const contextProcessor = new RaindropContextSpanProcessor();
|
|
2894
|
+
const callerProcessor = otherOptions.processor;
|
|
2895
|
+
const processor = new CompositeSpanProcessor(
|
|
2896
|
+
callerProcessor ? [contextProcessor, callerProcessor] : [contextProcessor],
|
|
2897
|
+
localDebuggerProcessor ? [localDebuggerProcessor] : []
|
|
2898
|
+
);
|
|
2899
|
+
try {
|
|
2900
|
+
traceloop4.initialize({
|
|
2901
|
+
baseUrl: apiUrl,
|
|
2902
|
+
apiKey: writeKey,
|
|
2903
|
+
...otherOptions,
|
|
2904
|
+
logLevel,
|
|
2905
|
+
silenceInitializationMessage: true,
|
|
2906
|
+
// This branch only runs when tracing is enabled (the disabled
|
|
2907
|
+
// case is handled above), so tracing is always on here.
|
|
2908
|
+
tracingEnabled: true,
|
|
2909
|
+
disableBatch: disableBatching,
|
|
2910
|
+
processor,
|
|
2911
|
+
exporter: guardedExporter
|
|
2912
|
+
});
|
|
2913
|
+
traceloopInitialized = true;
|
|
2914
|
+
} catch (initError) {
|
|
2915
|
+
releasePipelineClaim();
|
|
2916
|
+
claimedPipeline = false;
|
|
2917
|
+
throw initError;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
} else {
|
|
2921
|
+
traceloopInitialized = true;
|
|
2922
|
+
}
|
|
2395
2923
|
}
|
|
2396
2924
|
}
|
|
2397
2925
|
} catch (error) {
|
|
2926
|
+
if (claimedPipeline && !traceloopInitialized) {
|
|
2927
|
+
releasePipelineClaim();
|
|
2928
|
+
claimedPipeline = false;
|
|
2929
|
+
}
|
|
2398
2930
|
console.warn(
|
|
2399
2931
|
"[raindrop] Failed to initialize traceloop. Spans will not be sent.",
|
|
2400
2932
|
error instanceof Error ? error.message : error
|
|
2401
2933
|
);
|
|
2402
2934
|
}
|
|
2935
|
+
if (traceloopInitialized) {
|
|
2936
|
+
markPipelineForExitFlush();
|
|
2937
|
+
}
|
|
2938
|
+
const deregisterExitFlusher = directShipper ? registerClientFlusher(async () => {
|
|
2939
|
+
try {
|
|
2940
|
+
await directShipper.flush();
|
|
2941
|
+
} catch (e) {
|
|
2942
|
+
}
|
|
2943
|
+
}) : void 0;
|
|
2403
2944
|
return {
|
|
2404
2945
|
/**
|
|
2405
2946
|
* Returns instrumentation instances for your NodeSDK.
|
|
@@ -2487,7 +3028,7 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2487
3028
|
);
|
|
2488
3029
|
}
|
|
2489
3030
|
const headers = withProjectIdHeaders(processorOptions == null ? void 0 : processorOptions.headers);
|
|
2490
|
-
const productionProcessor =
|
|
3031
|
+
const productionProcessor = traceloop4.createSpanProcessor({
|
|
2491
3032
|
baseUrl: apiUrl,
|
|
2492
3033
|
apiKey: writeKey,
|
|
2493
3034
|
disableBatch: disableBatching,
|
|
@@ -2500,12 +3041,16 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2500
3041
|
allowedInstrumentationLibraries: processorOptions == null ? void 0 : processorOptions.allowedInstrumentationLibraries,
|
|
2501
3042
|
localDebuggerUrlOpt: localDebuggerUrl
|
|
2502
3043
|
});
|
|
3044
|
+
const contextProcessor = new RaindropContextSpanProcessor();
|
|
2503
3045
|
return withV2SpanCompat(
|
|
2504
|
-
|
|
3046
|
+
new CompositeSpanProcessor(
|
|
3047
|
+
[contextProcessor, productionProcessor],
|
|
3048
|
+
localDebuggerProcessor ? [localDebuggerProcessor] : []
|
|
3049
|
+
)
|
|
2505
3050
|
);
|
|
2506
3051
|
},
|
|
2507
3052
|
begin(traceContext) {
|
|
2508
|
-
var
|
|
3053
|
+
var _a2;
|
|
2509
3054
|
if (!traceContext.eventId) {
|
|
2510
3055
|
traceContext.eventId = crypto.randomUUID();
|
|
2511
3056
|
}
|
|
@@ -2514,19 +3059,27 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2514
3059
|
traceContext,
|
|
2515
3060
|
traceId,
|
|
2516
3061
|
analytics,
|
|
2517
|
-
directShipper
|
|
3062
|
+
directShipper,
|
|
3063
|
+
{ projectId, authHint }
|
|
2518
3064
|
);
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
...
|
|
3065
|
+
const bound = bindRoutingContext({ projectId, authHint }, interaction);
|
|
3066
|
+
interaction.setBoundContext(bound);
|
|
3067
|
+
try {
|
|
3068
|
+
analytics._trackAiPartial({
|
|
3069
|
+
...traceContext,
|
|
3070
|
+
properties: {
|
|
3071
|
+
...(_a2 = traceContext.properties) != null ? _a2 : {},
|
|
3072
|
+
...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
|
|
3073
|
+
}
|
|
3074
|
+
});
|
|
3075
|
+
if (interaction.getTraceId()) {
|
|
3076
|
+
activeInteractions.set(interaction.getTraceId(), interaction);
|
|
2524
3077
|
}
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
3078
|
+
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
3079
|
+
} catch (error) {
|
|
3080
|
+
unbindRoutingContext(bound);
|
|
3081
|
+
throw error;
|
|
2528
3082
|
}
|
|
2529
|
-
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
2530
3083
|
return interaction;
|
|
2531
3084
|
},
|
|
2532
3085
|
getActiveInteraction(eventId) {
|
|
@@ -2541,12 +3094,15 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2541
3094
|
return interactionByTraceId;
|
|
2542
3095
|
}
|
|
2543
3096
|
}
|
|
2544
|
-
const interaction = new LiveInteraction({ eventId }, traceId, analytics, directShipper
|
|
3097
|
+
const interaction = new LiveInteraction({ eventId }, traceId, analytics, directShipper, {
|
|
3098
|
+
projectId,
|
|
3099
|
+
authHint
|
|
3100
|
+
});
|
|
2545
3101
|
activeInteractionsByEventId.set(eventId, interaction);
|
|
2546
3102
|
return interaction;
|
|
2547
3103
|
},
|
|
2548
3104
|
tracer(globalProperties) {
|
|
2549
|
-
return new LiveTracer(globalProperties, directShipper);
|
|
3105
|
+
return new LiveTracer(globalProperties, directShipper, { projectId, authHint });
|
|
2550
3106
|
},
|
|
2551
3107
|
/**
|
|
2552
3108
|
* Best-effort drain of in-flight OTel spans and direct shipper batches.
|
|
@@ -2561,18 +3117,19 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2561
3117
|
}
|
|
2562
3118
|
if (traceloopInitialized) {
|
|
2563
3119
|
try {
|
|
2564
|
-
await
|
|
3120
|
+
await traceloop4.forceFlush();
|
|
2565
3121
|
} catch (e) {
|
|
2566
3122
|
}
|
|
2567
3123
|
}
|
|
2568
3124
|
},
|
|
2569
3125
|
async close() {
|
|
3126
|
+
deregisterExitFlusher == null ? void 0 : deregisterExitFlusher();
|
|
2570
3127
|
activeInteractions.clear();
|
|
2571
3128
|
activeInteractionsByEventId.clear();
|
|
2572
3129
|
await (directShipper == null ? void 0 : directShipper.shutdown());
|
|
2573
3130
|
if (traceloopInitialized) {
|
|
2574
3131
|
try {
|
|
2575
|
-
await
|
|
3132
|
+
await traceloop4.forceFlush();
|
|
2576
3133
|
} catch (e) {
|
|
2577
3134
|
}
|
|
2578
3135
|
}
|
|
@@ -2598,6 +3155,8 @@ export {
|
|
|
2598
3155
|
projectIdHeaders,
|
|
2599
3156
|
SHUTDOWN_DEADLINE_MS,
|
|
2600
3157
|
POST_SHUTDOWN_TIMEOUT_MS,
|
|
3158
|
+
withRoutingContext,
|
|
2601
3159
|
package_default,
|
|
3160
|
+
authHintForKey,
|
|
2602
3161
|
tracing
|
|
2603
3162
|
};
|