@hue-run/sdk 0.16.0 → 0.18.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/CLI.md +18 -11
- package/EVALUATIONS.md +53 -2
- package/README.md +295 -45
- package/dist/attachment.d.ts +82 -0
- package/dist/attachment.js +225 -0
- package/dist/blobs.d.ts +73 -17
- package/dist/blobs.js +247 -96
- package/dist/cli/eval-direct.d.ts +3 -2
- package/dist/cli/eval-direct.js +49 -6
- package/dist/client.d.ts +21 -1
- package/dist/client.js +217 -32
- package/dist/evals/client.d.ts +14 -1
- package/dist/evals/client.js +73 -9
- package/dist/evals/files.d.ts +11 -1
- package/dist/evals/files.js +172 -20
- package/dist/evals/media.d.ts +217 -0
- package/dist/evals/media.js +907 -0
- package/dist/evals/runner.js +130 -106
- package/dist/evals/types.d.ts +48 -0
- package/dist/evals.d.ts +2 -0
- package/dist/evals.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/inline-files.d.ts +160 -28
- package/dist/inline-files.js +809 -86
- package/dist/json-edits.d.ts +24 -0
- package/dist/json-edits.js +187 -0
- package/dist/privacy.d.ts +14 -1
- package/dist/privacy.js +86 -25
- package/dist/safety.d.ts +7 -2
- package/dist/safety.js +22 -4
- package/dist/snapshot.d.ts +7 -4
- package/dist/snapshot.js +177 -38
- package/dist/transport.d.ts +18 -0
- package/dist/transport.js +544 -38
- package/dist/types.d.ts +28 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/snapshot.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createTraceState } from "@opentelemetry/api";
|
|
2
2
|
import { types as utilTypes } from "node:util";
|
|
3
3
|
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
4
|
-
import { hashInlineFiles,
|
|
4
|
+
import { hashInlineFiles, hashNestedInlineFiles, INLINE_FILE_TEXT_PER_RECORD, MAX_INLINE_FILE_TEXT, isMediaKey, isMessageKey, literalKeys, mayInlineFiles, readingOf, } from "./inline-files.js";
|
|
5
5
|
import { scrubsToolCredentials, scrubToolCredentials } from "./tool-definitions.js";
|
|
6
6
|
import { MAX_RECORD_NODES } from "./config.js";
|
|
7
7
|
import { truncatedMarker } from "./privacy.js";
|
|
@@ -20,6 +20,25 @@ function cutToUnits(value, units) {
|
|
|
20
20
|
// A slice can keep the whole original string alive; the copy holds only what is kept.
|
|
21
21
|
return Buffer.from(value.slice(0, end), "utf16le").toString("utf16le");
|
|
22
22
|
}
|
|
23
|
+
/** Whether a long string may be a file's inline content: a `data:` URL or base64 text. */
|
|
24
|
+
function mayBeFileContent(text) {
|
|
25
|
+
return text.startsWith("data:") || (text.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(text));
|
|
26
|
+
}
|
|
27
|
+
/** Whether a log record is a correlated GenAI event with a structured body, whose media may be
|
|
28
|
+
* uploaded under its trace. */
|
|
29
|
+
function offloadsLogBody(source) {
|
|
30
|
+
const name = source.eventName ?? source.attributes?.["event.name"];
|
|
31
|
+
const body = source.body;
|
|
32
|
+
const traceId = source.spanContext?.traceId;
|
|
33
|
+
return (typeof name === "string" &&
|
|
34
|
+
name.startsWith("gen_ai.") &&
|
|
35
|
+
body !== null &&
|
|
36
|
+
typeof body === "object" &&
|
|
37
|
+
!utilTypes.isUint8Array(body) &&
|
|
38
|
+
typeof traceId === "string" &&
|
|
39
|
+
/^[0-9a-f]{32}$/.test(traceId) &&
|
|
40
|
+
!/^0+$/.test(traceId));
|
|
41
|
+
}
|
|
23
42
|
/** The record's byte or value budget ran out: a span's events and links past it are left out and
|
|
24
43
|
* counted as dropped, where anything else loses the record. */
|
|
25
44
|
class BudgetExceeded extends RangeError {
|
|
@@ -30,6 +49,8 @@ class Snapshot {
|
|
|
30
49
|
captureContent;
|
|
31
50
|
valueUnits;
|
|
32
51
|
hold;
|
|
52
|
+
memo;
|
|
53
|
+
traceId;
|
|
33
54
|
bytes = 512;
|
|
34
55
|
unresolvedResource = false;
|
|
35
56
|
/** The value strings this snapshot cut to `valueUnits`; export recognizes them, so the
|
|
@@ -38,28 +59,48 @@ class Snapshot {
|
|
|
38
59
|
nodes = 0;
|
|
39
60
|
ancestors = new Set();
|
|
40
61
|
copied = new Map();
|
|
62
|
+
attributesCopied = new Map();
|
|
63
|
+
ownAttributesCopied = new Map();
|
|
64
|
+
/** Message texts as the queue copies them, their media as their digest: a span's own, and
|
|
65
|
+
* nested or a log record's (small binary media kept). */
|
|
41
66
|
hashed = new Map();
|
|
67
|
+
nestedHashed = new Map();
|
|
68
|
+
/** Inspected texts as they would be exported with every file as its digest, by how their
|
|
69
|
+
* attribute is read: what the queue is charged for a value held whole for upload. */
|
|
70
|
+
charged = new Map();
|
|
42
71
|
inspected = 0;
|
|
43
72
|
/** Bytes of values held whole for upload, charged to the held-value budget. */
|
|
44
73
|
held = 0;
|
|
45
74
|
/** Set while the span's own attributes are copied: only they may be held for upload. */
|
|
46
75
|
own = false;
|
|
47
|
-
/** The
|
|
76
|
+
/** The own attributes holding literal text, while they are copied. */
|
|
77
|
+
literal = new Set();
|
|
78
|
+
/** Set for a log record: only its inspected attributes' media and its body's are held. */
|
|
79
|
+
log = false;
|
|
80
|
+
/** Set while a GenAI log record's structured body is copied: a long string that may be a
|
|
81
|
+
* file's content is held whole for upload. */
|
|
82
|
+
holdingBody = false;
|
|
83
|
+
/** The span's own messages whose inline media shrank to their digest when queued, by
|
|
48
84
|
* attribute: the text queued (cut or not), and how many files it lost. */
|
|
49
85
|
digested = new Map();
|
|
50
86
|
/** How many files each message text {@link inlineFiles} hashed replaced by their digest. */
|
|
51
87
|
hashedFiles = new Map();
|
|
88
|
+
/** The span's own message attributes inspected within the record's allowance, whether here or
|
|
89
|
+
* left to export for a message held whole: export inspects only these. */
|
|
90
|
+
inspectedKeys = new Set();
|
|
52
91
|
/**
|
|
53
92
|
* In metadata-only mode the recorded messages, which export strips, are not copied at all. A
|
|
54
93
|
* value string (an attribute's, an event's or link's attribute's, a log body or a status
|
|
55
94
|
* message) longer than `valueUnits` is cut to that length: export cuts it to the value cap
|
|
56
95
|
* anyway, and charging it whole could drop the record before that cut ever ran.
|
|
57
96
|
*/
|
|
58
|
-
constructor(limit, captureContent = true, valueUnits = Infinity, hold) {
|
|
97
|
+
constructor(limit, captureContent = true, valueUnits = Infinity, hold, memo, traceId = "") {
|
|
59
98
|
this.limit = limit;
|
|
60
99
|
this.captureContent = captureContent;
|
|
61
100
|
this.valueUnits = valueUnits;
|
|
62
101
|
this.hold = hold;
|
|
102
|
+
this.memo = memo;
|
|
103
|
+
this.traceId = traceId;
|
|
63
104
|
}
|
|
64
105
|
/** Whether the held-value budget takes `bytes` more, charging them when it does. */
|
|
65
106
|
holds(bytes) {
|
|
@@ -74,33 +115,51 @@ class Snapshot {
|
|
|
74
115
|
* longer than the queued value length or bytes over the cap, within the held-value budget, and
|
|
75
116
|
* a recorded message that may inline a large file kept as it is (export uploads the file).
|
|
76
117
|
* Undefined for a value copied as before; text over the length the budget cannot hold is then
|
|
77
|
-
* cut and its
|
|
118
|
+
* cut and its inline media shrink to their digest, as before uploads existed.
|
|
78
119
|
*/
|
|
79
120
|
heldValue(key, value) {
|
|
80
121
|
if (!this.hold || !this.own)
|
|
81
122
|
return undefined;
|
|
82
123
|
if (typeof value === "string") {
|
|
124
|
+
// Literal text (`input.value` declared `text/plain`) is no JSON Hue reads files from: it is
|
|
125
|
+
// never inspected for media, but a span's value over the cap is still held whole to upload.
|
|
126
|
+
const literal = this.literal.has(key);
|
|
127
|
+
// A log record's value is never uploaded whole: only the media in its inspected attributes.
|
|
128
|
+
if (this.log && (literal || !isMediaKey(key)))
|
|
129
|
+
return undefined;
|
|
83
130
|
if (value.length > this.valueUnits) {
|
|
131
|
+
if (this.log && (value.length > MAX_INLINE_FILE_TEXT || !mayInlineFiles(key, value)))
|
|
132
|
+
return undefined;
|
|
84
133
|
// The queue must take the cut the value falls back to, as it would have taken it before.
|
|
85
134
|
const fallback = this.valueUnits * 2 + 16;
|
|
86
135
|
if (this.bytes + fallback > this.limit || !this.holds(value.length * 2))
|
|
87
136
|
return undefined;
|
|
88
137
|
this.charge(fallback);
|
|
138
|
+
// Export parses the held message; its inspection allowance is taken here, in order. A
|
|
139
|
+
// log record's export inspects within its own allowance.
|
|
140
|
+
if (!this.log &&
|
|
141
|
+
!literal &&
|
|
142
|
+
value.length <= MAX_INLINE_FILE_TEXT &&
|
|
143
|
+
mayInlineFiles(key, value) &&
|
|
144
|
+
this.inspected + value.length <= INLINE_FILE_TEXT_PER_RECORD) {
|
|
145
|
+
this.inspected += value.length;
|
|
146
|
+
this.inspectedKeys.add(key);
|
|
147
|
+
}
|
|
89
148
|
return { value };
|
|
90
149
|
}
|
|
91
|
-
// Within the queued length:
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
// their digest when queued, as before uploads existed.
|
|
95
|
-
if (!
|
|
150
|
+
// Within the queued length: an inspected attribute holding inline media is held whole for
|
|
151
|
+
// export to upload the files, within the held-value budget, and the queue is charged its
|
|
152
|
+
// copy with the files as their digest. Past the budget, a recorded message's files shrink to
|
|
153
|
+
// their digest when queued, as before uploads existed; any other value is queued as it is.
|
|
154
|
+
if (!isMediaKey(key) || literal)
|
|
96
155
|
return undefined;
|
|
97
|
-
const digested = this.inlineFiles(key, value);
|
|
156
|
+
const digested = this.inlineFiles(key, value, true);
|
|
98
157
|
if (digested === value || !this.holds(value.length * 2))
|
|
99
158
|
return undefined;
|
|
100
159
|
this.copy(digested, 1, "value", true);
|
|
101
160
|
return { value };
|
|
102
161
|
}
|
|
103
|
-
if (!utilTypes.isUint8Array(value))
|
|
162
|
+
if (this.log || !utilTypes.isUint8Array(value))
|
|
104
163
|
return undefined;
|
|
105
164
|
const length = typedArrayByteLength.call(value);
|
|
106
165
|
// Bytes over Hue's upload limit could only be exported cut: not copied whole for that.
|
|
@@ -119,7 +178,12 @@ class Snapshot {
|
|
|
119
178
|
throw new BudgetExceeded("Telemetry byte budget exceeded");
|
|
120
179
|
}
|
|
121
180
|
mark() {
|
|
122
|
-
return {
|
|
181
|
+
return {
|
|
182
|
+
bytes: this.bytes,
|
|
183
|
+
nodes: this.nodes,
|
|
184
|
+
copied: this.copied.size,
|
|
185
|
+
attributesCopied: this.attributesCopied.size,
|
|
186
|
+
};
|
|
123
187
|
}
|
|
124
188
|
/** Back to `mark`, forgetting the values copied since: a later copy must not reuse a partial
|
|
125
189
|
* copy of an item that was left out. */
|
|
@@ -131,6 +195,10 @@ class Snapshot {
|
|
|
131
195
|
for (const key of [...this.copied.keys()])
|
|
132
196
|
if (index++ >= mark.copied)
|
|
133
197
|
this.copied.delete(key);
|
|
198
|
+
index = 0;
|
|
199
|
+
for (const key of [...this.attributesCopied.keys()])
|
|
200
|
+
if (index++ >= mark.attributesCopied)
|
|
201
|
+
this.attributesCopied.delete(key);
|
|
134
202
|
}
|
|
135
203
|
/**
|
|
136
204
|
* As many of a span's newest `items` (its events or links) as the record's budget still holds,
|
|
@@ -163,7 +231,7 @@ class Snapshot {
|
|
|
163
231
|
return { kept, dropped: count - kept.length };
|
|
164
232
|
}
|
|
165
233
|
/**
|
|
166
|
-
* An attribute map. A
|
|
234
|
+
* An attribute map. A inline media part in a message attribute shrinks to its digest before it
|
|
167
235
|
* is charged: export replaces it anyway, and charging the file could drop the whole record.
|
|
168
236
|
*/
|
|
169
237
|
attributes(value) {
|
|
@@ -172,29 +240,58 @@ class Snapshot {
|
|
|
172
240
|
/** The span's own attribute map, whose values over the cap may be held whole for upload. */
|
|
173
241
|
ownAttributes(value) {
|
|
174
242
|
this.own = true;
|
|
243
|
+
this.literal = literalKeys(value);
|
|
175
244
|
try {
|
|
176
245
|
return this.attributes(value);
|
|
177
246
|
}
|
|
178
247
|
finally {
|
|
179
248
|
this.own = false;
|
|
249
|
+
this.literal = new Set();
|
|
180
250
|
}
|
|
181
251
|
}
|
|
182
|
-
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
252
|
+
/**
|
|
253
|
+
* An attribute with its inline media hashed. As queued (`charge` false), only a recorded message
|
|
254
|
+
* shrinks: a span's own with every binary file and text file over the inline limit as its
|
|
255
|
+
* digest, a nested one's or a log record's keeping small binary media. With `charge`, any
|
|
256
|
+
* inspected attribute as export would place it with every file as its digest, what the queue is
|
|
257
|
+
* charged for a value held whole for upload. Own, nested and charged copies cache separately. A
|
|
258
|
+
* record inspects at most {@link INLINE_FILE_TEXT_PER_RECORD} code units in all; beyond that,
|
|
259
|
+
* values are charged as recorded. Nothing is inspected in metadata-only mode.
|
|
260
|
+
*/
|
|
261
|
+
inlineFiles(key, value, charge = false) {
|
|
262
|
+
if (!this.captureContent ||
|
|
263
|
+
typeof value !== "string" ||
|
|
264
|
+
value.length > MAX_INLINE_FILE_TEXT ||
|
|
265
|
+
!mayInlineFiles(key, value) ||
|
|
266
|
+
(!charge && !isMessageKey(key)))
|
|
188
267
|
return value;
|
|
189
|
-
|
|
190
|
-
|
|
268
|
+
const own = this.own && !this.log;
|
|
269
|
+
// A span's own message is queued as it is charged: one copy serves both.
|
|
270
|
+
const shared = own && isMessageKey(key);
|
|
271
|
+
let hashed;
|
|
272
|
+
if (charge && !shared) {
|
|
273
|
+
const reading = readingOf(key);
|
|
274
|
+
hashed = this.charged.get(reading) ?? new Map();
|
|
275
|
+
this.charged.set(reading, hashed);
|
|
276
|
+
}
|
|
277
|
+
else
|
|
278
|
+
hashed = own ? this.hashed : this.nestedHashed;
|
|
279
|
+
if (hashed.has(value)) {
|
|
280
|
+
if (own)
|
|
281
|
+
this.inspectedKeys.add(key);
|
|
282
|
+
return hashed.get(value);
|
|
283
|
+
}
|
|
191
284
|
if (this.inspected + value.length > INLINE_FILE_TEXT_PER_RECORD)
|
|
192
285
|
return value;
|
|
193
286
|
this.inspected += value.length;
|
|
287
|
+
if (own)
|
|
288
|
+
this.inspectedKeys.add(key);
|
|
194
289
|
const count = { files: 0 };
|
|
195
|
-
const result =
|
|
196
|
-
|
|
197
|
-
|
|
290
|
+
const result = charge || own
|
|
291
|
+
? hashInlineFiles(key, value, count, this.memo, this.traceId, true)
|
|
292
|
+
: hashNestedInlineFiles(key, value);
|
|
293
|
+
hashed.set(value, result);
|
|
294
|
+
if (shared && count.files)
|
|
198
295
|
this.hashedFiles.set(value, count.files);
|
|
199
296
|
return result;
|
|
200
297
|
}
|
|
@@ -240,6 +337,19 @@ class Snapshot {
|
|
|
240
337
|
value(value, depth = 1) {
|
|
241
338
|
return this.copy(value, depth, "value", true);
|
|
242
339
|
}
|
|
340
|
+
/** A GenAI log record's structured body: strings are cut to the queued value length as in
|
|
341
|
+
* {@link value}, except that a longer string that may be a file's content (a `data:` URL or
|
|
342
|
+
* base64) within the inspection limit is held whole for export to upload, within the
|
|
343
|
+
* held-value budget, the queue charged what its cut would have cost. */
|
|
344
|
+
heldBody(value) {
|
|
345
|
+
this.holdingBody = this.hold !== undefined;
|
|
346
|
+
try {
|
|
347
|
+
return this.copy(value, 1, "value", true);
|
|
348
|
+
}
|
|
349
|
+
finally {
|
|
350
|
+
this.holdingBody = false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
243
353
|
copy(value, depth = 0, shape = "value", content = false) {
|
|
244
354
|
if (++this.nodes > MAX_RECORD_NODES)
|
|
245
355
|
throw new BudgetExceeded("Telemetry complexity limit exceeded");
|
|
@@ -249,6 +359,13 @@ class Snapshot {
|
|
|
249
359
|
if (typeof value === "string") {
|
|
250
360
|
let text = value;
|
|
251
361
|
if (content && text.length > this.valueUnits) {
|
|
362
|
+
if (this.holdingBody && text.length <= MAX_INLINE_FILE_TEXT && mayBeFileContent(text)) {
|
|
363
|
+
const fallback = this.valueUnits * 2 + 16;
|
|
364
|
+
if (this.bytes + fallback <= this.limit && this.holds(text.length * 2)) {
|
|
365
|
+
this.charge(fallback);
|
|
366
|
+
return text;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
252
369
|
text = cutToUnits(text, this.valueUnits);
|
|
253
370
|
this.cut.add(text);
|
|
254
371
|
}
|
|
@@ -266,8 +383,15 @@ class Snapshot {
|
|
|
266
383
|
throw new TypeError("Telemetry proxies are unsupported");
|
|
267
384
|
if (this.ancestors.has(value))
|
|
268
385
|
throw new TypeError("Cyclic telemetry value");
|
|
269
|
-
|
|
270
|
-
|
|
386
|
+
// One object can be reused as own attributes, nested attributes and an ordinary log body.
|
|
387
|
+
// Their copies differ: only attributes inspect media, and only own attributes upload it.
|
|
388
|
+
const copies = shape === "attributes"
|
|
389
|
+
? this.own
|
|
390
|
+
? this.ownAttributesCopied
|
|
391
|
+
: this.attributesCopied
|
|
392
|
+
: this.copied;
|
|
393
|
+
if (copies.has(value))
|
|
394
|
+
return copies.get(value);
|
|
271
395
|
if (utilTypes.isUint8Array(value)) {
|
|
272
396
|
// Own accessors/subclasses cannot disguise the retained byte count.
|
|
273
397
|
// A length-tracking SharedArrayBuffer view can grow on another thread
|
|
@@ -277,14 +401,14 @@ class Snapshot {
|
|
|
277
401
|
this.charge(length);
|
|
278
402
|
const copy = new Uint8Array(length);
|
|
279
403
|
typedArraySet.call(copy, value);
|
|
280
|
-
|
|
404
|
+
copies.set(value, copy);
|
|
281
405
|
return copy;
|
|
282
406
|
}
|
|
283
407
|
const array = Array.isArray(value);
|
|
284
408
|
if (!array && ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
285
409
|
throw new TypeError("Telemetry must contain data objects");
|
|
286
410
|
const copy = array ? [] : Object.create(null);
|
|
287
|
-
|
|
411
|
+
copies.set(value, copy);
|
|
288
412
|
this.ancestors.add(value);
|
|
289
413
|
if (array) {
|
|
290
414
|
if (value.length > MAX_RECORD_NODES)
|
|
@@ -316,9 +440,13 @@ class Snapshot {
|
|
|
316
440
|
? this.scrubbedBeforeCut(key, this.inlineFiles(key, source))
|
|
317
441
|
: source, depth + 1, shape === "event" && key === "attributes" ? "attributes" : "value", content || shape === "attributes");
|
|
318
442
|
copy[key] = copied;
|
|
319
|
-
// A span's own message whose
|
|
443
|
+
// A span's own message whose inline media shrank to their digest is named as it
|
|
320
444
|
// was queued, cut or not, so export reports each file as not uploaded.
|
|
321
|
-
const files = this.own &&
|
|
445
|
+
const files = this.own &&
|
|
446
|
+
!this.log &&
|
|
447
|
+
shape === "attributes" &&
|
|
448
|
+
typeof source === "string" &&
|
|
449
|
+
isMessageKey(key)
|
|
322
450
|
? this.hashedFiles.get(source)
|
|
323
451
|
: undefined;
|
|
324
452
|
if (files && typeof copied === "string")
|
|
@@ -360,7 +488,7 @@ class Snapshot {
|
|
|
360
488
|
if (value == null || Object.hasOwn(attributes, key))
|
|
361
489
|
continue;
|
|
362
490
|
this.charge(key.length * 2 + 16);
|
|
363
|
-
attributes[key] = this.copy(this.scrubbedBeforeCut(key, value), 0, "value", true);
|
|
491
|
+
attributes[key] = this.copy(this.scrubbedBeforeCut(key, this.inlineFiles(key, value)), 0, "value", true);
|
|
364
492
|
}
|
|
365
493
|
return resourceFromAttributes(attributes, { schemaUrl: this.copy(source.schemaUrl) });
|
|
366
494
|
}
|
|
@@ -368,8 +496,8 @@ class Snapshot {
|
|
|
368
496
|
function contextReader(context) {
|
|
369
497
|
return () => context;
|
|
370
498
|
}
|
|
371
|
-
export function snapshotSpan(source, limit, captureContent = true, valueUnits = Infinity, hold) {
|
|
372
|
-
const snapshot = new Snapshot(limit, captureContent, valueUnits, hold);
|
|
499
|
+
export function snapshotSpan(source, limit, captureContent = true, valueUnits = Infinity, hold, memo) {
|
|
500
|
+
const snapshot = new Snapshot(limit, captureContent, valueUnits, hold, memo, source.spanContext().traceId);
|
|
373
501
|
const context = snapshot.context(source.spanContext());
|
|
374
502
|
const fields = snapshot.copy({
|
|
375
503
|
name: source.name,
|
|
@@ -416,10 +544,16 @@ export function snapshotSpan(source, limit, captureContent = true, valueUnits =
|
|
|
416
544
|
cut: snapshot.cut,
|
|
417
545
|
held: snapshot.held,
|
|
418
546
|
digested: snapshot.digested,
|
|
547
|
+
inspected: snapshot.inspectedKeys,
|
|
419
548
|
};
|
|
420
549
|
}
|
|
421
|
-
export function snapshotLog(source, limit, captureContent = true, valueUnits = Infinity) {
|
|
422
|
-
|
|
550
|
+
export function snapshotLog(source, limit, captureContent = true, valueUnits = Infinity, hold, memo) {
|
|
551
|
+
// A log record's media upload under its own trace: an uncorrelated record holds none.
|
|
552
|
+
const traceId = source.spanContext?.traceId;
|
|
553
|
+
const correlated = typeof traceId === "string" && /^[0-9a-f]{32}$/.test(traceId) && !/^0+$/.test(traceId);
|
|
554
|
+
const holding = correlated ? hold : undefined;
|
|
555
|
+
const snapshot = new Snapshot(limit, captureContent, valueUnits, holding, memo, traceId ?? "");
|
|
556
|
+
snapshot.log = true;
|
|
423
557
|
// Only our batching processor sees this copy. Its writer methods deliberately
|
|
424
558
|
// cannot mutate the admitted snapshot or invalidate its charged byte count.
|
|
425
559
|
const record = {
|
|
@@ -432,8 +566,12 @@ export function snapshotLog(source, limit, captureContent = true, valueUnits = I
|
|
|
432
566
|
instrumentationScope: source.instrumentationScope,
|
|
433
567
|
droppedAttributesCount: source.droppedAttributesCount,
|
|
434
568
|
}),
|
|
435
|
-
body:
|
|
436
|
-
|
|
569
|
+
body: holding && captureContent && offloadsLogBody(source)
|
|
570
|
+
? snapshot.heldBody(source.body)
|
|
571
|
+
: snapshot.value(source.body),
|
|
572
|
+
attributes: holding
|
|
573
|
+
? snapshot.ownAttributes(source.attributes)
|
|
574
|
+
: snapshot.attributes(source.attributes),
|
|
437
575
|
spanContext: snapshot.context(source.spanContext),
|
|
438
576
|
resource: snapshot.resource(source.resource),
|
|
439
577
|
setAttribute() {
|
|
@@ -460,7 +598,8 @@ export function snapshotLog(source, limit, captureContent = true, valueUnits = I
|
|
|
460
598
|
bytes: snapshot.bytes,
|
|
461
599
|
unresolvedResource: snapshot.unresolvedResource,
|
|
462
600
|
cut: snapshot.cut,
|
|
463
|
-
held:
|
|
601
|
+
held: snapshot.held,
|
|
464
602
|
digested: new Map(),
|
|
603
|
+
inspected: new Set(),
|
|
465
604
|
};
|
|
466
605
|
}
|
package/dist/transport.d.ts
CHANGED
|
@@ -79,11 +79,19 @@ export declare class HueTransport {
|
|
|
79
79
|
private holdsReleased;
|
|
80
80
|
private admissionCuts;
|
|
81
81
|
private admissionDigests;
|
|
82
|
+
private admissionInspected;
|
|
82
83
|
/** Uploads values over the inline limit apart from their spans; absent when disabled. */
|
|
83
84
|
private uploader?;
|
|
84
85
|
/** Bytes of values over the inline limit queued spans hold whole for upload, and each span's. */
|
|
85
86
|
private heldBytes;
|
|
86
87
|
private held;
|
|
88
|
+
private mediaMemo;
|
|
89
|
+
private media;
|
|
90
|
+
private logParts;
|
|
91
|
+
private logMedia;
|
|
92
|
+
private mediaOwners;
|
|
93
|
+
private mediaTimer?;
|
|
94
|
+
private mediaFinalizer;
|
|
87
95
|
private uploaded;
|
|
88
96
|
private uploadFallbacks;
|
|
89
97
|
constructor(options: HueOptions);
|
|
@@ -98,6 +106,16 @@ export declare class HueTransport {
|
|
|
98
106
|
private announceLiveSpans;
|
|
99
107
|
private stopLiveTimer;
|
|
100
108
|
private stopLiveSpans;
|
|
109
|
+
/** Holds the staged attachments of a log record being admitted with the queued record, within
|
|
110
|
+
* the held-value budget; those the budget refuses are counted as not uploaded. */
|
|
111
|
+
private admitLogParts;
|
|
112
|
+
/** Registers a span whose staged files are released if it is never exported. */
|
|
113
|
+
private ownMedia;
|
|
114
|
+
private mediaIdentity;
|
|
115
|
+
private releaseMedia;
|
|
116
|
+
private protectMedia;
|
|
117
|
+
private releaseMediaIdentity;
|
|
118
|
+
private sweepMedia;
|
|
101
119
|
/** Bounded: a trace whose root never arrives (an abandoned run) gives way to newer ones. */
|
|
102
120
|
private countDropped;
|
|
103
121
|
/** Cumulative counters and current queue gauges. */
|