@bitfab/sdk 0.34.1 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -17
- package/dist/{chunk-5ZMEY5NX.js → chunk-4YTIVUYX.js} +307 -208
- package/dist/chunk-4YTIVUYX.js.map +1 -0
- package/dist/{chunk-KO373TDH.js → chunk-JECWMVJG.js} +3 -3
- package/dist/index.cjs +328 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +2 -2
- package/dist/node.cjs +328 -213
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +2 -2
- package/dist/{replay-YI2BUPCV.js → replay-CVMULH7T.js} +2 -2
- package/package.json +1 -2
- package/dist/chunk-5ZMEY5NX.js.map +0 -1
- /package/dist/{chunk-KO373TDH.js.map → chunk-JECWMVJG.js.map} +0 -0
- /package/dist/{replay-YI2BUPCV.js.map → replay-CVMULH7T.js.map} +0 -0
|
@@ -207,8 +207,78 @@ var BitfabError = class extends Error {
|
|
|
207
207
|
}
|
|
208
208
|
};
|
|
209
209
|
|
|
210
|
+
// src/readEnv.ts
|
|
211
|
+
function readEnv(name) {
|
|
212
|
+
if (typeof process !== "undefined" && process.env) {
|
|
213
|
+
return process.env[name];
|
|
214
|
+
}
|
|
215
|
+
return void 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/compress.ts
|
|
219
|
+
var DISABLE_COMPRESSION_ENV = "BITFAB_DISABLE_COMPRESSION";
|
|
220
|
+
var MIN_COMPRESSED_BYTES = 8192;
|
|
221
|
+
var gzipNode;
|
|
222
|
+
var _nodeGzipReady = (typeof process !== "undefined" && process.versions?.node ? (
|
|
223
|
+
// The join trick hides "node:zlib" from static analysis so bundlers that
|
|
224
|
+
// ban Node.js built-ins don't fail at build time. webpackIgnore tells
|
|
225
|
+
// webpack/turbopack to emit a native import() so Node.js can resolve the
|
|
226
|
+
// module at runtime. Same pattern as `asyncStorage.ts`.
|
|
227
|
+
import(
|
|
228
|
+
/* webpackIgnore: true */
|
|
229
|
+
["node", "zlib"].join(":")
|
|
230
|
+
).then(({ gzip }) => {
|
|
231
|
+
gzipNode = (data) => new Promise((resolve, reject) => {
|
|
232
|
+
gzip(data, (error, result) => {
|
|
233
|
+
if (error) {
|
|
234
|
+
reject(error);
|
|
235
|
+
} else {
|
|
236
|
+
resolve(result);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}).catch(() => {
|
|
241
|
+
})
|
|
242
|
+
) : Promise.resolve()).then(() => {
|
|
243
|
+
});
|
|
244
|
+
function toArrayBuffer(view) {
|
|
245
|
+
return view.buffer.slice(
|
|
246
|
+
view.byteOffset,
|
|
247
|
+
view.byteOffset + view.byteLength
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
async function gzipViaStream(bytes) {
|
|
251
|
+
const stream = new Blob([bytes]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
252
|
+
return await new Response(stream).arrayBuffer();
|
|
253
|
+
}
|
|
254
|
+
function encodeRequestBody(body) {
|
|
255
|
+
if (readEnv(DISABLE_COMPRESSION_ENV)) {
|
|
256
|
+
return { body };
|
|
257
|
+
}
|
|
258
|
+
const bytes = new TextEncoder().encode(body);
|
|
259
|
+
if (bytes.byteLength < MIN_COMPRESSED_BYTES) {
|
|
260
|
+
return { body };
|
|
261
|
+
}
|
|
262
|
+
if (gzipNode) {
|
|
263
|
+
return gzipNode(bytes).then(
|
|
264
|
+
(compressed) => ({
|
|
265
|
+
body: toArrayBuffer(compressed),
|
|
266
|
+
contentEncoding: "gzip"
|
|
267
|
+
}),
|
|
268
|
+
() => ({ body })
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
if (typeof CompressionStream === "undefined") {
|
|
272
|
+
return { body };
|
|
273
|
+
}
|
|
274
|
+
return gzipViaStream(bytes).then(
|
|
275
|
+
(compressed) => ({ body: compressed, contentEncoding: "gzip" }),
|
|
276
|
+
() => ({ body })
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
210
280
|
// src/version.generated.ts
|
|
211
|
-
var __version__ = "0.
|
|
281
|
+
var __version__ = "0.36.0";
|
|
212
282
|
|
|
213
283
|
// src/constants.ts
|
|
214
284
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -279,6 +349,125 @@ function runWithReplayContext(ctx, fn) {
|
|
|
279
349
|
return fn();
|
|
280
350
|
}
|
|
281
351
|
|
|
352
|
+
// src/payloadBudget.ts
|
|
353
|
+
var MAX_SPAN_CARRIER_BYTES = 28e5;
|
|
354
|
+
var textEncoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : null;
|
|
355
|
+
function byteLength(value) {
|
|
356
|
+
return textEncoder ? textEncoder.encode(value).length : value.length;
|
|
357
|
+
}
|
|
358
|
+
function carrierByteLength(body) {
|
|
359
|
+
return carrierBytesOf(textEncoder ? textEncoder.encode(body) : null, body);
|
|
360
|
+
}
|
|
361
|
+
function carrierBytesOf(encoded, body) {
|
|
362
|
+
if (!encoded) {
|
|
363
|
+
return body.length + 2;
|
|
364
|
+
}
|
|
365
|
+
let extra = 2;
|
|
366
|
+
for (let i = 0; i < encoded.length; i++) {
|
|
367
|
+
const byte = encoded[i];
|
|
368
|
+
if (byte === 34 || byte === 92) {
|
|
369
|
+
extra += 1;
|
|
370
|
+
} else if (byte < 32) {
|
|
371
|
+
extra += byte === 8 || byte === 9 || byte === 10 || byte === 12 || byte === 13 ? 1 : 5;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return encoded.length + extra;
|
|
375
|
+
}
|
|
376
|
+
var MAX_BYTES_PER_UNIT = 3;
|
|
377
|
+
function fitsCarrierBudget(body) {
|
|
378
|
+
const units = body.length;
|
|
379
|
+
if (units * MAX_BYTES_PER_UNIT + 2 <= MAX_SPAN_CARRIER_BYTES) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
if (units + 2 > MAX_SPAN_CARRIER_BYTES) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
return carrierByteLength(body) <= MAX_SPAN_CARRIER_BYTES;
|
|
386
|
+
}
|
|
387
|
+
var STRUCTURAL_SPAN_KEYS = /* @__PURE__ */ new Set([
|
|
388
|
+
"name",
|
|
389
|
+
"type",
|
|
390
|
+
"function_name",
|
|
391
|
+
"error_source"
|
|
392
|
+
]);
|
|
393
|
+
function asRecord(value) {
|
|
394
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
395
|
+
}
|
|
396
|
+
function cloneTrimmable(payload) {
|
|
397
|
+
const copy = { ...payload };
|
|
398
|
+
const containers = [];
|
|
399
|
+
const spanData = asRecord(copy.span_data);
|
|
400
|
+
if (spanData) {
|
|
401
|
+
const clone = { ...spanData };
|
|
402
|
+
copy.span_data = clone;
|
|
403
|
+
containers.push(clone);
|
|
404
|
+
}
|
|
405
|
+
const rawSpan = asRecord(copy.rawSpan);
|
|
406
|
+
const rawSpanData = rawSpan && asRecord(rawSpan.span_data);
|
|
407
|
+
if (rawSpan && rawSpanData) {
|
|
408
|
+
const clone = { ...rawSpanData };
|
|
409
|
+
copy.rawSpan = { ...rawSpan, span_data: clone };
|
|
410
|
+
containers.push(clone);
|
|
411
|
+
}
|
|
412
|
+
if (containers.length === 0) {
|
|
413
|
+
containers.push(copy);
|
|
414
|
+
}
|
|
415
|
+
return { copy, containers };
|
|
416
|
+
}
|
|
417
|
+
function collectCandidates(containers) {
|
|
418
|
+
const candidates = [];
|
|
419
|
+
for (const container of containers) {
|
|
420
|
+
for (const [key, value] of Object.entries(container)) {
|
|
421
|
+
if (STRUCTURAL_SPAN_KEYS.has(key) || value == null) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
let size;
|
|
425
|
+
try {
|
|
426
|
+
size = byteLength(JSON.stringify(value) ?? "");
|
|
427
|
+
} catch {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
candidates.push({ container, key, size });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return candidates.sort((a, b) => b.size - a.size);
|
|
434
|
+
}
|
|
435
|
+
function trimPayloadToBudget(payload, encode) {
|
|
436
|
+
const { copy, containers } = cloneTrimmable(payload);
|
|
437
|
+
const candidates = collectCandidates(containers);
|
|
438
|
+
if (candidates.length === 0) {
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
const trimmed = [];
|
|
442
|
+
for (const candidate of candidates) {
|
|
443
|
+
candidate.container[candidate.key] = `<unserializable: too_large_${candidate.size}_bytes>`;
|
|
444
|
+
trimmed.push(candidate.key);
|
|
445
|
+
let body;
|
|
446
|
+
try {
|
|
447
|
+
body = encode(copy);
|
|
448
|
+
} catch {
|
|
449
|
+
return void 0;
|
|
450
|
+
}
|
|
451
|
+
if (fitsCarrierBudget(body)) {
|
|
452
|
+
return { value: copy, trimmed };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
function markPayloadTrimmed(value, trimmed) {
|
|
458
|
+
const existing = Array.isArray(value.errors) ? value.errors : [];
|
|
459
|
+
value.errors = [
|
|
460
|
+
...existing,
|
|
461
|
+
{
|
|
462
|
+
source: "sdk",
|
|
463
|
+
step: "payload_budget",
|
|
464
|
+
error: `trimmed oversized field(s) to fit the ${MAX_SPAN_CARRIER_BYTES}-byte span carrier budget: ${[
|
|
465
|
+
...new Set(trimmed)
|
|
466
|
+
].join(", ")}`
|
|
467
|
+
}
|
|
468
|
+
];
|
|
469
|
+
}
|
|
470
|
+
|
|
282
471
|
// src/warnOnce.ts
|
|
283
472
|
var warned = /* @__PURE__ */ new Set();
|
|
284
473
|
function warnOnce(key, message) {
|
|
@@ -294,8 +483,37 @@ function warnOnce(key, message) {
|
|
|
294
483
|
|
|
295
484
|
// src/serializePayload.ts
|
|
296
485
|
function serializePayloadBody(payload) {
|
|
486
|
+
const encoded = encodePayloadBody(payload);
|
|
487
|
+
if (fitsCarrierBudget(encoded.body)) {
|
|
488
|
+
return { body: encoded.body, dropped: encoded.dropped };
|
|
489
|
+
}
|
|
490
|
+
return applyPayloadBudget(encoded);
|
|
491
|
+
}
|
|
492
|
+
function applyPayloadBudget(encoded) {
|
|
493
|
+
const result = encoded.value ? trimPayloadToBudget(
|
|
494
|
+
encoded.value,
|
|
495
|
+
(value) => encodePayloadBody(value).body
|
|
496
|
+
) : void 0;
|
|
497
|
+
if (!result) {
|
|
498
|
+
return { body: encoded.body, dropped: encoded.dropped };
|
|
499
|
+
}
|
|
500
|
+
warnOnce(
|
|
501
|
+
"payload:over-budget",
|
|
502
|
+
`a span payload exceeded the ${MAX_SPAN_CARRIER_BYTES}-byte carrier budget; its largest field(s) (${[
|
|
503
|
+
...new Set(result.trimmed)
|
|
504
|
+
].join(
|
|
505
|
+
", "
|
|
506
|
+
)}) were replaced with placeholders so the span still ships. The span is incomplete and may not be replayable.`
|
|
507
|
+
);
|
|
508
|
+
markPayloadTrimmed(result.value, result.trimmed);
|
|
509
|
+
return {
|
|
510
|
+
body: encodePayloadBody(result.value).body,
|
|
511
|
+
dropped: encoded.dropped
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function encodePayloadBody(payload) {
|
|
297
515
|
try {
|
|
298
|
-
return { body: JSON.stringify(payload), dropped: [] };
|
|
516
|
+
return { body: JSON.stringify(payload), dropped: [], value: payload };
|
|
299
517
|
} catch {
|
|
300
518
|
const dropped = [];
|
|
301
519
|
const sanitize = (value, seen) => {
|
|
@@ -360,12 +578,11 @@ function serializePayloadBody(payload) {
|
|
|
360
578
|
sanitized = sanitize(payload, /* @__PURE__ */ new WeakSet());
|
|
361
579
|
} catch (error) {
|
|
362
580
|
const message = error instanceof Error ? error.message : String(error);
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
dropped
|
|
366
|
-
};
|
|
581
|
+
const marker = { error: `payload_serialize_failed: ${message}` };
|
|
582
|
+
return { body: JSON.stringify(marker), dropped, value: marker };
|
|
367
583
|
}
|
|
368
|
-
|
|
584
|
+
const isRecord = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
|
|
585
|
+
if (dropped.length > 0 && isRecord) {
|
|
369
586
|
const obj = sanitized;
|
|
370
587
|
const existing = Array.isArray(obj.errors) ? obj.errors : [];
|
|
371
588
|
obj.errors = [
|
|
@@ -379,7 +596,11 @@ function serializePayloadBody(payload) {
|
|
|
379
596
|
}
|
|
380
597
|
];
|
|
381
598
|
}
|
|
382
|
-
return {
|
|
599
|
+
return {
|
|
600
|
+
body: JSON.stringify(sanitized),
|
|
601
|
+
dropped,
|
|
602
|
+
value: isRecord ? sanitized : void 0
|
|
603
|
+
};
|
|
383
604
|
}
|
|
384
605
|
}
|
|
385
606
|
|
|
@@ -395,14 +616,6 @@ import {
|
|
|
395
616
|
BatchSpanProcessor
|
|
396
617
|
} from "@opentelemetry/sdk-trace-base";
|
|
397
618
|
|
|
398
|
-
// src/readEnv.ts
|
|
399
|
-
function readEnv(name) {
|
|
400
|
-
if (typeof process !== "undefined" && process.env) {
|
|
401
|
-
return process.env[name];
|
|
402
|
-
}
|
|
403
|
-
return void 0;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
619
|
// src/unrefTimer.ts
|
|
407
620
|
function unrefTimer(timer) {
|
|
408
621
|
const handle = timer;
|
|
@@ -418,10 +631,8 @@ var OTLP_TRACES_ENDPOINT = "/api/sdk/otel/v1/traces";
|
|
|
418
631
|
var MAX_EXPORT_REQUEST_BYTES = 3e6;
|
|
419
632
|
var MAX_REQUEST_BYTES_ENV = "BITFAB_OTEL_MAX_REQUEST_BYTES";
|
|
420
633
|
var EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
|
|
421
|
-
var COLLECTOR_ENDPOINT_ENV = "BITFAB_OTEL_EXPORTER_ENDPOINT";
|
|
422
634
|
var MAX_QUEUE_SIZE = 8192;
|
|
423
635
|
var DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
|
|
424
|
-
var COLLECTOR_MAX_EXPORT_BATCH_SIZE = 32;
|
|
425
636
|
var DIRECT_MAX_REQUEST_BATCH_SIZE = 8;
|
|
426
637
|
var DEFAULT_EXPORT_CONCURRENCY = 32;
|
|
427
638
|
var MAX_EXPORT_CONCURRENCY = 64;
|
|
@@ -466,7 +677,7 @@ function recordTraceSubmission(operation, payload) {
|
|
|
466
677
|
return;
|
|
467
678
|
}
|
|
468
679
|
if (operation === "external_span") {
|
|
469
|
-
const rawSpan =
|
|
680
|
+
const rawSpan = asRecord2(payload.rawSpan);
|
|
470
681
|
if (typeof rawSpan?.id !== "string") {
|
|
471
682
|
submissionCounter += 1;
|
|
472
683
|
}
|
|
@@ -503,14 +714,14 @@ function takeReplaySpanCounts(traceIds) {
|
|
|
503
714
|
}
|
|
504
715
|
return counts;
|
|
505
716
|
}
|
|
506
|
-
function
|
|
717
|
+
function asRecord2(value) {
|
|
507
718
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
508
719
|
}
|
|
509
720
|
function resolveSourceTraceId(payload) {
|
|
510
721
|
if (typeof payload.sourceTraceId === "string") {
|
|
511
722
|
return payload.sourceTraceId;
|
|
512
723
|
}
|
|
513
|
-
const rawTrace =
|
|
724
|
+
const rawTrace = asRecord2(payload.externalTrace) ?? asRecord2(payload.rawTrace);
|
|
514
725
|
return typeof rawTrace?.id === "string" ? rawTrace.id : void 0;
|
|
515
726
|
}
|
|
516
727
|
function otlpValue(value) {
|
|
@@ -568,32 +779,28 @@ function spanToOtlp(span) {
|
|
|
568
779
|
}
|
|
569
780
|
return result;
|
|
570
781
|
}
|
|
571
|
-
|
|
782
|
+
var SPAN_SEPARATOR_BYTES = 1;
|
|
783
|
+
function encodeSpan(span) {
|
|
784
|
+
const json = JSON.stringify(spanToOtlp(span));
|
|
785
|
+
return { json, size: byteLength(json) };
|
|
786
|
+
}
|
|
787
|
+
function requestEnvelope(first) {
|
|
572
788
|
const scope = first.instrumentationScope;
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
]
|
|
587
|
-
}
|
|
588
|
-
]
|
|
589
|
-
};
|
|
789
|
+
const resource = JSON.stringify({
|
|
790
|
+
attributes: otlpAttributes(
|
|
791
|
+
first.resource.attributes
|
|
792
|
+
)
|
|
793
|
+
});
|
|
794
|
+
const scopeJson = JSON.stringify({
|
|
795
|
+
name: scope.name,
|
|
796
|
+
version: scope.version ?? ""
|
|
797
|
+
});
|
|
798
|
+
const head = `{"resourceSpans":[{"resource":${resource},"scopeSpans":[{"scope":${scopeJson},"spans":[`;
|
|
799
|
+
const tail = "]}]}]}";
|
|
800
|
+
return { head, tail, size: byteLength(head) + byteLength(tail) };
|
|
590
801
|
}
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
if (typeof TextEncoder !== "undefined") {
|
|
594
|
-
return new TextEncoder().encode(json).length;
|
|
595
|
-
}
|
|
596
|
-
return json.length;
|
|
802
|
+
function encodeRequest(envelope, spans) {
|
|
803
|
+
return envelope.head + spans.map((span) => span.json).join(",") + envelope.tail;
|
|
597
804
|
}
|
|
598
805
|
function delay(ms) {
|
|
599
806
|
return new Promise((resolve) => {
|
|
@@ -671,57 +878,55 @@ var BitfabSpanExporter = class {
|
|
|
671
878
|
return true;
|
|
672
879
|
}
|
|
673
880
|
let encoded;
|
|
881
|
+
let envelope;
|
|
674
882
|
try {
|
|
675
|
-
encoded = spans.map(
|
|
883
|
+
encoded = spans.map(encodeSpan);
|
|
884
|
+
envelope = requestEnvelope(spans[0]);
|
|
676
885
|
} catch (error) {
|
|
677
886
|
logError("failed to encode an OpenTelemetry span batch", error);
|
|
678
887
|
return false;
|
|
679
888
|
}
|
|
680
|
-
const
|
|
681
|
-
const batches = this.buildRequestBatches(first, encoded);
|
|
889
|
+
const batches = this.buildRequestBatches(envelope, encoded);
|
|
682
890
|
const results = await mapWithConcurrency(
|
|
683
891
|
batches,
|
|
684
892
|
this.exportConcurrency,
|
|
685
|
-
(batch) => this.send(
|
|
893
|
+
(batch) => this.send(envelope, batch)
|
|
686
894
|
);
|
|
687
895
|
return results.every(Boolean);
|
|
688
896
|
}
|
|
689
|
-
buildRequestBatches(
|
|
897
|
+
buildRequestBatches(envelope, spans) {
|
|
690
898
|
const batches = [];
|
|
691
899
|
let current = [];
|
|
900
|
+
let size = envelope.size;
|
|
692
901
|
for (const span of spans) {
|
|
693
|
-
|
|
694
|
-
|
|
902
|
+
const addition = span.size + (current.length > 0 ? SPAN_SEPARATOR_BYTES : 0);
|
|
903
|
+
if (current.length > 0 && (current.length >= this.maxRequestBatchSize || size + addition > this.maxRequestBytes)) {
|
|
904
|
+
batches.push({ spans: current, size });
|
|
695
905
|
current = [];
|
|
906
|
+
size = envelope.size;
|
|
696
907
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
batches.push(current);
|
|
700
|
-
current = [span];
|
|
701
|
-
} else {
|
|
702
|
-
current = candidate;
|
|
703
|
-
}
|
|
908
|
+
current.push(span);
|
|
909
|
+
size += span.size + (current.length > 1 ? SPAN_SEPARATOR_BYTES : 0);
|
|
704
910
|
}
|
|
705
911
|
if (current.length > 0) {
|
|
706
|
-
batches.push(current);
|
|
912
|
+
batches.push({ spans: current, size });
|
|
707
913
|
}
|
|
708
914
|
return batches;
|
|
709
915
|
}
|
|
710
|
-
async send(
|
|
711
|
-
|
|
712
|
-
if (encodedSize(payload) > this.maxRequestBytes) {
|
|
916
|
+
async send(envelope, batch) {
|
|
917
|
+
if (batch.size > this.maxRequestBytes) {
|
|
713
918
|
logError(
|
|
714
919
|
"a single OpenTelemetry span exceeded the configured request-size target and could not be exported"
|
|
715
920
|
);
|
|
716
921
|
return false;
|
|
717
922
|
}
|
|
718
923
|
try {
|
|
719
|
-
await this.sendWithRetries(
|
|
924
|
+
await this.sendWithRetries(encodeRequest(envelope, batch.spans));
|
|
720
925
|
return true;
|
|
721
926
|
} catch (error) {
|
|
722
927
|
if (error instanceof OtlpPayloadTooLargeError) {
|
|
723
928
|
logError(
|
|
724
|
-
spans.length === 1 ? "a single OpenTelemetry span exceeded the ingestion request limit and could not be exported" : "an OpenTelemetry span batch exceeded the ingestion request limit and could not be exported"
|
|
929
|
+
batch.spans.length === 1 ? "a single OpenTelemetry span exceeded the ingestion request limit and could not be exported" : "an OpenTelemetry span batch exceeded the ingestion request limit and could not be exported"
|
|
725
930
|
);
|
|
726
931
|
return false;
|
|
727
932
|
}
|
|
@@ -745,15 +950,15 @@ var BitfabSpanExporter = class {
|
|
|
745
950
|
* the server does not yet understand. The fix is a client-supplied
|
|
746
951
|
* idempotency key that ingestion dedupes on.
|
|
747
952
|
*/
|
|
748
|
-
async sendWithRetries(
|
|
953
|
+
async sendWithRetries(body) {
|
|
749
954
|
for (let attempt = 0; attempt < MAX_SEND_ATTEMPTS; attempt += 1) {
|
|
750
955
|
try {
|
|
751
956
|
const response = await this.directSender(
|
|
752
957
|
OTLP_TRACES_ENDPOINT,
|
|
753
|
-
|
|
958
|
+
body,
|
|
754
959
|
EXPORT_TIMEOUT_MILLIS
|
|
755
960
|
);
|
|
756
|
-
const partialSuccess =
|
|
961
|
+
const partialSuccess = asRecord2(response?.partialSuccess);
|
|
757
962
|
const rejected = partialSuccess?.rejectedSpans;
|
|
758
963
|
if (rejected !== void 0 && rejected !== "0" && rejected !== 0) {
|
|
759
964
|
logError(
|
|
@@ -781,115 +986,6 @@ var BitfabSpanExporter = class {
|
|
|
781
986
|
async forceFlush() {
|
|
782
987
|
}
|
|
783
988
|
};
|
|
784
|
-
var CollectorSpanExporter = class {
|
|
785
|
-
constructor(endpoint, apiKey, maxRequestBytes) {
|
|
786
|
-
this.endpoint = endpoint;
|
|
787
|
-
this.apiKey = apiKey;
|
|
788
|
-
this.maxRequestBytes = maxRequestBytes;
|
|
789
|
-
}
|
|
790
|
-
/**
|
|
791
|
-
* Loaded through a dynamic import rather than a top-level one so bundlers
|
|
792
|
-
* code-split it: Collector delivery is opt-in, and a consumer who never sets
|
|
793
|
-
* an endpoint should not pay for the exporter in their initial bundle. It is
|
|
794
|
-
* a hard dependency, so this cannot fail for want of the package.
|
|
795
|
-
*/
|
|
796
|
-
loadExporterModule() {
|
|
797
|
-
if (!this.pendingModule) {
|
|
798
|
-
this.pendingModule = import("@opentelemetry/exporter-trace-otlp-proto");
|
|
799
|
-
}
|
|
800
|
-
return this.pendingModule;
|
|
801
|
-
}
|
|
802
|
-
export(spans, resultCallback) {
|
|
803
|
-
void this.exportAsync(spans).then(
|
|
804
|
-
(succeeded) => {
|
|
805
|
-
resultCallback({
|
|
806
|
-
code: succeeded ? ExportResultCode.SUCCESS : ExportResultCode.FAILED
|
|
807
|
-
});
|
|
808
|
-
},
|
|
809
|
-
(error) => {
|
|
810
|
-
resultCallback({ code: ExportResultCode.FAILED, error });
|
|
811
|
-
}
|
|
812
|
-
);
|
|
813
|
-
}
|
|
814
|
-
async exportAsync(spans) {
|
|
815
|
-
if (spans.length === 0) {
|
|
816
|
-
return true;
|
|
817
|
-
}
|
|
818
|
-
let delegate;
|
|
819
|
-
try {
|
|
820
|
-
delegate = await this.resolveDelegate();
|
|
821
|
-
} catch (error) {
|
|
822
|
-
logError("failed to build the OTLP Collector exporter", error);
|
|
823
|
-
return false;
|
|
824
|
-
}
|
|
825
|
-
const results = await Promise.all(
|
|
826
|
-
this.partition(spans).map(
|
|
827
|
-
(batch) => new Promise((resolve) => {
|
|
828
|
-
try {
|
|
829
|
-
delegate.export(batch, (result) => {
|
|
830
|
-
resolve(result.code === ExportResultCode.SUCCESS);
|
|
831
|
-
});
|
|
832
|
-
} catch (error) {
|
|
833
|
-
logError("Collector export threw", error);
|
|
834
|
-
resolve(false);
|
|
835
|
-
}
|
|
836
|
-
})
|
|
837
|
-
)
|
|
838
|
-
);
|
|
839
|
-
return results.every(Boolean);
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Partition by the encoded JSON size of each carrier rather than its encoded
|
|
843
|
-
* protobuf size. Protobuf is strictly smaller than the equivalent JSON for
|
|
844
|
-
* these payloads, so the JSON figure is a conservative bound that keeps every
|
|
845
|
-
* request under the target without pulling `@opentelemetry/otlp-transformer`
|
|
846
|
-
* into the dependency set purely to measure bytes.
|
|
847
|
-
*/
|
|
848
|
-
partition(spans) {
|
|
849
|
-
const batches = [];
|
|
850
|
-
let current = [];
|
|
851
|
-
let currentSize = 0;
|
|
852
|
-
for (const span of spans) {
|
|
853
|
-
const size = encodedSize(spanToOtlp(span));
|
|
854
|
-
if (current.length > 0 && currentSize + size > this.maxRequestBytes) {
|
|
855
|
-
batches.push(current);
|
|
856
|
-
current = [];
|
|
857
|
-
currentSize = 0;
|
|
858
|
-
}
|
|
859
|
-
current.push(span);
|
|
860
|
-
currentSize += size;
|
|
861
|
-
}
|
|
862
|
-
if (current.length > 0) {
|
|
863
|
-
batches.push(current);
|
|
864
|
-
}
|
|
865
|
-
return batches;
|
|
866
|
-
}
|
|
867
|
-
async resolveDelegate() {
|
|
868
|
-
const apiKey = this.apiKey() ?? "";
|
|
869
|
-
if (this.delegate && this.delegateApiKey === apiKey) {
|
|
870
|
-
return this.delegate;
|
|
871
|
-
}
|
|
872
|
-
const { OTLPTraceExporter } = await this.loadExporterModule();
|
|
873
|
-
const previous = this.delegate;
|
|
874
|
-
this.delegate = new OTLPTraceExporter({
|
|
875
|
-
url: this.endpoint,
|
|
876
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
877
|
-
timeoutMillis: EXPORT_TIMEOUT_MILLIS
|
|
878
|
-
});
|
|
879
|
-
this.delegateApiKey = apiKey;
|
|
880
|
-
if (previous) {
|
|
881
|
-
void previous.shutdown().catch(() => {
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
return this.delegate;
|
|
885
|
-
}
|
|
886
|
-
async shutdown() {
|
|
887
|
-
await this.delegate?.shutdown();
|
|
888
|
-
}
|
|
889
|
-
async forceFlush() {
|
|
890
|
-
await this.delegate?.forceFlush?.();
|
|
891
|
-
}
|
|
892
|
-
};
|
|
893
989
|
var DeliveryTrackingExporter = class {
|
|
894
990
|
constructor(exporter) {
|
|
895
991
|
this.exporter = exporter;
|
|
@@ -932,27 +1028,22 @@ var DeliveryTrackingExporter = class {
|
|
|
932
1028
|
var OtelBatchTransport = class {
|
|
933
1029
|
constructor(options) {
|
|
934
1030
|
this.closed = false;
|
|
935
|
-
const collectorEndpoint = options.collectorEndpoint;
|
|
936
1031
|
const maxRequestBytes = options.maxRequestBytes ?? MAX_EXPORT_REQUEST_BYTES;
|
|
937
1032
|
const maxRequestBatchSize = options.maxRequestBatchSize ?? DIRECT_MAX_REQUEST_BATCH_SIZE;
|
|
938
1033
|
if (maxRequestBatchSize <= 0) {
|
|
939
1034
|
throw new BitfabError("maxRequestBatchSize must be a positive integer");
|
|
940
1035
|
}
|
|
941
1036
|
this.deliveryTracker = new DeliveryTrackingExporter(
|
|
942
|
-
|
|
1037
|
+
new BitfabSpanExporter(
|
|
943
1038
|
options.directSender,
|
|
944
1039
|
maxRequestBytes,
|
|
945
1040
|
maxRequestBatchSize,
|
|
946
1041
|
options.exportConcurrency ?? DEFAULT_EXPORT_CONCURRENCY
|
|
947
|
-
) : new CollectorSpanExporter(
|
|
948
|
-
normalizeCollectorEndpoint(collectorEndpoint),
|
|
949
|
-
options.apiKey,
|
|
950
|
-
maxRequestBytes
|
|
951
1042
|
)
|
|
952
1043
|
);
|
|
953
1044
|
this.processor = new BatchSpanProcessor(this.deliveryTracker, {
|
|
954
1045
|
maxQueueSize: options.maxQueueSize ?? MAX_QUEUE_SIZE,
|
|
955
|
-
maxExportBatchSize: options.maxExportBatchSize ??
|
|
1046
|
+
maxExportBatchSize: options.maxExportBatchSize ?? DIRECT_MAX_EXPORT_BATCH_SIZE,
|
|
956
1047
|
scheduledDelayMillis: SCHEDULE_DELAY_MILLIS,
|
|
957
1048
|
exportTimeoutMillis: options.exportTimeoutMillis ?? EXPORT_TIMEOUT_MILLIS
|
|
958
1049
|
});
|
|
@@ -1037,16 +1128,12 @@ var OtelBatchTransport = class {
|
|
|
1037
1128
|
return flushed && shutdownCompleted;
|
|
1038
1129
|
}
|
|
1039
1130
|
};
|
|
1040
|
-
function normalizeCollectorEndpoint(endpoint) {
|
|
1041
|
-
const trimmed = endpoint.replace(/\/+$/, "");
|
|
1042
|
-
return trimmed.endsWith("/v1/traces") ? trimmed : `${trimmed}/v1/traces`;
|
|
1043
|
-
}
|
|
1044
1131
|
function endSpan(span, endTime) {
|
|
1045
1132
|
span.end(endTime);
|
|
1046
1133
|
}
|
|
1047
1134
|
function spanName(operation, payload) {
|
|
1048
1135
|
if (operation === "external_span") {
|
|
1049
|
-
const spanData =
|
|
1136
|
+
const spanData = asRecord2(asRecord2(payload.rawSpan)?.span_data);
|
|
1050
1137
|
if (typeof spanData?.name === "string") {
|
|
1051
1138
|
return spanData.name;
|
|
1052
1139
|
}
|
|
@@ -1057,8 +1144,8 @@ function spanName(operation, payload) {
|
|
|
1057
1144
|
return `bitfab.${operation}`;
|
|
1058
1145
|
}
|
|
1059
1146
|
function payloadTimestamp(payload, field) {
|
|
1060
|
-
const rawSpan =
|
|
1061
|
-
const rawTrace =
|
|
1147
|
+
const rawSpan = asRecord2(payload.rawSpan);
|
|
1148
|
+
const rawTrace = asRecord2(payload.externalTrace) ?? asRecord2(payload.rawTrace);
|
|
1062
1149
|
const raw = rawSpan?.[field] ?? rawTrace?.[field];
|
|
1063
1150
|
if (typeof raw !== "string") {
|
|
1064
1151
|
return void 0;
|
|
@@ -1067,7 +1154,7 @@ function payloadTimestamp(payload, field) {
|
|
|
1067
1154
|
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
1068
1155
|
}
|
|
1069
1156
|
function hasError(payload) {
|
|
1070
|
-
const spanData =
|
|
1157
|
+
const spanData = asRecord2(asRecord2(payload.rawSpan)?.span_data);
|
|
1071
1158
|
if (spanData?.error != null) {
|
|
1072
1159
|
return true;
|
|
1073
1160
|
}
|
|
@@ -1077,7 +1164,6 @@ function hasError(payload) {
|
|
|
1077
1164
|
function createOtelTransport(options) {
|
|
1078
1165
|
return new OtelBatchTransport({
|
|
1079
1166
|
...options,
|
|
1080
|
-
collectorEndpoint: readEnv(COLLECTOR_ENDPOINT_ENV) || void 0,
|
|
1081
1167
|
exportConcurrency: readBoundedIntEnv(
|
|
1082
1168
|
EXPORT_CONCURRENCY_ENV,
|
|
1083
1169
|
MAX_EXPORT_CONCURRENCY,
|
|
@@ -1225,8 +1311,7 @@ var HttpClient = class {
|
|
|
1225
1311
|
}
|
|
1226
1312
|
if (!this.traceTransport) {
|
|
1227
1313
|
this.traceTransport = createTraceTransport({
|
|
1228
|
-
|
|
1229
|
-
directSender: (endpoint, payload, timeoutMs) => this.request(endpoint, payload, {
|
|
1314
|
+
directSender: (endpoint, body, timeoutMs) => this.sendEncoded(endpoint, body, {
|
|
1230
1315
|
timeout: timeoutMs
|
|
1231
1316
|
})
|
|
1232
1317
|
});
|
|
@@ -1296,11 +1381,6 @@ var HttpClient = class {
|
|
|
1296
1381
|
* @throws {BitfabError} If the request fails
|
|
1297
1382
|
*/
|
|
1298
1383
|
async request(endpoint, payload, options) {
|
|
1299
|
-
const url = `${this.serviceUrl}${endpoint}`;
|
|
1300
|
-
const timeout = options?.timeout ?? this.timeout;
|
|
1301
|
-
const method = options?.method ?? "POST";
|
|
1302
|
-
const controller = new AbortController();
|
|
1303
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1304
1384
|
const { body, dropped } = serializePayloadBody(payload);
|
|
1305
1385
|
if (dropped.length > 0) {
|
|
1306
1386
|
try {
|
|
@@ -1310,14 +1390,33 @@ var HttpClient = class {
|
|
|
1310
1390
|
} catch {
|
|
1311
1391
|
}
|
|
1312
1392
|
}
|
|
1393
|
+
return this.sendEncoded(endpoint, body, options);
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* POST an already-encoded body. The span transport encodes its own batches,
|
|
1397
|
+
* so routing them back through {@link HttpClient.request} would encode the
|
|
1398
|
+
* same data twice.
|
|
1399
|
+
*/
|
|
1400
|
+
async sendEncoded(endpoint, body, options) {
|
|
1401
|
+
const url = `${this.serviceUrl}${endpoint}`;
|
|
1402
|
+
const timeout = options?.timeout ?? this.timeout;
|
|
1403
|
+
const method = options?.method ?? "POST";
|
|
1404
|
+
const controller = new AbortController();
|
|
1405
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1406
|
+
const prepared = encodeRequestBody(body);
|
|
1407
|
+
const encoded = prepared instanceof Promise ? await prepared : prepared;
|
|
1408
|
+
const headers = {
|
|
1409
|
+
"Content-Type": "application/json",
|
|
1410
|
+
Authorization: `Bearer ${this.resolveApiKey() ?? ""}`
|
|
1411
|
+
};
|
|
1412
|
+
if (encoded.contentEncoding) {
|
|
1413
|
+
headers["Content-Encoding"] = encoded.contentEncoding;
|
|
1414
|
+
}
|
|
1313
1415
|
try {
|
|
1314
1416
|
const response = await fetch(url, {
|
|
1315
1417
|
method,
|
|
1316
|
-
headers
|
|
1317
|
-
|
|
1318
|
-
Authorization: `Bearer ${this.resolveApiKey() ?? ""}`
|
|
1319
|
-
},
|
|
1320
|
-
body,
|
|
1418
|
+
headers,
|
|
1419
|
+
body: encoded.body,
|
|
1321
1420
|
signal: controller.signal
|
|
1322
1421
|
});
|
|
1323
1422
|
if (!response.ok) {
|
|
@@ -1657,8 +1756,8 @@ function fallbackUuidV4() {
|
|
|
1657
1756
|
|
|
1658
1757
|
// src/serialize.ts
|
|
1659
1758
|
import superjson from "superjson";
|
|
1660
|
-
var MAX_SERIALIZED_BYTES =
|
|
1661
|
-
var MAX_FRAMEWORK_SERIALIZED_BYTES =
|
|
1759
|
+
var MAX_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES;
|
|
1760
|
+
var MAX_FRAMEWORK_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES;
|
|
1662
1761
|
function describeValue(value) {
|
|
1663
1762
|
try {
|
|
1664
1763
|
const ctorName = value?.constructor?.name;
|
|
@@ -2296,4 +2395,4 @@ export {
|
|
|
2296
2395
|
reportReplayProgress,
|
|
2297
2396
|
replay
|
|
2298
2397
|
};
|
|
2299
|
-
//# sourceMappingURL=chunk-
|
|
2398
|
+
//# sourceMappingURL=chunk-4YTIVUYX.js.map
|