@logbrew/sdk 0.1.29 → 0.1.31
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 +2 -2
- package/core.cjs +47 -11
- package/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -456,7 +456,7 @@ Prefer removing sensitive values at the source before calling LogBrew. `eventFil
|
|
|
456
456
|
|
|
457
457
|
## Automatic Delivery
|
|
458
458
|
|
|
459
|
-
When a client owns a `transport`, it automatically sends queued work after
|
|
459
|
+
When a client owns a `transport`, it automatically sends queued work 1 second after the first queued event or when 50 events are waiting, whichever happens first, so a single event is readable in about a second while bursts still share one request. The one-shot timer starts only after capture, later events do not restart it, is `unref()`'d on Node.js, and is cancelled by manual flush, purge, or shutdown. Automatic sends reuse the same serialized flush path, immutable retry body, accepted-prefix acknowledgement, and persistent queue as manual calls. They do not install process, signal, page, or exit hooks.
|
|
460
460
|
|
|
461
461
|
```js
|
|
462
462
|
const transport = RecordingTransport.alwaysAccept();
|
|
@@ -465,7 +465,7 @@ const client = LogBrewClient.create({
|
|
|
465
465
|
sdkName: "checkout-api",
|
|
466
466
|
sdkVersion: "1.0.0",
|
|
467
467
|
transport,
|
|
468
|
-
deliveryIntervalMs:
|
|
468
|
+
deliveryIntervalMs: 1000,
|
|
469
469
|
deliveryQueueThreshold: 50
|
|
470
470
|
});
|
|
471
471
|
|
package/core.cjs
CHANGED
|
@@ -88,7 +88,8 @@ const DEFAULT_MAX_QUEUE_SIZE = 1000;
|
|
|
88
88
|
const DEFAULT_MAX_QUEUE_BYTES = 4 * 1024 * 1024;
|
|
89
89
|
const DEFAULT_MAX_BATCH_EVENTS = 100;
|
|
90
90
|
const DEFAULT_MAX_BATCH_BYTES = 256 * 1024;
|
|
91
|
-
|
|
91
|
+
// One second matches the OpenTelemetry log processor default, so a lone event becomes readable quickly.
|
|
92
|
+
const DEFAULT_DELIVERY_INTERVAL_MS = 1000;
|
|
92
93
|
const MAX_DELIVERY_INTERVAL_MS = 60 * 1000;
|
|
93
94
|
const DEFAULT_DELIVERY_QUEUE_THRESHOLD = 50;
|
|
94
95
|
const MAX_CLIENT_REPORT_REASONS = 16;
|
|
@@ -96,6 +97,8 @@ const MAX_CLIENT_REPORT_COUNT = 1_000_000_000;
|
|
|
96
97
|
const DELIVERY_HEALTH_SCHEMA_VERSION = 1;
|
|
97
98
|
const EVENT_QUEUE_FACTORY = Symbol.for("@logbrew/sdk.eventQueueFactory");
|
|
98
99
|
const CONTEXT_PROVIDER = Symbol.for("@logbrew/sdk.contextProvider");
|
|
100
|
+
// Runtime packages supply request-scoped breadcrumbs through this seam; core merges them into issues.
|
|
101
|
+
const BREADCRUMB_PROVIDER = Symbol.for("@logbrew/sdk.breadcrumbProvider");
|
|
99
102
|
const MAX_ERROR_CAUSES = 5;
|
|
100
103
|
const BUILTIN_ERROR_NAMES = new Set([
|
|
101
104
|
"AggregateError",
|
|
@@ -215,6 +218,7 @@ class LogBrewClient {
|
|
|
215
218
|
sdkVersion,
|
|
216
219
|
context,
|
|
217
220
|
[CONTEXT_PROVIDER]: contextProvider,
|
|
221
|
+
[BREADCRUMB_PROVIDER]: breadcrumbProvider,
|
|
218
222
|
maxRetries = 2,
|
|
219
223
|
eventFilter,
|
|
220
224
|
maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
|
|
@@ -236,6 +240,9 @@ class LogBrewClient {
|
|
|
236
240
|
if (contextProvider !== undefined && typeof contextProvider !== "function") {
|
|
237
241
|
throw new SdkError("validation_error", "context provider must be a function");
|
|
238
242
|
}
|
|
243
|
+
if (breadcrumbProvider !== undefined && typeof breadcrumbProvider !== "function") {
|
|
244
|
+
throw new SdkError("validation_error", "breadcrumb provider must be a function");
|
|
245
|
+
}
|
|
239
246
|
requireNonNegativeInteger("maxRetries", maxRetries);
|
|
240
247
|
if (eventFilter !== undefined && typeof eventFilter !== "function") {
|
|
241
248
|
throw new SdkError("validation_error", "eventFilter must be a function");
|
|
@@ -285,6 +292,7 @@ class LogBrewClient {
|
|
|
285
292
|
onEventDropped,
|
|
286
293
|
context: clientContext,
|
|
287
294
|
contextProvider,
|
|
295
|
+
breadcrumbProvider,
|
|
288
296
|
sdk: {
|
|
289
297
|
name: sdkName,
|
|
290
298
|
language: "javascript",
|
|
@@ -307,6 +315,7 @@ class LogBrewClient {
|
|
|
307
315
|
onEventDropped,
|
|
308
316
|
context,
|
|
309
317
|
contextProvider,
|
|
318
|
+
breadcrumbProvider,
|
|
310
319
|
eventStore,
|
|
311
320
|
eventQueueFactory,
|
|
312
321
|
transport,
|
|
@@ -326,6 +335,7 @@ class LogBrewClient {
|
|
|
326
335
|
this.onEventDropped = onEventDropped;
|
|
327
336
|
this.context = cloneTelemetryContext(context);
|
|
328
337
|
this.contextProvider = contextProvider;
|
|
338
|
+
this.breadcrumbProvider = breadcrumbProvider;
|
|
329
339
|
this.transport = transport;
|
|
330
340
|
this.sdk = sdk;
|
|
331
341
|
this.maxRetries = maxRetries;
|
|
@@ -631,20 +641,46 @@ class LogBrewClient {
|
|
|
631
641
|
}
|
|
632
642
|
|
|
633
643
|
#pushIssue(id, timestamp, attributes) {
|
|
634
|
-
|
|
644
|
+
if (attributes.breadcrumbs !== undefined) {
|
|
645
|
+
return this.#pushEvent("issue", id, timestamp, validateIssue(attributes));
|
|
646
|
+
}
|
|
647
|
+
const provided = this.#providedBreadcrumbs();
|
|
648
|
+
const merged = provided.breadcrumbs.length === 0
|
|
649
|
+
? this.issueBreadcrumbs
|
|
650
|
+
: [...this.issueBreadcrumbs, ...provided.breadcrumbs]
|
|
651
|
+
.sort((left, right) => Date.parse(left.timestamp) - Date.parse(right.timestamp));
|
|
652
|
+
const breadcrumbs = merged.slice(-MAX_ISSUE_BREADCRUMBS);
|
|
653
|
+
const truncated = attributes.breadcrumbsTruncated === true || this.issueBreadcrumbsTruncated
|
|
654
|
+
|| provided.truncated || merged.length > breadcrumbs.length;
|
|
655
|
+
const withBreadcrumbs = breadcrumbs.length === 0
|
|
635
656
|
? attributes
|
|
636
|
-
: {
|
|
637
|
-
...attributes,
|
|
638
|
-
breadcrumbs: this.issueBreadcrumbs,
|
|
639
|
-
...(
|
|
640
|
-
attributes.breadcrumbsTruncated === true || this.issueBreadcrumbsTruncated
|
|
641
|
-
? { breadcrumbsTruncated: true }
|
|
642
|
-
: {}
|
|
643
|
-
)
|
|
644
|
-
};
|
|
657
|
+
: { ...attributes, breadcrumbs, ...(truncated ? { breadcrumbsTruncated: true } : {}) };
|
|
645
658
|
return this.#pushEvent("issue", id, timestamp, validateIssue(withBreadcrumbs));
|
|
646
659
|
}
|
|
647
660
|
|
|
661
|
+
// Provider failures and invalid entries never cost the issue itself.
|
|
662
|
+
#providedBreadcrumbs() {
|
|
663
|
+
let provided;
|
|
664
|
+
try {
|
|
665
|
+
provided = this.breadcrumbProvider?.();
|
|
666
|
+
} catch {
|
|
667
|
+
return { breadcrumbs: [], truncated: false };
|
|
668
|
+
}
|
|
669
|
+
if (!provided || !Array.isArray(provided.breadcrumbs)) {
|
|
670
|
+
return { breadcrumbs: [], truncated: false };
|
|
671
|
+
}
|
|
672
|
+
const breadcrumbs = [];
|
|
673
|
+
let truncated = provided.truncated === true || provided.breadcrumbs.length > MAX_ISSUE_BREADCRUMBS;
|
|
674
|
+
for (const breadcrumb of provided.breadcrumbs.slice(-MAX_ISSUE_BREADCRUMBS)) {
|
|
675
|
+
try {
|
|
676
|
+
breadcrumbs.push(validateIssueBreadcrumb(breadcrumb));
|
|
677
|
+
} catch {
|
|
678
|
+
truncated = true;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return { breadcrumbs, truncated };
|
|
682
|
+
}
|
|
683
|
+
|
|
648
684
|
#pushEvent(eventType, id, timestamp, attributes) {
|
|
649
685
|
if (this.closed) {
|
|
650
686
|
throw new SdkError("shutdown_error", "client is already shut down");
|
package/index.d.ts
CHANGED
|
@@ -886,7 +886,7 @@ export declare class LogBrewClient {
|
|
|
886
886
|
transport?: Transport;
|
|
887
887
|
/** Enable interval and queue-threshold delivery. Defaults to true when transport is supplied. */
|
|
888
888
|
automaticDelivery?: boolean;
|
|
889
|
-
/** One-shot delivery interval in milliseconds. Defaults to
|
|
889
|
+
/** One-shot delivery interval in milliseconds. Defaults to 1000 and must not exceed 60000. */
|
|
890
890
|
deliveryIntervalMs?: number;
|
|
891
891
|
/** Queue count that triggers delivery without waiting for the interval. Defaults to min(50, maxQueueSize). */
|
|
892
892
|
deliveryQueueThreshold?: number;
|