UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

95 lines (80 loc) 2.49 kB
'use strict' const { PAYLOAD_TAGGING_MAX_TAGS } = require('../constants') const redactedKeys = new Set([ 'authorization', 'x-authorization', 'password', 'token' ]) const truncated = 'truncated' const redacted = 'redacted' /** * Escapes dots in keys to preserve hierarchy in flattened tag names. * * @param {string} key * @returns {string} */ function escapeKey (key) { return key.replaceAll('.', String.raw`\.`) } /** * Compute normalized payload tags from any given object. * * - Limits total tag count to `PAYLOAD_TAGGING_MAX_TAGS - 1` plus the `_dd.payload_tags_incomplete` flag * - Truncates values at max depth and for large scalars * - Redacts known sensitive keys * * @param {unknown} object - Input to flatten into tags * @param {{ maxDepth: number, prefix: string }} opts - Traversal options * @returns {Record<string, string|boolean>} Map of tag names to values */ function tagsFromObject (object, opts) { const { maxDepth, prefix } = opts let tagCount = 0 let abort = false /** @type {Record<string, string|boolean>} */ const result = {} function tagRec (prefix, object, depth = 0) { // Off by one: _dd.payload_tags_trimmed counts as 1 tag if (abort) { return } if (tagCount >= PAYLOAD_TAGGING_MAX_TAGS - 1) { abort = true result['_dd.payload_tags_incomplete'] = true return } if (depth >= maxDepth && object !== null && typeof object === 'object') { tagCount += 1 result[prefix] = truncated return } if (object === undefined) { tagCount += 1 result[prefix] = 'undefined' return } if (object === null) { tagCount += 1 result[prefix] = 'null' return } if (['number', 'boolean'].includes(typeof object) || Buffer.isBuffer(object)) { tagCount += 1 result[prefix] = object.toString().slice(0, 5000) return } if (typeof object === 'string') { tagCount += 1 result[prefix] = object.slice(0, 5000) } if (typeof object === 'object') { // eslint-disable-line eslint-rules/eslint-safe-typeof-object for (const [key, value] of Object.entries(object)) { if (redactedKeys.has(key.toLowerCase())) { tagCount += 1 result[`${prefix}.${escapeKey(key)}`] = redacted } else { tagRec(`${prefix}.${escapeKey(key)}`, value, depth + 1) } } } } tagRec(prefix, object) return result } module.exports = { tagsFromObject }