@logbrew/sdk 0.1.38 → 0.1.39

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.
Files changed (90) hide show
  1. package/automatic-delivery.cjs +271 -0
  2. package/batch-sender.cjs +164 -0
  3. package/bounded-number.cjs +34 -0
  4. package/browser-breadcrumbs.cjs +346 -136
  5. package/capture-support.cjs +100 -0
  6. package/client-options.cjs +292 -0
  7. package/client-report.cjs +232 -0
  8. package/client.cjs +447 -0
  9. package/console-arguments.cjs +151 -0
  10. package/console-capture.cjs +194 -0
  11. package/core.cjs +30 -2810
  12. package/delivery-health.cjs +133 -0
  13. package/error-causes.cjs +130 -0
  14. package/error-details.cjs +124 -0
  15. package/error-issue.cjs +187 -0
  16. package/event-clone.cjs +55 -0
  17. package/event-metadata.cjs +40 -0
  18. package/event-pipeline.cjs +325 -0
  19. package/event-queue.cjs +306 -0
  20. package/event-store.cjs +237 -0
  21. package/event-validation.cjs +159 -0
  22. package/examples/agent-timeline.cjs +57 -46
  23. package/examples/agent-timeline.mjs +41 -35
  24. package/examples/index.mjs +122 -94
  25. package/examples/readme-example.cjs +36 -27
  26. package/examples/readme-example.mjs +21 -17
  27. package/examples/real-user-smoke.cjs +41 -32
  28. package/examples/real-user-smoke.mjs +26 -22
  29. package/exception-chain.cjs +205 -0
  30. package/index.d.ts +144 -1076
  31. package/index.js +1 -1
  32. package/issue-exception.cjs +13 -8
  33. package/metric-validation.cjs +95 -0
  34. package/network-milestone.cjs +155 -0
  35. package/null-value.cjs +4 -0
  36. package/opentelemetry-bridge.cjs +330 -0
  37. package/opentelemetry-context.cjs +245 -0
  38. package/opentelemetry-exceptions.cjs +69 -0
  39. package/opentelemetry-keys.cjs +183 -0
  40. package/opentelemetry-span.cjs +286 -0
  41. package/opentelemetry-summary.cjs +213 -0
  42. package/opentelemetry-time.cjs +131 -0
  43. package/opentelemetry.cjs +99 -1068
  44. package/package.json +55 -1
  45. package/pino-destination.cjs +108 -0
  46. package/pino-record.cjs +237 -0
  47. package/product-action.cjs +163 -0
  48. package/provided-breadcrumbs.cjs +117 -0
  49. package/random-hex.cjs +29 -0
  50. package/react-native.js +1 -1
  51. package/recording-transport.cjs +68 -0
  52. package/release-artifacts-build.cjs +263 -84
  53. package/release-artifacts-common.js +347 -66
  54. package/release-artifacts-debug-id.js +178 -0
  55. package/release-artifacts-inspect.js +213 -0
  56. package/release-artifacts-issue-event.js +99 -0
  57. package/release-artifacts-manifest-artifact.js +107 -0
  58. package/release-artifacts-manifest.js +77 -0
  59. package/release-artifacts-mappings.js +265 -0
  60. package/release-artifacts-prepare.js +297 -0
  61. package/release-artifacts-source-context.js +210 -0
  62. package/release-artifacts-symbolication.js +272 -421
  63. package/release-artifacts-upload-files.js +122 -0
  64. package/release-artifacts-upload-request.js +246 -0
  65. package/release-artifacts-upload.js +155 -300
  66. package/release-artifacts-urls.js +49 -0
  67. package/release-artifacts.js +189 -662
  68. package/retry-delay.cjs +32 -0
  69. package/span-validation.cjs +191 -0
  70. package/stored-events.cjs +243 -0
  71. package/types/client.d.ts +67 -0
  72. package/types/delivery.d.ts +125 -0
  73. package/types/issues.d.ts +249 -0
  74. package/types/logging.d.ts +175 -0
  75. package/types/opentelemetry.d.ts +205 -0
  76. package/types/product.d.ts +128 -0
  77. package/types/recording-transport.d.ts +15 -0
  78. package/types/sdk-error.d.ts +9 -0
  79. package/types/telemetry.d.ts +171 -0
  80. package/types/trace-context.d.ts +110 -0
  81. package/types/transport-error.d.ts +10 -0
  82. package/utf8.cjs +37 -0
  83. package/validation.cjs +49 -1
  84. package/vite-release-artifacts-config.cjs +120 -0
  85. package/vite-release-artifacts.cjs +199 -99
  86. package/vite-release-artifacts.d.cts +65 -40
  87. package/vite-release-artifacts.d.ts +65 -40
  88. package/vite-release-artifacts.js +2 -2
  89. package/winston-info.cjs +205 -0
  90. package/winston.cjs +189 -289
@@ -0,0 +1,245 @@
1
+ const { NULL_VALUE } = require("./null-value.cjs");
2
+ const { SdkError } = require("./sdk-error.cjs");
3
+ const {
4
+ ZERO_SPAN_ID,
5
+ isObjectValue,
6
+ optionalProperty,
7
+ requireSpanId,
8
+ requireTraceId
9
+ } = require("./validation.cjs");
10
+
11
+ /**
12
+ * @import { LogCorrelationTraceContext } from "./index.cjs"
13
+ * @typedef {{ traceId: string, spanId: string, sampled: boolean }} SpanContextIds
14
+ * @typedef {Readonly<{ spanId?: unknown, spanIdFactory?: unknown }>} ChildSpanOptions
15
+ */
16
+
17
+ const SPAN_ID_BYTES = 8;
18
+ const MAX_SPAN_ID_ATTEMPTS = 3;
19
+ const FIRST_ATTEMPT = 0;
20
+ const ATTEMPT_STEP = 1;
21
+ const BYTE_VALUES = 256;
22
+ const HEX_RADIX = 16;
23
+ const HEX_BYTE_WIDTH = 2;
24
+ const SAMPLED_BIT_BASE = 2;
25
+ const SAMPLED_BIT = 1;
26
+ const OPENTELEMETRY_API_PACKAGE = "@opentelemetry/api";
27
+
28
+ /**
29
+ * @param {unknown} traceId
30
+ * @returns {string | undefined}
31
+ */
32
+ function normalizeTraceId(traceId) {
33
+ try {
34
+ return requireTraceId(traceId).toLowerCase();
35
+ } catch {
36
+ return undefined;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @param {unknown} spanId
42
+ * @returns {string | undefined}
43
+ */
44
+ function normalizeSpanId(spanId) {
45
+ try {
46
+ return requireSpanId("trace spanId", spanId).toLowerCase();
47
+ } catch {
48
+ return undefined;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @param {unknown} traceFlags
54
+ * @returns {boolean}
55
+ */
56
+ function openTelemetryTraceFlagsSampled(traceFlags) {
57
+ const sampled = optionalProperty(traceFlags, "sampled");
58
+ if (typeof sampled === "boolean") {
59
+ return sampled;
60
+ }
61
+ if (typeof traceFlags === "number" && Number.isFinite(traceFlags)) {
62
+ return Math.abs(Math.trunc(traceFlags) % SAMPLED_BIT_BASE) === SAMPLED_BIT;
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * @param {unknown} spanContext
69
+ * @returns {SpanContextIds | undefined}
70
+ */
71
+ function normalizeOpenTelemetrySpanContextIds(spanContext) {
72
+ if (!isObjectValue(spanContext) || spanContext["isValid"] === false) {
73
+ return undefined;
74
+ }
75
+ const traceId = normalizeTraceId(spanContext["traceId"]);
76
+ const spanId = normalizeSpanId(spanContext["spanId"]);
77
+ if (traceId === undefined || spanId === undefined) {
78
+ return undefined;
79
+ }
80
+ return {
81
+ traceId,
82
+
83
+ spanId,
84
+
85
+ sampled: openTelemetryTraceFlagsSampled(spanContext["traceFlags"])
86
+ };
87
+ }
88
+
89
+ /**
90
+ * @param {number} byteLength
91
+ * @returns {string}
92
+ */
93
+ function randomHex(byteLength) {
94
+ const bytes = new Uint8Array(byteLength);
95
+ const crypto = optionalProperty(globalThis, "crypto");
96
+ const getRandomValues = optionalProperty(crypto, "getRandomValues");
97
+ if (typeof getRandomValues === "function") {
98
+ Reflect.apply(getRandomValues, crypto, [bytes]);
99
+ } else {
100
+ for (const index of bytes.keys()) {
101
+ bytes[index] = Math.floor(Math.random() * BYTE_VALUES);
102
+ }
103
+ }
104
+ return Array.from(bytes, (byte) => byte.toString(HEX_RADIX).padStart(HEX_BYTE_WIDTH, "0")).join("");
105
+ }
106
+
107
+ /**
108
+ * @returns {string}
109
+ */
110
+ function defaultSpanIdFactory() {
111
+ for (let attempt = FIRST_ATTEMPT; attempt < MAX_SPAN_ID_ATTEMPTS; attempt += ATTEMPT_STEP) {
112
+ const spanId = randomHex(SPAN_ID_BYTES);
113
+ if (spanId !== ZERO_SPAN_ID) {
114
+ return spanId;
115
+ }
116
+ }
117
+ throw new SdkError("configuration_error", "spanIdFactory must return a non-zero 16-character hex span id");
118
+ }
119
+
120
+ /**
121
+ * @param {ChildSpanOptions} [options]
122
+ * @returns {string}
123
+ */
124
+ function resolveLogBrewChildSpanId(options = {}) {
125
+ const explicitSpanId = options.spanId;
126
+ if (explicitSpanId !== undefined) {
127
+ return requireSpanId("spanId", explicitSpanId).toLowerCase();
128
+ }
129
+ const { spanIdFactory } = options;
130
+ /** @type {unknown} */
131
+ const spanId = typeof spanIdFactory === "function"
132
+ ? Reflect.apply(spanIdFactory, undefined, [])
133
+ : defaultSpanIdFactory();
134
+ return requireSpanId("spanId", spanId).toLowerCase();
135
+ }
136
+
137
+ /**
138
+ * @param {unknown} method
139
+ * @param {unknown} thisArg
140
+ * @returns {{ value: unknown } | undefined}
141
+ */
142
+ function callWithoutArguments(method, thisArg) {
143
+ if (typeof method !== "function") {
144
+ return undefined;
145
+ }
146
+ try {
147
+ return { value: Reflect.apply(method, thisArg, []) };
148
+ } catch {
149
+ return undefined;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * @param {unknown} spanContext
155
+ * @param {ChildSpanOptions} [options]
156
+ * @returns {LogCorrelationTraceContext | null}
157
+ */
158
+ function logbrewTraceContextFromOpenTelemetrySpanContext(spanContext, options = {}) {
159
+ const context = normalizeOpenTelemetrySpanContextIds(spanContext);
160
+ if (context === undefined) {
161
+ return NULL_VALUE;
162
+ }
163
+ return {
164
+ traceId: context.traceId,
165
+
166
+ spanId: resolveLogBrewChildSpanId(options),
167
+
168
+ parentSpanId: context.spanId,
169
+ sampled: context.sampled
170
+ };
171
+ }
172
+
173
+ /**
174
+ * @param {unknown} span
175
+ * @param {ChildSpanOptions} [options]
176
+ * @returns {LogCorrelationTraceContext | null}
177
+ */
178
+ function logbrewTraceContextFromOpenTelemetrySpan(span, options = {}) {
179
+ if (!isObjectValue(span)) {
180
+ return NULL_VALUE;
181
+ }
182
+ const getSpanContext = typeof span["spanContext"] === "function"
183
+ ? span["spanContext"]
184
+ : span["getSpanContext"];
185
+ const spanContext = callWithoutArguments(getSpanContext, span);
186
+ if (spanContext === undefined) {
187
+ return NULL_VALUE;
188
+ }
189
+ return logbrewTraceContextFromOpenTelemetrySpanContext(spanContext.value, options);
190
+ }
191
+
192
+ /**
193
+ * @returns {((id: string) => unknown) | undefined}
194
+ */
195
+ function optionalRequire() {
196
+ /** @type {unknown} */
197
+ const moduleRequire = typeof module === "undefined" ? undefined : Reflect.get(module, "require");
198
+ if (typeof moduleRequire === "function") {
199
+ return (id) => {
200
+ /** @type {unknown} */
201
+ const required = Reflect.apply(moduleRequire, module, [id]);
202
+ return required;
203
+ };
204
+ }
205
+ return typeof require === "function" ? require : undefined;
206
+ }
207
+
208
+ /**
209
+ * @returns {unknown}
210
+ */
211
+ function optionalOpenTelemetryApi() {
212
+ const requireOptional = optionalRequire();
213
+ if (requireOptional === undefined) {
214
+ return undefined;
215
+ }
216
+ try {
217
+ return requireOptional(OPENTELEMETRY_API_PACKAGE);
218
+ } catch {
219
+ return undefined;
220
+ }
221
+ }
222
+
223
+ /**
224
+ * @param {ChildSpanOptions} [options]
225
+ * @returns {LogCorrelationTraceContext | null}
226
+ */
227
+ function logbrewTraceContextFromCurrentOpenTelemetrySpan(options = {}) {
228
+ const openTelemetryApi = optionalProperty(options, "openTelemetryApi") ?? optionalOpenTelemetryApi();
229
+ const trace = optionalProperty(openTelemetryApi, "trace");
230
+ const getActiveSpan = optionalProperty(trace, "getActiveSpan");
231
+ const activeSpan = callWithoutArguments(getActiveSpan, trace);
232
+ if (activeSpan === undefined) {
233
+ return NULL_VALUE;
234
+ }
235
+ return logbrewTraceContextFromOpenTelemetrySpan(activeSpan.value, options);
236
+ }
237
+
238
+ module.exports = {
239
+ defaultSpanIdFactory,
240
+ logbrewTraceContextFromCurrentOpenTelemetrySpan,
241
+ logbrewTraceContextFromOpenTelemetrySpan,
242
+ logbrewTraceContextFromOpenTelemetrySpanContext,
243
+ normalizeOpenTelemetrySpanContextIds,
244
+ normalizeSpanId
245
+ };
@@ -0,0 +1,69 @@
1
+ const { isList, isRecord, optionalProperty } = require("./validation.cjs");
2
+
3
+ /**
4
+ * @import { Metadata } from "./index.cjs"
5
+ */
6
+
7
+ const MAX_EXCEPTION_TYPES = 8;
8
+ const NO_EXCEPTIONS = 0;
9
+ const EXCEPTION_TYPE_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$:.]{0,127}$/u;
10
+
11
+ /**
12
+ * @param {unknown} value
13
+ * @returns {string | undefined}
14
+ */
15
+ function safeOpenTelemetryExceptionType(value) {
16
+ return typeof value === "string" && EXCEPTION_TYPE_PATTERN.test(value) ? value : undefined;
17
+ }
18
+
19
+ class OpenTelemetryExceptionSummary {
20
+ count = NO_EXCEPTIONS;
21
+ escapedCount = NO_EXCEPTIONS;
22
+ /** @type {string[]} */
23
+ types = [];
24
+
25
+ /**
26
+ * @param {Readonly<Record<string, unknown>>} event
27
+ * @returns {void}
28
+ */
29
+ add(event) {
30
+ this.count += 1;
31
+ if (optionalProperty(event["attributes"], "exception.escaped") === true) {
32
+ this.escapedCount += 1;
33
+ }
34
+ const type = safeOpenTelemetryExceptionType(optionalProperty(event["attributes"], "exception.type"));
35
+ if (type !== undefined && !this.types.includes(type) && this.types.length < MAX_EXCEPTION_TYPES) {
36
+ this.types.push(type);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @returns {Metadata}
42
+ */
43
+ metadata() {
44
+ return {
45
+ "otel.exception_event_count": this.count,
46
+ ...(this.escapedCount > NO_EXCEPTIONS ? { "otel.exception_escaped_count": this.escapedCount } : {}),
47
+ ...(this.types.length > NO_EXCEPTIONS ? { "otel.exception_types": this.types.join(",") } : {})
48
+ };
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @param {unknown} events
54
+ * @returns {OpenTelemetryExceptionSummary | undefined}
55
+ */
56
+ function openTelemetryExceptionEventSummary(events) {
57
+ if (!isList(events) || events.length === NO_EXCEPTIONS) {
58
+ return undefined;
59
+ }
60
+ const summary = new OpenTelemetryExceptionSummary();
61
+ for (const event of events) {
62
+ if (isRecord(event) && event["name"] === "exception") {
63
+ summary.add(event);
64
+ }
65
+ }
66
+ return summary.count > NO_EXCEPTIONS ? summary : undefined;
67
+ }
68
+
69
+ module.exports = { openTelemetryExceptionEventSummary, safeOpenTelemetryExceptionType };
@@ -0,0 +1,183 @@
1
+ const { compactMetadata, isMetadataValue } = require("./log-context.cjs");
2
+ const { SdkError } = require("./sdk-error.cjs");
3
+ const { isList, isRecord, requireNonEmpty } = require("./validation.cjs");
4
+
5
+ /**
6
+ * @import { Metadata } from "./index.cjs"
7
+ * @typedef {Readonly<ReadonlySet<string>>} KeySet
8
+ * @typedef {Readonly<{
9
+ * attributeKeys?: unknown,
10
+ * captureUnsampled?: unknown,
11
+ * eventAttributeKeys?: unknown,
12
+ * includeSpanEvents?: unknown,
13
+ * includeSpanLinks?: unknown,
14
+ * linkAttributeKeys?: unknown,
15
+ * metadata?: unknown,
16
+ * resourceAttributeKeys?: unknown
17
+ * }>} ReadableSpanOptions
18
+ * @typedef {Readonly<{
19
+ * attributeKeys: KeySet,
20
+ * captureUnsampled: boolean,
21
+ * eventAttributeKeys: KeySet,
22
+ * includeSpanEvents: boolean,
23
+ * includeSpanLinks: boolean,
24
+ * linkAttributeKeys: KeySet,
25
+ * metadata: Readonly<Metadata>,
26
+ * resourceAttributeKeys: KeySet
27
+ * }>} ResolvedSpanOptions
28
+ */
29
+
30
+ const SPAN_ATTRIBUTE_KEYS = [
31
+ "db.operation.name",
32
+ "db.system",
33
+ "faas.trigger",
34
+ "graphql.operation.name",
35
+ "graphql.operation.type",
36
+ "http.method",
37
+ "http.request.method",
38
+ "http.response.status_code",
39
+ "http.route",
40
+ "http.status_code",
41
+ "messaging.operation.name",
42
+ "messaging.system",
43
+ "rpc.method",
44
+ "rpc.service",
45
+ "rpc.system"
46
+ ];
47
+ const RESOURCE_ATTRIBUTE_KEYS = [
48
+ "deployment.environment",
49
+ "deployment.environment.name",
50
+ "service.name",
51
+ "service.version",
52
+ "telemetry.sdk.language",
53
+ "telemetry.sdk.name",
54
+ "telemetry.sdk.version"
55
+ ];
56
+ /** @type {KeySet} */
57
+ const DEFAULT_SPAN_ATTRIBUTE_KEYS = new Set(SPAN_ATTRIBUTE_KEYS);
58
+ /** @type {KeySet} */
59
+ const DEFAULT_RESOURCE_ATTRIBUTE_KEYS = new Set(RESOURCE_ATTRIBUTE_KEYS);
60
+ /** @type {KeySet} */
61
+ const DEFAULT_EVENT_ATTRIBUTE_KEYS = new Set(["exception.escaped", "exception.type"]);
62
+ /** @type {KeySet} */
63
+ const DEFAULT_LINK_ATTRIBUTE_KEYS = new Set();
64
+ /** @type {KeySet} */
65
+ const TRACE_SUMMARY_METADATA_KEYS = new Set([...RESOURCE_ATTRIBUTE_KEYS, ...SPAN_ATTRIBUTE_KEYS]);
66
+ /** @type {KeySet} */
67
+ const SENSITIVE_OTEL_ATTRIBUTE_KEYS = new Set([
68
+ "code.stacktrace",
69
+ "db.statement",
70
+ "exception.message",
71
+ "exception.stacktrace",
72
+ "http.request.body",
73
+ "http.response.body",
74
+ "http.url",
75
+ "url.full"
76
+ ]);
77
+ const SENSITIVE_OTEL_ATTRIBUTE_PREFIXES = ["http.request.header.", "http.response.header."];
78
+ const SENSITIVE_OTEL_ATTRIBUTE_PATTERN = /(?:^|[._-])(?:authorization|body|cookie|credential|fragment|header|headers|payload|password|passwd|private[-_]?key|query|secret|stack|stacktrace|token)(?:[._-]|$)/iu;
79
+
80
+ /**
81
+ * @param {string} key
82
+ * @returns {boolean}
83
+ */
84
+ function isSensitiveOpenTelemetryAttributeKey(key) {
85
+ if (SENSITIVE_OTEL_ATTRIBUTE_KEYS.has(key)) {
86
+ return true;
87
+ }
88
+ if (SENSITIVE_OTEL_ATTRIBUTE_PREFIXES.some((prefix) => key.startsWith(prefix))) {
89
+ return true;
90
+ }
91
+ return SENSITIVE_OTEL_ATTRIBUTE_PATTERN.test(key);
92
+ }
93
+
94
+ /**
95
+ * @param {string} label
96
+ * @param {unknown} extraKey
97
+ * @returns {string}
98
+ */
99
+ function allowedExtraKey(label, extraKey) {
100
+ const key = requireNonEmpty(label, extraKey);
101
+ if (isSensitiveOpenTelemetryAttributeKey(key)) {
102
+ throw new SdkError("validation_error", `${label} cannot include sensitive key: ${key}`);
103
+ }
104
+ return key;
105
+ }
106
+
107
+ /**
108
+ * @param {KeySet} defaultKeys
109
+ * @param {unknown} extraKeys
110
+ * @param {string} label
111
+ * @returns {KeySet}
112
+ */
113
+ function openTelemetryAttributeKeySet(defaultKeys, extraKeys, label) {
114
+ const allowedKeys = new Set(defaultKeys);
115
+ if (extraKeys === undefined) {
116
+ return allowedKeys;
117
+ }
118
+ if (!isList(extraKeys)) {
119
+ throw new SdkError("validation_error", `${label} must be an array`);
120
+ }
121
+ for (const extraKey of extraKeys) {
122
+ allowedKeys.add(allowedExtraKey(label, extraKey));
123
+ }
124
+ return allowedKeys;
125
+ }
126
+
127
+ /**
128
+ * @param {ReadableSpanOptions} [options]
129
+ * @returns {ResolvedSpanOptions}
130
+ */
131
+ function resolveOpenTelemetryReadableSpanOptions(options = {}) {
132
+ return {
133
+ attributeKeys: openTelemetryAttributeKeySet(
134
+ DEFAULT_SPAN_ATTRIBUTE_KEYS,
135
+ options.attributeKeys,
136
+ "OpenTelemetry attributeKeys"
137
+ ),
138
+ captureUnsampled: options.captureUnsampled === true,
139
+ eventAttributeKeys: openTelemetryAttributeKeySet(
140
+ DEFAULT_EVENT_ATTRIBUTE_KEYS,
141
+ options.eventAttributeKeys,
142
+ "OpenTelemetry eventAttributeKeys"
143
+ ),
144
+ includeSpanEvents: options.includeSpanEvents !== false,
145
+ includeSpanLinks: options.includeSpanLinks !== false,
146
+ linkAttributeKeys: openTelemetryAttributeKeySet(
147
+ DEFAULT_LINK_ATTRIBUTE_KEYS,
148
+ options.linkAttributeKeys,
149
+ "OpenTelemetry linkAttributeKeys"
150
+ ),
151
+ metadata: compactMetadata(options.metadata),
152
+ resourceAttributeKeys: openTelemetryAttributeKeySet(
153
+ DEFAULT_RESOURCE_ATTRIBUTE_KEYS,
154
+ options.resourceAttributeKeys,
155
+ "OpenTelemetry resourceAttributeKeys"
156
+ )
157
+ };
158
+ }
159
+
160
+ /**
161
+ * @param {unknown} attributes
162
+ * @param {KeySet} allowedKeys
163
+ * @returns {Metadata}
164
+ */
165
+ function openTelemetrySelectedMetadata(attributes, allowedKeys) {
166
+ /** @type {Metadata} */
167
+ const metadata = {};
168
+ if (!isRecord(attributes)) {
169
+ return metadata;
170
+ }
171
+ for (const [key, value] of Object.entries(attributes)) {
172
+ if (allowedKeys.has(key) && !isSensitiveOpenTelemetryAttributeKey(key) && isMetadataValue(value)) {
173
+ metadata[key] = value;
174
+ }
175
+ }
176
+ return metadata;
177
+ }
178
+
179
+ module.exports = {
180
+ TRACE_SUMMARY_METADATA_KEYS,
181
+ openTelemetrySelectedMetadata,
182
+ resolveOpenTelemetryReadableSpanOptions
183
+ };