UNPKG

@sentry/core

Version:
162 lines (150 loc) 5.62 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const is = require('./utils/is.js'); /** * Type-guard: The attribute object has the shape the official attribute object (value, type, unit). * https://develop.sentry.dev/sdk/telemetry/scopes/#setting-attributes */ function isAttributeObject(maybeObj) { return ( typeof maybeObj === 'object' && maybeObj != null && !Array.isArray(maybeObj) && Object.keys(maybeObj).includes('value') ); } /** * Converts an attribute value to a typed attribute value. * * For now, we intentionally only support primitive values and attribute objects with primitive values. * If @param useFallback is true, we stringify non-primitive values to a string attribute value. Otherwise * we return `undefined` for unsupported values. * * @param value - The value of the passed attribute. * @param useFallback - If true, unsupported values will be stringified to a string attribute value. * Defaults to false. In this case, `undefined` is returned for unsupported values. * @returns The typed attribute. */ function attributeValueToTypedAttributeValue( rawValue, useFallback, ) { const { value, unit } = isAttributeObject(rawValue) ? rawValue : { value: rawValue, unit: undefined }; const attributeValue = getTypedAttributeValue(value); const checkedUnit = unit && typeof unit === 'string' ? { unit } : {}; if (attributeValue) { return { ...attributeValue, ...checkedUnit }; } if (!useFallback || (useFallback === 'skip-undefined' && value === undefined)) { return; } // Fallback: stringify the value // TODO(v11): be smarter here and use String constructor if stringify fails // (this is a breaking change for already existing attribute values) let stringValue = ''; try { stringValue = JSON.stringify(value) ?? ''; } catch { // Do nothing } return { value: stringValue, type: 'string', ...checkedUnit, }; } /** * Serializes raw attributes to typed attributes as expected in our envelopes. * * @param attributes The raw attributes to serialize. * @param fallback If true, unsupported values will be stringified to a string attribute value. * Defaults to false. In this case, `undefined` is returned for unsupported values. * * @returns The serialized attributes. */ function serializeAttributes( attributes, fallback = false, ) { const serializedAttributes = {}; for (const [key, value] of Object.entries(attributes ?? {})) { const typedValue = attributeValueToTypedAttributeValue(value, fallback); if (typedValue) { serializedAttributes[key] = typedValue; } } return serializedAttributes; } /** * Estimates the serialized byte size of {@link Attributes}, * with a couple of heuristics for performance. */ function estimateTypedAttributesSizeInBytes(attributes) { if (!attributes) { return 0; } let weight = 0; for (const [key, attr] of Object.entries(attributes)) { weight += key.length * 2; weight += attr.type.length * 2; weight += (attr.unit?.length ?? 0) * 2; const val = attr.value; if (Array.isArray(val)) { // Assumption: Individual array items have the same type and roughly the same size // probably not always true but allows us to cut down on runtime weight += estimatePrimitiveSizeInBytes(val[0]) * val.length; } else if (is.isPrimitive(val)) { weight += estimatePrimitiveSizeInBytes(val); } else { // default fallback for anything else (objects) weight += 100; } } return weight; } function estimatePrimitiveSizeInBytes(value) { if (typeof value === 'string') { return value.length * 2; } else if (typeof value === 'boolean') { return 4; } else if (typeof value === 'number') { return 8; } return 0; } /** * NOTE: We intentionally do not return anything for non-primitive values: * - array support will come in the future but if we stringify arrays now, * sending arrays (unstringified) later will be a subtle breaking change. * - Objects are not supported yet and product support is still TBD. * - We still keep the type signature for TypedAttributeValue wider to avoid a * breaking change once we add support for non-primitive values. * - Once we go back to supporting arrays and stringifying all other values, * we already implemented the serialization logic here: * https://github.com/getsentry/sentry-javascript/pull/18165 */ function getTypedAttributeValue(value) { const primitiveType = typeof value === 'string' ? 'string' : typeof value === 'boolean' ? 'boolean' : typeof value === 'number' && !Number.isNaN(value) ? Number.isInteger(value) ? 'integer' : 'double' : null; if (primitiveType) { // @ts-expect-error - TS complains because {@link TypedAttributeValue} is strictly typed to // avoid setting the wrong `type` on the attribute value. // In this case, getPrimitiveType already does the check but TS doesn't know that. // The "clean" alternative is to return an object per `typeof value` case // but that would require more bundle size // Therefore, we ignore it. return { value, type: primitiveType }; } } exports.attributeValueToTypedAttributeValue = attributeValueToTypedAttributeValue; exports.estimateTypedAttributesSizeInBytes = estimateTypedAttributesSizeInBytes; exports.isAttributeObject = isAttributeObject; exports.serializeAttributes = serializeAttributes; //# sourceMappingURL=attributes.js.map