UNPKG

newrelic

Version:
135 lines (104 loc) 3.03 kB
/* * Copyright 2020 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' module.exports = parse module.exports.fromString = fromString module.exports.fromMap = fromMap // this creates a copy of trim that can be used with map const trim = Function.prototype.call.bind(String.prototype.trim) const stringify = require('json-stringify-safe') // pass in parent logger to avoid circular deps function parse(labels, parentLogger) { const logger = parentLogger.child({ component: 'label-parser' }) let results if (!labels) { return [] } else if (typeof labels === 'string') { results = fromString(labels) } else if (labels) { results = fromMap(labels) } results.warnings.forEach(function logWarnings(message) { logger.warn(message) }) return results.labels } function fromString(raw) { const map = Object.create(null) if (!raw) { return { labels: [], warnings: [] } } const pairs = raw.split(';').map(trim) let parts while (!pairs[pairs.length - 1]) { pairs.pop() } while (!pairs[0]) { pairs.shift() } for (let i = 0, l = pairs.length; i < l; ++i) { parts = pairs[i].split(':').map(trim) if (parts.length !== 2) { return warn('Could not create a Label pair from ' + parts[i]) } else if (!parts[0]) { return warn('Label key can not be empty') } else if (!parts[1]) { return warn('Label value can not be empty') } map[parts[0]] = parts[1] } return fromMap(map) function warn(message) { return { labels: [], warnings: ['Invalid Label String: ' + raw, message] } } } function fromMap(map) { const warnings = [] let labels = [] Object.keys(map).forEach(function processKeys(key) { const type = truncate(key, 255) if (!map[key] || typeof map[key] !== 'string') { return warnings.push( 'Label value for ' + type + 'should be a string with a length between 1 and 255 characters' ) } const value = truncate(map[key], 255) if (type !== key) { warnings.push('Label key too long: ' + type) } if (value !== map[key]) { warnings.push('Label value too long: ' + value) } labels.push({ label_type: type, label_value: value }) }) if (labels.length > 64) { warnings.push('Too many Labels, list truncated to 64') labels = labels.slice(0, 64) } if (warnings.length) { try { warnings.unshift('Partially Invalid Label Setting: ' + stringify(map)) } catch (err) { warnings.unshift('Failed to stringify labels: ' + err.message) } } return { labels, warnings } } function truncate(str, max) { let len = 0 let i for (i = 0; i < str.length; ++i) { const chr = str.charCodeAt(i) if (chr >= 0xd800 && chr <= 0xdbff && i !== str.length) { // Handle UTF-16 surrogate pairs. // eslint-disable-next-line sonarjs/updated-loop-counter i += 1 } if (++len === max) { break } } return str.slice(0, i + 1) }