UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

111 lines (98 loc) 3.46 kB
'use strict' const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false }) const { PAYLOAD_TAG_REQUEST_PREFIX, PAYLOAD_TAG_RESPONSE_PREFIX } = require('../constants') const jsonpath = require('../../../../vendor/dist/jsonpath-plus').JSONPath const { tagsFromObject } = require('./tagging') /** * Given an identified value, attempt to parse it as JSON if relevant * * @param {unknown} value * @returns {unknown} the parsed object if parsing was successful, the input if not */ function maybeJSONParseValue (value) { if (typeof value !== 'string' || value[0] !== '{') { return value } try { return JSON.parse(value) } catch { return value } } /** * Apply expansion to all expansion JSONPath queries * * @param {Record<string, unknown>} object * @param {string[]} expansionRules list of JSONPath queries */ function expand (object, expansionRules) { for (const rule of expansionRules) { jsonpath(rule, object, (value, _type, desc) => { if (desc.parent && desc.parentProperty) { desc.parent[desc.parentProperty] = maybeJSONParseValue(value) } }) } } /** * Apply redaction to all redaction JSONPath queries * * @param {Record<string, unknown>} object * @param {string[]} redactionRules */ function redact (object, redactionRules) { for (const rule of redactionRules) { jsonpath(rule, object, (_value, _type, desc) => { if (desc.parent && desc.parentProperty) { desc.parent[desc.parentProperty] = 'redacted' } }) } } /** * Generate a map of tag names to tag values by performing: * 1. Attempting to parse identified fields as JSON * 2. Redacting fields identified by redaction rules * 3. Flattening the resulting object, producing as many tag name/tag value pairs * as there are leaf values in the object * This function performs side-effects on a _copy_ of the input object. * * @param {{ expand: string[], request: string[], response: string[] }} config sdk configuration for the service * @param {Record<string, unknown>} object the input object to generate tags from * @param {{ prefix: string, maxDepth: number }} opts tag generation options * @returns {Record<string, string|boolean>} Tags map */ function computeTags (config, object, opts) { const payload = rfdc(object) const redactionRules = opts.prefix === PAYLOAD_TAG_REQUEST_PREFIX ? config.request : config.response const expansionRules = config.expand expand(payload, expansionRules) redact(payload, redactionRules) return tagsFromObject(payload, opts) } /** * Compute request tags with the request prefix. * * @param {{ expand: string[], request: string[], response: string[] }} config * @param {Record<string, unknown>} object * @param {{ maxDepth: number }} opts * @returns {Record<string, string|boolean>} */ function tagsFromRequest (config, object, opts) { return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_REQUEST_PREFIX }) } /** * Compute response tags with the response prefix. * * @param {{ expand: string[], request: string[], response: string[] }} config * @param {Record<string, unknown>} object * @param {{ maxDepth: number }} opts * @returns {Record<string, string|boolean>} */ function tagsFromResponse (config, object, opts) { return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_RESPONSE_PREFIX }) } module.exports = { computeTags, tagsFromRequest, tagsFromResponse }