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
package/dist/index.js
CHANGED
|
@@ -5771,7 +5771,13 @@ __export(index_exports, {
|
|
|
5771
5771
|
});
|
|
5772
5772
|
module.exports = __toCommonJS(index_exports);
|
|
5773
5773
|
|
|
5774
|
-
//
|
|
5774
|
+
// src/lib/inject-als.ts
|
|
5775
|
+
var import_node_async_hooks = require("async_hooks");
|
|
5776
|
+
if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
|
|
5777
|
+
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_node_async_hooks.AsyncLocalStorage;
|
|
5778
|
+
}
|
|
5779
|
+
|
|
5780
|
+
// ../core/dist/chunk-ITAZONWL.js
|
|
5775
5781
|
function normalizeFeatureFlags(input) {
|
|
5776
5782
|
if (Array.isArray(input)) {
|
|
5777
5783
|
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
@@ -6166,6 +6172,171 @@ var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
|
6166
6172
|
"ai.response.providerMetadata"
|
|
6167
6173
|
];
|
|
6168
6174
|
var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
|
|
6175
|
+
function getAsyncLocalStorageCtor() {
|
|
6176
|
+
return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
|
|
6177
|
+
}
|
|
6178
|
+
function getWeakRefCtor() {
|
|
6179
|
+
const ctor = globalThis.WeakRef;
|
|
6180
|
+
return typeof ctor === "function" ? ctor : void 0;
|
|
6181
|
+
}
|
|
6182
|
+
var MAX_BINDING_STACK = 128;
|
|
6183
|
+
var EMPTY_STACK = [];
|
|
6184
|
+
var RoutingContextStorage = class {
|
|
6185
|
+
constructor() {
|
|
6186
|
+
this._als = null;
|
|
6187
|
+
this._enterWithUsable = false;
|
|
6188
|
+
this._syncStack = EMPTY_STACK;
|
|
6189
|
+
this._adoptionChecked = false;
|
|
6190
|
+
this._warnedNoAmbientBind = false;
|
|
6191
|
+
}
|
|
6192
|
+
maybeAdoptAsyncLocalStorage() {
|
|
6193
|
+
if (this._adoptionChecked) return;
|
|
6194
|
+
this._adoptionChecked = true;
|
|
6195
|
+
const Ctor = getAsyncLocalStorageCtor();
|
|
6196
|
+
if (!Ctor) return;
|
|
6197
|
+
const als = new Ctor();
|
|
6198
|
+
try {
|
|
6199
|
+
als.run(EMPTY_STACK, () => {
|
|
6200
|
+
});
|
|
6201
|
+
} catch (e) {
|
|
6202
|
+
return;
|
|
6203
|
+
}
|
|
6204
|
+
this._als = als;
|
|
6205
|
+
if (typeof als.enterWith === "function") {
|
|
6206
|
+
try {
|
|
6207
|
+
als.enterWith(EMPTY_STACK);
|
|
6208
|
+
this._enterWithUsable = true;
|
|
6209
|
+
} catch (e) {
|
|
6210
|
+
this._enterWithUsable = false;
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
getStack() {
|
|
6215
|
+
var _a;
|
|
6216
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
6217
|
+
if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
|
|
6218
|
+
return this._syncStack;
|
|
6219
|
+
}
|
|
6220
|
+
/**
|
|
6221
|
+
* Persist an ambient stack mutation. Returns false when an ALS is adopted but
|
|
6222
|
+
* `enterWith` is unusable (workerd): callers must NOT fall back to the
|
|
6223
|
+
* process-shared sync stack, since concurrent isolates would cross-stamp.
|
|
6224
|
+
*/
|
|
6225
|
+
setAmbientStack(stack) {
|
|
6226
|
+
if (this._als) {
|
|
6227
|
+
if (!this._enterWithUsable) return false;
|
|
6228
|
+
this._als.enterWith(stack);
|
|
6229
|
+
return true;
|
|
6230
|
+
}
|
|
6231
|
+
this._syncStack = stack;
|
|
6232
|
+
return true;
|
|
6233
|
+
}
|
|
6234
|
+
push(binding) {
|
|
6235
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
6236
|
+
if (this._als && !this._enterWithUsable) {
|
|
6237
|
+
this.warnNoAmbientBindOnce();
|
|
6238
|
+
return;
|
|
6239
|
+
}
|
|
6240
|
+
let stack = this.getStack();
|
|
6241
|
+
if (stack.length >= MAX_BINDING_STACK) {
|
|
6242
|
+
stack = stack.filter((b) => b.isLive());
|
|
6243
|
+
if (stack.length >= MAX_BINDING_STACK) {
|
|
6244
|
+
stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
|
|
6245
|
+
}
|
|
6246
|
+
}
|
|
6247
|
+
this.setAmbientStack([...stack, binding]);
|
|
6248
|
+
}
|
|
6249
|
+
remove(binding) {
|
|
6250
|
+
binding.markDead();
|
|
6251
|
+
const stack = this.getStack();
|
|
6252
|
+
const pruned = stack.filter((b) => b !== binding && b.isLive());
|
|
6253
|
+
if (pruned.length !== stack.length) {
|
|
6254
|
+
this.setAmbientStack(pruned);
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
6257
|
+
runWith(binding, callback) {
|
|
6258
|
+
this.maybeAdoptAsyncLocalStorage();
|
|
6259
|
+
if (this._als) {
|
|
6260
|
+
return this._als.run([...this.getStack(), binding], callback);
|
|
6261
|
+
}
|
|
6262
|
+
const previous = this._syncStack;
|
|
6263
|
+
this._syncStack = [...previous, binding];
|
|
6264
|
+
try {
|
|
6265
|
+
return callback();
|
|
6266
|
+
} finally {
|
|
6267
|
+
this._syncStack = previous;
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6270
|
+
current() {
|
|
6271
|
+
const stack = this.getStack();
|
|
6272
|
+
if (stack.length === 0) return void 0;
|
|
6273
|
+
const top = stack[stack.length - 1];
|
|
6274
|
+
if (top.isLive()) return top;
|
|
6275
|
+
const pruned = stack.filter((b) => b.isLive());
|
|
6276
|
+
this.setAmbientStack(pruned);
|
|
6277
|
+
return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
|
|
6278
|
+
}
|
|
6279
|
+
warnNoAmbientBindOnce() {
|
|
6280
|
+
if (this._warnedNoAmbientBind) return;
|
|
6281
|
+
this._warnedNoAmbientBind = true;
|
|
6282
|
+
console.warn(
|
|
6283
|
+
"[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."
|
|
6284
|
+
);
|
|
6285
|
+
}
|
|
6286
|
+
};
|
|
6287
|
+
var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
|
|
6288
|
+
function routingStorage() {
|
|
6289
|
+
const holder = globalThis;
|
|
6290
|
+
let storage = holder[ROUTING_STORAGE_KEY];
|
|
6291
|
+
if (!storage) {
|
|
6292
|
+
storage = new RoutingContextStorage();
|
|
6293
|
+
holder[ROUTING_STORAGE_KEY] = storage;
|
|
6294
|
+
}
|
|
6295
|
+
return storage;
|
|
6296
|
+
}
|
|
6297
|
+
function makeBoundContext(binding, owner) {
|
|
6298
|
+
const WeakRefCtor = owner !== void 0 ? getWeakRefCtor() : void 0;
|
|
6299
|
+
const ref = WeakRefCtor && owner !== void 0 ? new WeakRefCtor(owner) : void 0;
|
|
6300
|
+
let dead = false;
|
|
6301
|
+
return {
|
|
6302
|
+
projectId: binding.projectId,
|
|
6303
|
+
authHint: binding.authHint,
|
|
6304
|
+
isLive() {
|
|
6305
|
+
if (dead) return false;
|
|
6306
|
+
return ref === void 0 || ref.deref() !== void 0;
|
|
6307
|
+
},
|
|
6308
|
+
markDead() {
|
|
6309
|
+
dead = true;
|
|
6310
|
+
}
|
|
6311
|
+
};
|
|
6312
|
+
}
|
|
6313
|
+
function bindRoutingContext(binding, owner) {
|
|
6314
|
+
const bound = makeBoundContext(binding, owner);
|
|
6315
|
+
try {
|
|
6316
|
+
routingStorage().push(bound);
|
|
6317
|
+
} catch (e) {
|
|
6318
|
+
}
|
|
6319
|
+
return bound;
|
|
6320
|
+
}
|
|
6321
|
+
function unbindRoutingContext(bound) {
|
|
6322
|
+
if (!bound || !isBoundContext(bound)) return;
|
|
6323
|
+
try {
|
|
6324
|
+
routingStorage().remove(bound);
|
|
6325
|
+
} catch (e) {
|
|
6326
|
+
}
|
|
6327
|
+
}
|
|
6328
|
+
function withRoutingContext(binding, callback) {
|
|
6329
|
+
const bound = makeBoundContext(binding);
|
|
6330
|
+
return routingStorage().runWith(bound, callback);
|
|
6331
|
+
}
|
|
6332
|
+
function currentRoutingBinding() {
|
|
6333
|
+
const bound = routingStorage().current();
|
|
6334
|
+
if (!bound) return void 0;
|
|
6335
|
+
return { projectId: bound.projectId, authHint: bound.authHint };
|
|
6336
|
+
}
|
|
6337
|
+
function isBoundContext(value) {
|
|
6338
|
+
return typeof value.isLive === "function";
|
|
6339
|
+
}
|
|
6169
6340
|
|
|
6170
6341
|
// ../core/dist/index.node.js
|
|
6171
6342
|
var import_async_hooks = require("async_hooks");
|
|
@@ -10305,7 +10476,7 @@ var SignalEventSchema = external_exports.object({
|
|
|
10305
10476
|
// package.json
|
|
10306
10477
|
var package_default = {
|
|
10307
10478
|
name: "raindrop-ai",
|
|
10308
|
-
version: "0.2.
|
|
10479
|
+
version: "0.2.2",
|
|
10309
10480
|
main: "dist/index.js",
|
|
10310
10481
|
module: "dist/index.mjs",
|
|
10311
10482
|
types: "dist/index.d.ts",
|
|
@@ -10371,6 +10542,7 @@ var package_default = {
|
|
|
10371
10542
|
dependencies: {
|
|
10372
10543
|
"@opentelemetry/api": "^1.9.0",
|
|
10373
10544
|
"@opentelemetry/exporter-trace-otlp-http": "^0.57.2",
|
|
10545
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.57.2",
|
|
10374
10546
|
"@traceloop/node-server-sdk": "0.19.0-otel-v1",
|
|
10375
10547
|
weakref: "^0.2.1",
|
|
10376
10548
|
zod: "^3.23.8"
|
|
@@ -10402,6 +10574,7 @@ var package_default = {
|
|
|
10402
10574
|
"@traceloop/instrumentation-together",
|
|
10403
10575
|
"@opentelemetry/instrumentation",
|
|
10404
10576
|
"@opentelemetry/exporter-trace-otlp-http",
|
|
10577
|
+
"@opentelemetry/exporter-trace-otlp-proto",
|
|
10405
10578
|
"@opentelemetry/sdk-trace-base"
|
|
10406
10579
|
],
|
|
10407
10580
|
noExternal: [
|
|
@@ -10517,7 +10690,7 @@ var import_instrumentation_pinecone = require("@traceloop/instrumentation-pineco
|
|
|
10517
10690
|
var import_instrumentation_qdrant = require("@traceloop/instrumentation-qdrant");
|
|
10518
10691
|
var import_instrumentation_together = require("@traceloop/instrumentation-together");
|
|
10519
10692
|
var import_instrumentation_vertexai = require("@traceloop/instrumentation-vertexai");
|
|
10520
|
-
var
|
|
10693
|
+
var traceloop4 = __toESM(require("@traceloop/node-server-sdk"));
|
|
10521
10694
|
var import_weakref = require("weakref");
|
|
10522
10695
|
|
|
10523
10696
|
// src/tracing/direct/http.ts
|
|
@@ -10741,6 +10914,190 @@ function getActiveTraceContext() {
|
|
|
10741
10914
|
};
|
|
10742
10915
|
}
|
|
10743
10916
|
|
|
10917
|
+
// src/tracing/multi-project.ts
|
|
10918
|
+
var import_node_crypto = require("crypto");
|
|
10919
|
+
var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
|
|
10920
|
+
var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
|
|
10921
|
+
var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
|
|
10922
|
+
var EXPORT_SUCCESS = 0;
|
|
10923
|
+
var EXPORT_FAILED = 1;
|
|
10924
|
+
function authHintForKey(writeKey) {
|
|
10925
|
+
if (!writeKey) return void 0;
|
|
10926
|
+
return (0, import_node_crypto.createHash)("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
|
|
10927
|
+
}
|
|
10928
|
+
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.multiProjectState");
|
|
10929
|
+
function getState() {
|
|
10930
|
+
const holder = globalThis;
|
|
10931
|
+
let state = holder[STATE_KEY];
|
|
10932
|
+
if (!state) {
|
|
10933
|
+
state = {
|
|
10934
|
+
foreignClientSeen: false,
|
|
10935
|
+
seenClientHints: /* @__PURE__ */ new Set(),
|
|
10936
|
+
ownerAuthHint: void 0,
|
|
10937
|
+
ownerProjectId: void 0,
|
|
10938
|
+
pipelineClaimed: false,
|
|
10939
|
+
traceloopConfiguredWithoutClaim: false,
|
|
10940
|
+
multiKeyWarned: false,
|
|
10941
|
+
pendingMultiKeyWarning: false
|
|
10942
|
+
};
|
|
10943
|
+
holder[STATE_KEY] = state;
|
|
10944
|
+
}
|
|
10945
|
+
return state;
|
|
10946
|
+
}
|
|
10947
|
+
function emitMultiKeyWarningOnce() {
|
|
10948
|
+
const state = getState();
|
|
10949
|
+
if (state.multiKeyWarned) return;
|
|
10950
|
+
state.multiKeyWarned = true;
|
|
10951
|
+
state.pendingMultiKeyWarning = false;
|
|
10952
|
+
console.warn(
|
|
10953
|
+
"[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."
|
|
10954
|
+
);
|
|
10955
|
+
}
|
|
10956
|
+
function registerClientKey(authHint, tracingEnabled = false) {
|
|
10957
|
+
if (!authHint) return;
|
|
10958
|
+
const state = getState();
|
|
10959
|
+
state.seenClientHints.add(authHint);
|
|
10960
|
+
if (state.seenClientHints.size > 1) {
|
|
10961
|
+
state.foreignClientSeen = true;
|
|
10962
|
+
if (tracingEnabled || state.pipelineClaimed) {
|
|
10963
|
+
emitMultiKeyWarningOnce();
|
|
10964
|
+
} else {
|
|
10965
|
+
state.pendingMultiKeyWarning = true;
|
|
10966
|
+
}
|
|
10967
|
+
}
|
|
10968
|
+
}
|
|
10969
|
+
function markForeignClient() {
|
|
10970
|
+
getState().foreignClientSeen = true;
|
|
10971
|
+
}
|
|
10972
|
+
function foreignClientSeen() {
|
|
10973
|
+
return getState().foreignClientSeen;
|
|
10974
|
+
}
|
|
10975
|
+
function stampSpan(span, projectId, authHint) {
|
|
10976
|
+
try {
|
|
10977
|
+
if (projectId) {
|
|
10978
|
+
span.setAttribute(PROJECT_ID_SPAN_ATTRIBUTE, projectId);
|
|
10979
|
+
}
|
|
10980
|
+
if (authHint && foreignClientSeen()) {
|
|
10981
|
+
span.setAttribute(AUTH_HINT_SPAN_ATTRIBUTE, authHint);
|
|
10982
|
+
}
|
|
10983
|
+
} catch (e) {
|
|
10984
|
+
}
|
|
10985
|
+
}
|
|
10986
|
+
var RaindropContextSpanProcessor = class {
|
|
10987
|
+
onStart(span) {
|
|
10988
|
+
try {
|
|
10989
|
+
const bound = currentRoutingBinding();
|
|
10990
|
+
if (!bound) return;
|
|
10991
|
+
stampSpan(span, bound.projectId, bound.authHint);
|
|
10992
|
+
} catch (e) {
|
|
10993
|
+
}
|
|
10994
|
+
}
|
|
10995
|
+
onEnd() {
|
|
10996
|
+
}
|
|
10997
|
+
async forceFlush() {
|
|
10998
|
+
}
|
|
10999
|
+
async shutdown() {
|
|
11000
|
+
}
|
|
11001
|
+
};
|
|
11002
|
+
var GuardedSpanExporter = class {
|
|
11003
|
+
constructor(inner, ownerAuthHint) {
|
|
11004
|
+
this.droppedTotal = 0;
|
|
11005
|
+
this.inner = inner;
|
|
11006
|
+
this.ownerAuthHint = ownerAuthHint;
|
|
11007
|
+
}
|
|
11008
|
+
partition(spans) {
|
|
11009
|
+
var _a;
|
|
11010
|
+
const allowed = [];
|
|
11011
|
+
let dropped = 0;
|
|
11012
|
+
const requirePositive = foreignClientSeen();
|
|
11013
|
+
for (const span of spans) {
|
|
11014
|
+
const attrs = (_a = span.attributes) != null ? _a : {};
|
|
11015
|
+
const hint = attrs[AUTH_HINT_SPAN_ATTRIBUTE];
|
|
11016
|
+
const keep = requirePositive ? hint === this.ownerAuthHint : hint === void 0 || hint === this.ownerAuthHint;
|
|
11017
|
+
if (keep) {
|
|
11018
|
+
allowed.push(span);
|
|
11019
|
+
} else {
|
|
11020
|
+
dropped += 1;
|
|
11021
|
+
}
|
|
11022
|
+
}
|
|
11023
|
+
return { allowed, dropped };
|
|
11024
|
+
}
|
|
11025
|
+
warnDropped(dropped) {
|
|
11026
|
+
this.droppedTotal += dropped;
|
|
11027
|
+
const total = this.droppedTotal;
|
|
11028
|
+
rateLimitedLog(
|
|
11029
|
+
"js-sdk.multi-project.dropped",
|
|
11030
|
+
() => console.warn(
|
|
11031
|
+
`[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.`
|
|
11032
|
+
)
|
|
11033
|
+
);
|
|
11034
|
+
}
|
|
11035
|
+
export(spans, resultCallback) {
|
|
11036
|
+
let allowed;
|
|
11037
|
+
let dropped;
|
|
11038
|
+
try {
|
|
11039
|
+
({ allowed, dropped } = this.partition(spans));
|
|
11040
|
+
} catch (e) {
|
|
11041
|
+
if (foreignClientSeen()) {
|
|
11042
|
+
this.warnDropped(spans.length);
|
|
11043
|
+
resultCallback({ code: EXPORT_FAILED });
|
|
11044
|
+
return;
|
|
11045
|
+
}
|
|
11046
|
+
this.inner.export(spans, resultCallback);
|
|
11047
|
+
return;
|
|
11048
|
+
}
|
|
11049
|
+
if (dropped) {
|
|
11050
|
+
this.warnDropped(dropped);
|
|
11051
|
+
}
|
|
11052
|
+
if (allowed.length === 0) {
|
|
11053
|
+
resultCallback({ code: EXPORT_SUCCESS });
|
|
11054
|
+
return;
|
|
11055
|
+
}
|
|
11056
|
+
this.inner.export(allowed, resultCallback);
|
|
11057
|
+
}
|
|
11058
|
+
shutdown() {
|
|
11059
|
+
return this.inner.shutdown();
|
|
11060
|
+
}
|
|
11061
|
+
forceFlush() {
|
|
11062
|
+
return this.inner.forceFlush ? this.inner.forceFlush() : Promise.resolve();
|
|
11063
|
+
}
|
|
11064
|
+
};
|
|
11065
|
+
function buildGuardedExporter(baseUrl, headers, ownerAuthHint) {
|
|
11066
|
+
const inner = new import_exporter_trace_otlp_proto.OTLPTraceExporter({
|
|
11067
|
+
url: `${baseUrl}/v1/traces`,
|
|
11068
|
+
headers
|
|
11069
|
+
});
|
|
11070
|
+
return new GuardedSpanExporter(inner, ownerAuthHint);
|
|
11071
|
+
}
|
|
11072
|
+
function pipelineOwnerHint() {
|
|
11073
|
+
return getState().ownerAuthHint;
|
|
11074
|
+
}
|
|
11075
|
+
function claimPipeline(authHint, projectId) {
|
|
11076
|
+
const state = getState();
|
|
11077
|
+
if (state.pipelineClaimed) {
|
|
11078
|
+
return false;
|
|
11079
|
+
}
|
|
11080
|
+
state.pipelineClaimed = true;
|
|
11081
|
+
state.ownerAuthHint = authHint;
|
|
11082
|
+
state.ownerProjectId = projectId;
|
|
11083
|
+
if (state.foreignClientSeen && state.pendingMultiKeyWarning) {
|
|
11084
|
+
emitMultiKeyWarningOnce();
|
|
11085
|
+
}
|
|
11086
|
+
return true;
|
|
11087
|
+
}
|
|
11088
|
+
function releasePipelineClaim() {
|
|
11089
|
+
const state = getState();
|
|
11090
|
+
state.pipelineClaimed = false;
|
|
11091
|
+
state.ownerAuthHint = void 0;
|
|
11092
|
+
state.ownerProjectId = void 0;
|
|
11093
|
+
}
|
|
11094
|
+
function markTraceloopConfiguredWithoutClaim() {
|
|
11095
|
+
getState().traceloopConfiguredWithoutClaim = true;
|
|
11096
|
+
}
|
|
11097
|
+
function traceloopConfiguredWithoutClaim() {
|
|
11098
|
+
return getState().traceloopConfiguredWithoutClaim;
|
|
11099
|
+
}
|
|
11100
|
+
|
|
10744
11101
|
// src/tracing/direct/shipper.ts
|
|
10745
11102
|
function serializeAssociationValue(value) {
|
|
10746
11103
|
return stringifyBounded(value);
|
|
@@ -10800,7 +11157,11 @@ var DirectTraceShipper = class {
|
|
|
10800
11157
|
attrString2("traceloop.entity.input", params.input),
|
|
10801
11158
|
attrString2("traceloop.entity.output", params.output),
|
|
10802
11159
|
// Duration tracking
|
|
10803
|
-
attrInt2("traceloop.entity.duration_ms", params.durationMs)
|
|
11160
|
+
attrInt2("traceloop.entity.duration_ms", params.durationMs),
|
|
11161
|
+
// Per-span project routing: the ingest boundary routes on this attribute
|
|
11162
|
+
// (org-validated) and falls back to the request's project header. Direct
|
|
11163
|
+
// spans ship on this instance's own key, so no cross-key auth hint.
|
|
11164
|
+
attrString2(PROJECT_ID_SPAN_ATTRIBUTE, this.projectId)
|
|
10804
11165
|
];
|
|
10805
11166
|
for (const [key, value] of Object.entries(params.properties)) {
|
|
10806
11167
|
if (value === void 0) {
|
|
@@ -11098,12 +11459,27 @@ var DirectToolSpan = class {
|
|
|
11098
11459
|
}
|
|
11099
11460
|
};
|
|
11100
11461
|
var LiveInteraction = class {
|
|
11101
|
-
constructor(context5, traceId, analytics, directShipper) {
|
|
11462
|
+
constructor(context5, traceId, analytics, directShipper, routing) {
|
|
11102
11463
|
this.context = context5;
|
|
11103
11464
|
this.analytics = analytics;
|
|
11104
11465
|
this.tracer = import_api2.trace.getTracer("traceloop.tracer");
|
|
11105
11466
|
this.traceId = traceId;
|
|
11106
11467
|
this.directShipper = directShipper;
|
|
11468
|
+
this.routing = routing;
|
|
11469
|
+
}
|
|
11470
|
+
/**
|
|
11471
|
+
* Record the routing binding this interaction pushed onto the context stack
|
|
11472
|
+
* (via {@link bindRoutingContext} in `begin()`) so {@link finish} removes
|
|
11473
|
+
* exactly its own entry — non-LIFO safe, and leaving any still-open sibling's
|
|
11474
|
+
* binding intact.
|
|
11475
|
+
*/
|
|
11476
|
+
setBoundContext(bound) {
|
|
11477
|
+
this.boundContext = bound;
|
|
11478
|
+
}
|
|
11479
|
+
/** Stamp a manually-created OTel span with this interaction's routing. */
|
|
11480
|
+
stampRouting(span) {
|
|
11481
|
+
if (!this.routing) return;
|
|
11482
|
+
stampSpan(span, this.routing.projectId, this.routing.authHint);
|
|
11107
11483
|
}
|
|
11108
11484
|
ensureTraceId(preferred) {
|
|
11109
11485
|
if (preferred) {
|
|
@@ -11172,8 +11548,9 @@ var LiveInteraction = class {
|
|
|
11172
11548
|
import_api2.context.active(),
|
|
11173
11549
|
import_api2.trace.wrapSpanContext(spanContext)
|
|
11174
11550
|
);
|
|
11551
|
+
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
11175
11552
|
try {
|
|
11176
|
-
const result = await import_api2.context.with(wrappedContext,
|
|
11553
|
+
const result = await import_api2.context.with(wrappedContext, invoke);
|
|
11177
11554
|
const endTimeMs = Date.now();
|
|
11178
11555
|
this.directShipper.sendSpan({
|
|
11179
11556
|
name: taskName,
|
|
@@ -11208,11 +11585,17 @@ var LiveInteraction = class {
|
|
|
11208
11585
|
}
|
|
11209
11586
|
}
|
|
11210
11587
|
const wrappedFn = (...fnArgs) => {
|
|
11211
|
-
|
|
11212
|
-
const activeTraceId =
|
|
11588
|
+
const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
|
|
11589
|
+
const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
|
|
11213
11590
|
if (activeTraceId) {
|
|
11214
11591
|
this.traceId = activeTraceId;
|
|
11215
11592
|
}
|
|
11593
|
+
if (activeSpan) {
|
|
11594
|
+
this.stampRouting(activeSpan);
|
|
11595
|
+
}
|
|
11596
|
+
if (this.routing) {
|
|
11597
|
+
return withRoutingContext(this.routing, () => fn.apply(thisArg, fnArgs));
|
|
11598
|
+
}
|
|
11216
11599
|
return fn.apply(thisArg, fnArgs);
|
|
11217
11600
|
};
|
|
11218
11601
|
return traceloop.withTask(
|
|
@@ -11224,7 +11607,6 @@ var LiveInteraction = class {
|
|
|
11224
11607
|
suppressTracing: params.suppressTracing
|
|
11225
11608
|
},
|
|
11226
11609
|
wrappedFn,
|
|
11227
|
-
void 0,
|
|
11228
11610
|
...args
|
|
11229
11611
|
);
|
|
11230
11612
|
}
|
|
@@ -11261,10 +11643,11 @@ var LiveInteraction = class {
|
|
|
11261
11643
|
import_api2.context.active(),
|
|
11262
11644
|
import_api2.trace.wrapSpanContext(spanContext)
|
|
11263
11645
|
);
|
|
11646
|
+
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
11264
11647
|
let result;
|
|
11265
11648
|
let error;
|
|
11266
11649
|
try {
|
|
11267
|
-
result = await import_api2.context.with(wrappedContext,
|
|
11650
|
+
result = await import_api2.context.with(wrappedContext, invoke);
|
|
11268
11651
|
} catch (err) {
|
|
11269
11652
|
error = err instanceof Error ? err.message : String(err);
|
|
11270
11653
|
const endTimeMs2 = Date.now();
|
|
@@ -11332,6 +11715,9 @@ var LiveInteraction = class {
|
|
|
11332
11715
|
const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
|
|
11333
11716
|
const ctx = activeSpan == null ? void 0 : activeSpan.spanContext();
|
|
11334
11717
|
const liveSpanId = ctx && (0, import_api2.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
|
|
11718
|
+
if (activeSpan) {
|
|
11719
|
+
this.stampRouting(activeSpan);
|
|
11720
|
+
}
|
|
11335
11721
|
emitLive({
|
|
11336
11722
|
type: "tool_start",
|
|
11337
11723
|
spanId: liveSpanId,
|
|
@@ -11340,7 +11726,7 @@ var LiveInteraction = class {
|
|
|
11340
11726
|
metadata: params.inputParameters ? { args: params.inputParameters } : void 0
|
|
11341
11727
|
});
|
|
11342
11728
|
try {
|
|
11343
|
-
const r = await fn.apply(thisArg, wrappedArgs);
|
|
11729
|
+
const r = this.routing ? await withRoutingContext(this.routing, () => fn.apply(thisArg, wrappedArgs)) : await fn.apply(thisArg, wrappedArgs);
|
|
11344
11730
|
emitLive({
|
|
11345
11731
|
type: "tool_result",
|
|
11346
11732
|
spanId: liveSpanId,
|
|
@@ -11376,7 +11762,6 @@ var LiveInteraction = class {
|
|
|
11376
11762
|
suppressTracing: params.suppressTracing
|
|
11377
11763
|
},
|
|
11378
11764
|
wrapped,
|
|
11379
|
-
void 0,
|
|
11380
11765
|
...args
|
|
11381
11766
|
);
|
|
11382
11767
|
}
|
|
@@ -11387,6 +11772,7 @@ var LiveInteraction = class {
|
|
|
11387
11772
|
setAssociationProperties(span, contextProperties);
|
|
11388
11773
|
span.setAttribute("traceloop.span.kind", "task");
|
|
11389
11774
|
setAssociationProperties(span, properties);
|
|
11775
|
+
this.stampRouting(span);
|
|
11390
11776
|
return span;
|
|
11391
11777
|
}
|
|
11392
11778
|
startToolSpan(params) {
|
|
@@ -11428,6 +11814,7 @@ var LiveInteraction = class {
|
|
|
11428
11814
|
setAssociationProperties(span, contextProperties);
|
|
11429
11815
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
11430
11816
|
setAssociationProperties(span, properties);
|
|
11817
|
+
this.stampRouting(span);
|
|
11431
11818
|
if (inputParameters !== void 0) {
|
|
11432
11819
|
span.setAttribute("traceloop.entity.input", serializeSpanValue(inputParameters));
|
|
11433
11820
|
}
|
|
@@ -11530,6 +11917,8 @@ var LiveInteraction = class {
|
|
|
11530
11917
|
}
|
|
11531
11918
|
async finish(resultEvent) {
|
|
11532
11919
|
var _a, _b, _c, _d;
|
|
11920
|
+
unbindRoutingContext(this.boundContext);
|
|
11921
|
+
this.boundContext = void 0;
|
|
11533
11922
|
if (!this.traceId) {
|
|
11534
11923
|
this.resolveLiveTraceId();
|
|
11535
11924
|
}
|
|
@@ -11617,6 +12006,7 @@ var LiveInteraction = class {
|
|
|
11617
12006
|
setAssociationProperties(span, contextProperties);
|
|
11618
12007
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
11619
12008
|
setAssociationProperties(span, properties);
|
|
12009
|
+
this.stampRouting(span);
|
|
11620
12010
|
if (input !== void 0) {
|
|
11621
12011
|
span.setAttribute("traceloop.entity.input", stringifyBounded(input));
|
|
11622
12012
|
}
|
|
@@ -11662,10 +12052,16 @@ var LiveInteraction = class {
|
|
|
11662
12052
|
var import_api3 = require("@opentelemetry/api");
|
|
11663
12053
|
var traceloop2 = __toESM(require("@traceloop/node-server-sdk"));
|
|
11664
12054
|
var LiveTracer = class {
|
|
11665
|
-
constructor(globalProperties, directShipper) {
|
|
12055
|
+
constructor(globalProperties, directShipper, routing) {
|
|
11666
12056
|
this.tracer = import_api3.trace.getTracer("traceloop.tracer");
|
|
11667
12057
|
this.globalProperties = globalProperties || {};
|
|
11668
12058
|
this.directShipper = directShipper;
|
|
12059
|
+
this.routing = routing;
|
|
12060
|
+
}
|
|
12061
|
+
/** Stamp a manually-created OTel span with this tracer's client routing. */
|
|
12062
|
+
stampRouting(span) {
|
|
12063
|
+
if (!this.routing) return;
|
|
12064
|
+
stampSpan(span, this.routing.projectId, this.routing.authHint);
|
|
11669
12065
|
}
|
|
11670
12066
|
emitLiveEvent(event) {
|
|
11671
12067
|
var _a, _b;
|
|
@@ -11688,6 +12084,16 @@ var LiveTracer = class {
|
|
|
11688
12084
|
...params.properties || {}
|
|
11689
12085
|
};
|
|
11690
12086
|
const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
|
|
12087
|
+
const wrappedFn = (...fnArgs) => {
|
|
12088
|
+
const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
|
|
12089
|
+
if (activeSpan) {
|
|
12090
|
+
this.stampRouting(activeSpan);
|
|
12091
|
+
}
|
|
12092
|
+
if (this.routing) {
|
|
12093
|
+
return withRoutingContext(this.routing, () => fn.apply(thisArg, fnArgs));
|
|
12094
|
+
}
|
|
12095
|
+
return fn.apply(thisArg, fnArgs);
|
|
12096
|
+
};
|
|
11691
12097
|
return traceloop2.withTask(
|
|
11692
12098
|
{
|
|
11693
12099
|
name: taskName,
|
|
@@ -11696,8 +12102,7 @@ var LiveTracer = class {
|
|
|
11696
12102
|
traceContent: params.traceContent,
|
|
11697
12103
|
suppressTracing: params.suppressTracing
|
|
11698
12104
|
},
|
|
11699
|
-
|
|
11700
|
-
thisArg,
|
|
12105
|
+
wrappedFn,
|
|
11701
12106
|
...args
|
|
11702
12107
|
);
|
|
11703
12108
|
}
|
|
@@ -11746,6 +12151,7 @@ var LiveTracer = class {
|
|
|
11746
12151
|
const span = this.tracer.startSpan(name, {
|
|
11747
12152
|
startTime: startTimeMs
|
|
11748
12153
|
});
|
|
12154
|
+
this.stampRouting(span);
|
|
11749
12155
|
Object.entries(this.globalProperties).forEach(([key, value]) => {
|
|
11750
12156
|
span.setAttribute("traceloop.association.properties." + key, String(value));
|
|
11751
12157
|
});
|
|
@@ -11790,6 +12196,59 @@ var LiveTracer = class {
|
|
|
11790
12196
|
}
|
|
11791
12197
|
};
|
|
11792
12198
|
|
|
12199
|
+
// src/tracing/exit-flush.ts
|
|
12200
|
+
var traceloop3 = __toESM(require("@traceloop/node-server-sdk"));
|
|
12201
|
+
var STATE_KEY2 = /* @__PURE__ */ Symbol.for("raindrop.tracing.exitFlushState");
|
|
12202
|
+
function getState2() {
|
|
12203
|
+
const holder = globalThis;
|
|
12204
|
+
let state = holder[STATE_KEY2];
|
|
12205
|
+
if (!state) {
|
|
12206
|
+
state = {
|
|
12207
|
+
clientFlushers: /* @__PURE__ */ new Set(),
|
|
12208
|
+
pipelineFlushNeeded: false,
|
|
12209
|
+
handlerRegistered: false
|
|
12210
|
+
};
|
|
12211
|
+
holder[STATE_KEY2] = state;
|
|
12212
|
+
}
|
|
12213
|
+
return state;
|
|
12214
|
+
}
|
|
12215
|
+
function ensureExitHandler(state) {
|
|
12216
|
+
if (state.handlerRegistered) return;
|
|
12217
|
+
if (typeof process === "undefined" || typeof process.once !== "function") return;
|
|
12218
|
+
state.handlerRegistered = true;
|
|
12219
|
+
process.once("beforeExit", () => {
|
|
12220
|
+
void flushAll();
|
|
12221
|
+
});
|
|
12222
|
+
}
|
|
12223
|
+
function registerClientFlusher(flush) {
|
|
12224
|
+
const state = getState2();
|
|
12225
|
+
state.clientFlushers.add(flush);
|
|
12226
|
+
ensureExitHandler(state);
|
|
12227
|
+
return () => {
|
|
12228
|
+
state.clientFlushers.delete(flush);
|
|
12229
|
+
};
|
|
12230
|
+
}
|
|
12231
|
+
function markPipelineForExitFlush() {
|
|
12232
|
+
const state = getState2();
|
|
12233
|
+
state.pipelineFlushNeeded = true;
|
|
12234
|
+
ensureExitHandler(state);
|
|
12235
|
+
}
|
|
12236
|
+
async function flushAll() {
|
|
12237
|
+
const state = getState2();
|
|
12238
|
+
const tasks = [];
|
|
12239
|
+
for (const flush of state.clientFlushers) {
|
|
12240
|
+
tasks.push(Promise.resolve().then(flush).catch(() => {
|
|
12241
|
+
}));
|
|
12242
|
+
}
|
|
12243
|
+
if (state.pipelineFlushNeeded) {
|
|
12244
|
+
tasks.push(
|
|
12245
|
+
Promise.resolve().then(() => traceloop3.forceFlush()).catch(() => {
|
|
12246
|
+
})
|
|
12247
|
+
);
|
|
12248
|
+
}
|
|
12249
|
+
await Promise.all(tasks);
|
|
12250
|
+
}
|
|
12251
|
+
|
|
11793
12252
|
// src/tracing/tracer-core.ts
|
|
11794
12253
|
if (localDebuggerEnabled()) {
|
|
11795
12254
|
if (!process.env.OTEL_EXPORTER_OTLP_PROTOCOL) {
|
|
@@ -11898,6 +12357,29 @@ function resolveLocalDebuggerExporterBaseUrl(baseUrlOpt) {
|
|
|
11898
12357
|
function createLocalDebuggerOtlpExporter(config) {
|
|
11899
12358
|
return new import_exporter_trace_otlp_http.OTLPTraceExporter(config);
|
|
11900
12359
|
}
|
|
12360
|
+
function parseTraceloopHeaders(value) {
|
|
12361
|
+
const headers = {};
|
|
12362
|
+
for (const entry of value.split(",")) {
|
|
12363
|
+
const keyPairPart = entry.split(";")[0];
|
|
12364
|
+
const sep = keyPairPart.indexOf("=");
|
|
12365
|
+
if (sep <= 0) continue;
|
|
12366
|
+
try {
|
|
12367
|
+
const key = decodeURIComponent(keyPairPart.slice(0, sep).trim());
|
|
12368
|
+
const val = decodeURIComponent(keyPairPart.slice(sep + 1).trim());
|
|
12369
|
+
if (key.length > 0 && val.length > 0) headers[key] = val;
|
|
12370
|
+
} catch (e) {
|
|
12371
|
+
}
|
|
12372
|
+
}
|
|
12373
|
+
return headers;
|
|
12374
|
+
}
|
|
12375
|
+
function traceloopDefaultHeaders(writeKey) {
|
|
12376
|
+
const env = process.env.TRACELOOP_HEADERS;
|
|
12377
|
+
if (env) {
|
|
12378
|
+
const parsed = parseTraceloopHeaders(env);
|
|
12379
|
+
if (Object.keys(parsed).length > 0) return parsed;
|
|
12380
|
+
}
|
|
12381
|
+
return { Authorization: `Bearer ${writeKey}` };
|
|
12382
|
+
}
|
|
11901
12383
|
function createLocalDebuggerSpanProcessor(options) {
|
|
11902
12384
|
const localDebuggerUrl = resolveLocalDebuggerExporterBaseUrl(options.localDebuggerUrlOpt);
|
|
11903
12385
|
if (!localDebuggerUrl) {
|
|
@@ -11908,7 +12390,7 @@ function createLocalDebuggerSpanProcessor(options) {
|
|
|
11908
12390
|
headers: {}
|
|
11909
12391
|
});
|
|
11910
12392
|
try {
|
|
11911
|
-
return
|
|
12393
|
+
return traceloop4.createSpanProcessor({
|
|
11912
12394
|
apiKey: options.writeKey,
|
|
11913
12395
|
baseUrl: localDebuggerUrl,
|
|
11914
12396
|
disableBatch: options.disableBatching,
|
|
@@ -11924,12 +12406,6 @@ function createLocalDebuggerSpanProcessor(options) {
|
|
|
11924
12406
|
return void 0;
|
|
11925
12407
|
}
|
|
11926
12408
|
}
|
|
11927
|
-
function mergeWithBestEffortLocalDebuggerProcessor(processor, localDebuggerProcessor) {
|
|
11928
|
-
if (!localDebuggerProcessor) {
|
|
11929
|
-
return processor;
|
|
11930
|
-
}
|
|
11931
|
-
return new CompositeSpanProcessor(processor ? [processor] : [], [localDebuggerProcessor]);
|
|
11932
|
-
}
|
|
11933
12409
|
var warnedSpanNormalizeFailure = false;
|
|
11934
12410
|
var INVALID_OTEL_SPAN_ID = "0000000000000000";
|
|
11935
12411
|
function normalizeSpanForV1Exporter(span) {
|
|
@@ -12229,13 +12705,12 @@ function createManualInstrumentations(instrumentModules) {
|
|
|
12229
12705
|
}
|
|
12230
12706
|
return instrumentations;
|
|
12231
12707
|
}
|
|
12232
|
-
var activeInteractions = new import_weakref.WeakValueMap();
|
|
12233
|
-
var activeInteractionsByEventId = new import_weakref.WeakValueMap();
|
|
12234
12708
|
function getCurrentTraceId() {
|
|
12235
12709
|
var _a;
|
|
12236
12710
|
return (_a = import_api4.trace.getSpan(import_api4.context.active())) == null ? void 0 : _a.spanContext().traceId;
|
|
12237
12711
|
}
|
|
12238
12712
|
var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
12713
|
+
var _a;
|
|
12239
12714
|
process.env.TRACELOOP_TELEMETRY = "false";
|
|
12240
12715
|
const {
|
|
12241
12716
|
logLevel,
|
|
@@ -12250,12 +12725,15 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12250
12725
|
...otherOptions
|
|
12251
12726
|
} = options;
|
|
12252
12727
|
const cloudEnabledResolved = cloudEnabled != null ? cloudEnabled : true;
|
|
12728
|
+
const authHint = authHintForKey(writeKey);
|
|
12729
|
+
const clientTracingExports = !useExternalOtel && cloudEnabledResolved && tracingEnabled !== false;
|
|
12730
|
+
registerClientKey(authHint, clientTracingExports);
|
|
12253
12731
|
const withProjectIdHeaders = (existing) => {
|
|
12254
12732
|
if (!projectId) {
|
|
12255
12733
|
return existing;
|
|
12256
12734
|
}
|
|
12257
12735
|
return {
|
|
12258
|
-
|
|
12736
|
+
...traceloopDefaultHeaders(writeKey),
|
|
12259
12737
|
...existing != null ? existing : {},
|
|
12260
12738
|
...projectIdHeaders(projectId)
|
|
12261
12739
|
};
|
|
@@ -12277,9 +12755,12 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12277
12755
|
projectId
|
|
12278
12756
|
}) : void 0;
|
|
12279
12757
|
let traceloopInitialized = false;
|
|
12758
|
+
let claimedPipeline = false;
|
|
12759
|
+
const activeInteractions = new import_weakref.WeakValueMap();
|
|
12760
|
+
const activeInteractionsByEventId = new import_weakref.WeakValueMap();
|
|
12280
12761
|
try {
|
|
12281
12762
|
if (useExternalOtel) {
|
|
12282
|
-
|
|
12763
|
+
traceloop4.initialize({
|
|
12283
12764
|
baseUrl: apiUrl,
|
|
12284
12765
|
apiKey: writeKey,
|
|
12285
12766
|
logLevel,
|
|
@@ -12291,6 +12772,7 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12291
12772
|
// DO NOT create NodeSDK - customer has their own
|
|
12292
12773
|
});
|
|
12293
12774
|
traceloopInitialized = true;
|
|
12775
|
+
markTraceloopConfiguredWithoutClaim();
|
|
12294
12776
|
if (isDebug) {
|
|
12295
12777
|
console.log(
|
|
12296
12778
|
"[raindrop] External OTEL mode active. Add raindrop.createSpanProcessor() to your NodeSDK's spanProcessors. Register instrumentations (AnthropicInstrumentation, etc.) on your NodeSDK."
|
|
@@ -12307,12 +12789,12 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12307
12789
|
const localDebuggerProcessor = createLocalDebuggerSpanProcessor({
|
|
12308
12790
|
writeKey,
|
|
12309
12791
|
disableBatching,
|
|
12310
|
-
allowedInstrumentationLibraries:
|
|
12792
|
+
allowedInstrumentationLibraries: traceloop4.ALL_INSTRUMENTATION_LIBRARIES,
|
|
12311
12793
|
localDebuggerUrlOpt: localDebuggerUrl
|
|
12312
12794
|
});
|
|
12313
12795
|
if (!cloudEnabledResolved) {
|
|
12314
12796
|
if (localDebuggerProcessor) {
|
|
12315
|
-
|
|
12797
|
+
traceloop4.initialize({
|
|
12316
12798
|
baseUrl: apiUrl,
|
|
12317
12799
|
apiKey: writeKey,
|
|
12318
12800
|
...otherOptions,
|
|
@@ -12323,8 +12805,9 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12323
12805
|
processor: localDebuggerProcessor
|
|
12324
12806
|
});
|
|
12325
12807
|
traceloopInitialized = true;
|
|
12808
|
+
markTraceloopConfiguredWithoutClaim();
|
|
12326
12809
|
} else {
|
|
12327
|
-
|
|
12810
|
+
traceloop4.initialize({
|
|
12328
12811
|
baseUrl: apiUrl,
|
|
12329
12812
|
apiKey: writeKey,
|
|
12330
12813
|
logLevel,
|
|
@@ -12332,33 +12815,91 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12332
12815
|
tracingEnabled: false
|
|
12333
12816
|
});
|
|
12334
12817
|
traceloopInitialized = true;
|
|
12818
|
+
markTraceloopConfiguredWithoutClaim();
|
|
12335
12819
|
}
|
|
12820
|
+
} else if (tracingEnabled === false) {
|
|
12821
|
+
traceloopInitialized = false;
|
|
12336
12822
|
} else {
|
|
12337
|
-
const
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
)
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
})
|
|
12353
|
-
|
|
12823
|
+
const claimed = claimPipeline(authHint, projectId);
|
|
12824
|
+
claimedPipeline = claimed;
|
|
12825
|
+
const ownerHint = pipelineOwnerHint();
|
|
12826
|
+
if (!claimed && authHint !== ownerHint) {
|
|
12827
|
+
markForeignClient();
|
|
12828
|
+
console.warn(
|
|
12829
|
+
"[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."
|
|
12830
|
+
);
|
|
12831
|
+
}
|
|
12832
|
+
if (claimed && traceloopConfiguredWithoutClaim()) {
|
|
12833
|
+
releasePipelineClaim();
|
|
12834
|
+
claimedPipeline = false;
|
|
12835
|
+
console.warn(
|
|
12836
|
+
"[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."
|
|
12837
|
+
);
|
|
12838
|
+
} else if (claimed) {
|
|
12839
|
+
const exporterHeaders = (_a = withProjectIdHeaders(otherOptions.headers)) != null ? _a : traceloopDefaultHeaders(writeKey);
|
|
12840
|
+
let guardedExporter;
|
|
12841
|
+
try {
|
|
12842
|
+
const callerExporter = otherOptions.exporter;
|
|
12843
|
+
guardedExporter = callerExporter ? new GuardedSpanExporter(callerExporter, ownerHint) : buildGuardedExporter(apiUrl, exporterHeaders, ownerHint);
|
|
12844
|
+
} catch (guardError) {
|
|
12845
|
+
releasePipelineClaim();
|
|
12846
|
+
claimedPipeline = false;
|
|
12847
|
+
console.warn(
|
|
12848
|
+
`[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.`
|
|
12849
|
+
);
|
|
12850
|
+
}
|
|
12851
|
+
if (guardedExporter) {
|
|
12852
|
+
const contextProcessor = new RaindropContextSpanProcessor();
|
|
12853
|
+
const callerProcessor = otherOptions.processor;
|
|
12854
|
+
const processor = new CompositeSpanProcessor(
|
|
12855
|
+
callerProcessor ? [contextProcessor, callerProcessor] : [contextProcessor],
|
|
12856
|
+
localDebuggerProcessor ? [localDebuggerProcessor] : []
|
|
12857
|
+
);
|
|
12858
|
+
try {
|
|
12859
|
+
traceloop4.initialize({
|
|
12860
|
+
baseUrl: apiUrl,
|
|
12861
|
+
apiKey: writeKey,
|
|
12862
|
+
...otherOptions,
|
|
12863
|
+
logLevel,
|
|
12864
|
+
silenceInitializationMessage: true,
|
|
12865
|
+
// This branch only runs when tracing is enabled (the disabled
|
|
12866
|
+
// case is handled above), so tracing is always on here.
|
|
12867
|
+
tracingEnabled: true,
|
|
12868
|
+
disableBatch: disableBatching,
|
|
12869
|
+
processor,
|
|
12870
|
+
exporter: guardedExporter
|
|
12871
|
+
});
|
|
12872
|
+
traceloopInitialized = true;
|
|
12873
|
+
} catch (initError) {
|
|
12874
|
+
releasePipelineClaim();
|
|
12875
|
+
claimedPipeline = false;
|
|
12876
|
+
throw initError;
|
|
12877
|
+
}
|
|
12878
|
+
}
|
|
12879
|
+
} else {
|
|
12880
|
+
traceloopInitialized = true;
|
|
12881
|
+
}
|
|
12354
12882
|
}
|
|
12355
12883
|
}
|
|
12356
12884
|
} catch (error) {
|
|
12885
|
+
if (claimedPipeline && !traceloopInitialized) {
|
|
12886
|
+
releasePipelineClaim();
|
|
12887
|
+
claimedPipeline = false;
|
|
12888
|
+
}
|
|
12357
12889
|
console.warn(
|
|
12358
12890
|
"[raindrop] Failed to initialize traceloop. Spans will not be sent.",
|
|
12359
12891
|
error instanceof Error ? error.message : error
|
|
12360
12892
|
);
|
|
12361
12893
|
}
|
|
12894
|
+
if (traceloopInitialized) {
|
|
12895
|
+
markPipelineForExitFlush();
|
|
12896
|
+
}
|
|
12897
|
+
const deregisterExitFlusher = directShipper ? registerClientFlusher(async () => {
|
|
12898
|
+
try {
|
|
12899
|
+
await directShipper.flush();
|
|
12900
|
+
} catch (e) {
|
|
12901
|
+
}
|
|
12902
|
+
}) : void 0;
|
|
12362
12903
|
return {
|
|
12363
12904
|
/**
|
|
12364
12905
|
* Returns instrumentation instances for your NodeSDK.
|
|
@@ -12446,7 +12987,7 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12446
12987
|
);
|
|
12447
12988
|
}
|
|
12448
12989
|
const headers = withProjectIdHeaders(processorOptions == null ? void 0 : processorOptions.headers);
|
|
12449
|
-
const productionProcessor =
|
|
12990
|
+
const productionProcessor = traceloop4.createSpanProcessor({
|
|
12450
12991
|
baseUrl: apiUrl,
|
|
12451
12992
|
apiKey: writeKey,
|
|
12452
12993
|
disableBatch: disableBatching,
|
|
@@ -12459,12 +13000,16 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12459
13000
|
allowedInstrumentationLibraries: processorOptions == null ? void 0 : processorOptions.allowedInstrumentationLibraries,
|
|
12460
13001
|
localDebuggerUrlOpt: localDebuggerUrl
|
|
12461
13002
|
});
|
|
13003
|
+
const contextProcessor = new RaindropContextSpanProcessor();
|
|
12462
13004
|
return withV2SpanCompat(
|
|
12463
|
-
|
|
13005
|
+
new CompositeSpanProcessor(
|
|
13006
|
+
[contextProcessor, productionProcessor],
|
|
13007
|
+
localDebuggerProcessor ? [localDebuggerProcessor] : []
|
|
13008
|
+
)
|
|
12464
13009
|
);
|
|
12465
13010
|
},
|
|
12466
13011
|
begin(traceContext) {
|
|
12467
|
-
var
|
|
13012
|
+
var _a2;
|
|
12468
13013
|
if (!traceContext.eventId) {
|
|
12469
13014
|
traceContext.eventId = crypto.randomUUID();
|
|
12470
13015
|
}
|
|
@@ -12473,19 +13018,27 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12473
13018
|
traceContext,
|
|
12474
13019
|
traceId,
|
|
12475
13020
|
analytics,
|
|
12476
|
-
directShipper
|
|
13021
|
+
directShipper,
|
|
13022
|
+
{ projectId, authHint }
|
|
12477
13023
|
);
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
...
|
|
13024
|
+
const bound = bindRoutingContext({ projectId, authHint }, interaction);
|
|
13025
|
+
interaction.setBoundContext(bound);
|
|
13026
|
+
try {
|
|
13027
|
+
analytics._trackAiPartial({
|
|
13028
|
+
...traceContext,
|
|
13029
|
+
properties: {
|
|
13030
|
+
...(_a2 = traceContext.properties) != null ? _a2 : {},
|
|
13031
|
+
...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
|
|
13032
|
+
}
|
|
13033
|
+
});
|
|
13034
|
+
if (interaction.getTraceId()) {
|
|
13035
|
+
activeInteractions.set(interaction.getTraceId(), interaction);
|
|
12483
13036
|
}
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
13037
|
+
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
13038
|
+
} catch (error) {
|
|
13039
|
+
unbindRoutingContext(bound);
|
|
13040
|
+
throw error;
|
|
12487
13041
|
}
|
|
12488
|
-
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
12489
13042
|
return interaction;
|
|
12490
13043
|
},
|
|
12491
13044
|
getActiveInteraction(eventId) {
|
|
@@ -12500,12 +13053,15 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12500
13053
|
return interactionByTraceId;
|
|
12501
13054
|
}
|
|
12502
13055
|
}
|
|
12503
|
-
const interaction = new LiveInteraction({ eventId }, traceId, analytics, directShipper
|
|
13056
|
+
const interaction = new LiveInteraction({ eventId }, traceId, analytics, directShipper, {
|
|
13057
|
+
projectId,
|
|
13058
|
+
authHint
|
|
13059
|
+
});
|
|
12504
13060
|
activeInteractionsByEventId.set(eventId, interaction);
|
|
12505
13061
|
return interaction;
|
|
12506
13062
|
},
|
|
12507
13063
|
tracer(globalProperties) {
|
|
12508
|
-
return new LiveTracer(globalProperties, directShipper);
|
|
13064
|
+
return new LiveTracer(globalProperties, directShipper, { projectId, authHint });
|
|
12509
13065
|
},
|
|
12510
13066
|
/**
|
|
12511
13067
|
* Best-effort drain of in-flight OTel spans and direct shipper batches.
|
|
@@ -12520,18 +13076,19 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
12520
13076
|
}
|
|
12521
13077
|
if (traceloopInitialized) {
|
|
12522
13078
|
try {
|
|
12523
|
-
await
|
|
13079
|
+
await traceloop4.forceFlush();
|
|
12524
13080
|
} catch (e) {
|
|
12525
13081
|
}
|
|
12526
13082
|
}
|
|
12527
13083
|
},
|
|
12528
13084
|
async close() {
|
|
13085
|
+
deregisterExitFlusher == null ? void 0 : deregisterExitFlusher();
|
|
12529
13086
|
activeInteractions.clear();
|
|
12530
13087
|
activeInteractionsByEventId.clear();
|
|
12531
13088
|
await (directShipper == null ? void 0 : directShipper.shutdown());
|
|
12532
13089
|
if (traceloopInitialized) {
|
|
12533
13090
|
try {
|
|
12534
|
-
await
|
|
13091
|
+
await traceloop4.forceFlush();
|
|
12535
13092
|
} catch (e) {
|
|
12536
13093
|
}
|
|
12537
13094
|
}
|
|
@@ -12743,6 +13300,7 @@ var Raindrop = class {
|
|
|
12743
13300
|
setDefaultMaxTextFieldChars(config.maxTextFieldChars);
|
|
12744
13301
|
this.maxTextFieldChars = resolveMaxTextFieldChars(config.maxTextFieldChars);
|
|
12745
13302
|
this.writeKey = (_a = config.writeKey) != null ? _a : "";
|
|
13303
|
+
this.authHint = authHintForKey(this.writeKey);
|
|
12746
13304
|
this.localDebuggerUrlOpt = config.localWorkshopUrl === false ? null : config.localWorkshopUrl;
|
|
12747
13305
|
this.awaitSpanFlushOpt = config.awaitSpanFlush;
|
|
12748
13306
|
this.apiUrl = (_b = this.formatEndpoint(config.endpoint)) != null ? _b : `https://api.raindrop.ai/v1/`;
|
|
@@ -12805,6 +13363,14 @@ var Raindrop = class {
|
|
|
12805
13363
|
/**
|
|
12806
13364
|
* Begins a new interaction.
|
|
12807
13365
|
*
|
|
13366
|
+
* The interaction's routing binding lives until `finish()` (which unbinds it
|
|
13367
|
+
* by identity, so it is removed even if `finish()` runs inside a nested
|
|
13368
|
+
* `withSpan`/`withTool`/`asCurrent` scope or a detached task). One exception:
|
|
13369
|
+
* calling `begin()` INSIDE an `asCurrent(fn)` scope pushes the binding within
|
|
13370
|
+
* that scope, so it dies when the scope exits (matching the Python SDK's
|
|
13371
|
+
* token-reset semantics) — start such interactions outside `asCurrent`, or
|
|
13372
|
+
* keep their work inside the same scope.
|
|
13373
|
+
*
|
|
12808
13374
|
* @param traceContext - The trace context for the interaction.
|
|
12809
13375
|
* @returns The interaction object.
|
|
12810
13376
|
*/
|
|
@@ -12822,6 +13388,22 @@ var Raindrop = class {
|
|
|
12822
13388
|
tracer(globalProperties) {
|
|
12823
13389
|
return this._tracing.tracer(globalProperties);
|
|
12824
13390
|
}
|
|
13391
|
+
/**
|
|
13392
|
+
* Scope all spans created inside `fn` (and its awaited continuations) to this
|
|
13393
|
+
* client's project/key, without an interaction. Use it around auto-
|
|
13394
|
+
* instrumented calls (an LLM SDK call, a framework invocation) that aren't
|
|
13395
|
+
* wrapped by `begin()`/`finish()` so their spans route to this client's
|
|
13396
|
+
* project in a multi-client process. The binding lasts exactly the duration
|
|
13397
|
+
* of `fn` — it is removed when `fn` returns or throws.
|
|
13398
|
+
*
|
|
13399
|
+
* @example
|
|
13400
|
+
* ```ts
|
|
13401
|
+
* const answer = await raindrop.asCurrent(() => llm.chat({ ... }));
|
|
13402
|
+
* ```
|
|
13403
|
+
*/
|
|
13404
|
+
asCurrent(fn) {
|
|
13405
|
+
return withRoutingContext({ projectId: this.projectId, authHint: this.authHint }, fn);
|
|
13406
|
+
}
|
|
12825
13407
|
createSpanProcessor(processorOptions) {
|
|
12826
13408
|
return this._tracing.createSpanProcessor(processorOptions);
|
|
12827
13409
|
}
|