{"version":3,"file":"PrometheusSerializer.js","sourceRoot":"","sources":["../../src/PrometheusSerializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Attributes, AttributeValue } from '@opentelemetry/api';\nimport { diag } from '@opentelemetry/api';\nimport type {\n  ResourceMetrics,\n  ScopeMetrics,\n  MetricData,\n  DataPoint,\n  Histogram,\n} from '@opentelemetry/sdk-metrics';\nimport { DataPointType } from '@opentelemetry/sdk-metrics';\nimport type { InstrumentationScope } from '@opentelemetry/core';\nimport { hrTimeToMilliseconds } from '@opentelemetry/core';\nimport type { Resource } from '@opentelemetry/resources';\nimport {\n  ATTR_OTEL_SCOPE_NAME,\n  ATTR_OTEL_SCOPE_VERSION,\n} from '@opentelemetry/semantic-conventions';\n\n// This is currently listed as experimental.\nconst ATTR_OTEL_SCOPE_SCHEMA_URL = 'otel.scope.schema_url';\n\ntype PrometheusDataTypeLiteral =\n  | 'counter'\n  | 'gauge'\n  | 'histogram'\n  | 'summary'\n  | 'untyped';\n\nfunction escapeString(str: string) {\n  return str.replace(/\\\\/g, '\\\\\\\\').replace(/\\n/g, '\\\\n');\n}\n\n/**\n * String Attribute values are converted directly to Prometheus attribute values.\n * Non-string values are represented as JSON-encoded strings.\n *\n * `undefined` is converted to an empty string.\n */\nfunction escapeAttributeValue(str: AttributeValue = '') {\n  if (typeof str !== 'string') {\n    str = JSON.stringify(str);\n  }\n  return escapeString(str).replace(/\"/g, '\\\\\"');\n}\n\nconst invalidCharacterRegex = /[^a-z0-9_]/gi;\nconst multipleUnderscoreRegex = /_{2,}/g;\n\n/**\n * Ensures metric names are valid Prometheus metric names by removing\n * characters allowed by OpenTelemetry but disallowed by Prometheus.\n *\n * https://prometheus.io/docs/concepts/data_model/#metric-names-and-attributes\n *\n * 1. Names must match `[a-zA-Z_:][a-zA-Z0-9_:]*`\n *\n * 2. Colons are reserved for user defined recording rules.\n * They should not be used by exporters or direct instrumentation.\n *\n * OpenTelemetry metric names are already validated in the Meter when they are created,\n * and they match the format `[a-zA-Z][a-zA-Z0-9_.\\-]*` which is very close to a valid\n * prometheus metric name, so we only need to strip characters valid in OpenTelemetry\n * but not valid in prometheus and replace them with '_'.\n *\n * @param name name to be sanitized\n */\nfunction sanitizePrometheusMetricName(name: string): string {\n  // replace all invalid characters with '_'\n  return name\n    .replace(invalidCharacterRegex, '_')\n    .replace(multipleUnderscoreRegex, '_');\n}\n\n/**\n * @private\n *\n * Helper method which assists in enforcing the naming conventions for metric\n * names in Prometheus\n * @param name the name of the metric\n * @param type the kind of metric\n * @returns string\n */\nfunction enforcePrometheusNamingConvention(\n  name: string,\n  data: MetricData\n): string {\n  // Prometheus requires that metrics of the Counter kind have \"_total\" suffix\n  if (\n    !name.endsWith('_total') &&\n    data.dataPointType === DataPointType.SUM &&\n    data.isMonotonic\n  ) {\n    name = name + '_total';\n  }\n\n  return name;\n}\n\nfunction valueString(value: number) {\n  if (value === Infinity) {\n    return '+Inf';\n  } else if (value === -Infinity) {\n    return '-Inf';\n  } else {\n    // Handle finite numbers and NaN.\n    return `${value}`;\n  }\n}\n\nfunction toPrometheusType(metricData: MetricData): PrometheusDataTypeLiteral {\n  switch (metricData.dataPointType) {\n    case DataPointType.SUM:\n      if (metricData.isMonotonic) {\n        return 'counter';\n      }\n      return 'gauge';\n    case DataPointType.GAUGE:\n      return 'gauge';\n    case DataPointType.HISTOGRAM:\n      return 'histogram';\n    default:\n      return 'untyped';\n  }\n}\n\nfunction stringify(\n  metricName: string,\n  attributes: Attributes,\n  value: number,\n  timestamp?: number,\n  additionalAttributes?: Attributes\n) {\n  let hasAttribute = false;\n  let attributesStr = '';\n\n  for (const [key, val] of Object.entries(attributes)) {\n    const sanitizedAttributeName = sanitizePrometheusMetricName(key);\n    hasAttribute = true;\n    attributesStr += `${\n      attributesStr.length > 0 ? ',' : ''\n    }${sanitizedAttributeName}=\"${escapeAttributeValue(val)}\"`;\n  }\n  if (additionalAttributes) {\n    for (const [key, val] of Object.entries(additionalAttributes)) {\n      const sanitizedAttributeName = sanitizePrometheusMetricName(key);\n      hasAttribute = true;\n      attributesStr += `${\n        attributesStr.length > 0 ? ',' : ''\n      }${sanitizedAttributeName}=\"${escapeAttributeValue(val)}\"`;\n    }\n  }\n\n  if (hasAttribute) {\n    metricName += `{${attributesStr}}`;\n  }\n\n  return `${metricName} ${valueString(value)}${\n    timestamp !== undefined ? ' ' + String(timestamp) : ''\n  }\\n`;\n}\n\nconst NO_REGISTERED_METRICS = '# no registered metrics';\n\nexport class PrometheusSerializer {\n  private _prefix: string | undefined;\n  private _appendTimestamp: boolean;\n  private _additionalAttributes: Attributes | undefined;\n  private _withResourceConstantLabels: RegExp | undefined;\n  private _withoutScopeInfo: boolean | undefined;\n  private _withoutTargetInfo: boolean | undefined;\n\n  constructor(\n    prefix?: string,\n    appendTimestamp = false,\n    withResourceConstantLabels?: RegExp,\n    withoutTargetInfo?: boolean,\n    withoutScopeInfo?: boolean\n  ) {\n    if (prefix) {\n      this._prefix = prefix + '_';\n    }\n    this._appendTimestamp = appendTimestamp;\n    this._withResourceConstantLabels = withResourceConstantLabels;\n    this._withoutScopeInfo = !!withoutScopeInfo;\n    this._withoutTargetInfo = !!withoutTargetInfo;\n  }\n\n  serialize(resourceMetrics: ResourceMetrics): string {\n    let str = '';\n\n    this._additionalAttributes = this._filterResourceConstantLabels(\n      resourceMetrics.resource.attributes,\n      this._withResourceConstantLabels\n    );\n\n    for (const scopeMetrics of resourceMetrics.scopeMetrics) {\n      str += this._serializeScopeMetrics(scopeMetrics);\n    }\n\n    if (str === '') {\n      str += NO_REGISTERED_METRICS;\n    }\n\n    return this._serializeResource(resourceMetrics.resource) + str;\n  }\n\n  private _filterResourceConstantLabels(\n    attributes: Attributes,\n    pattern: RegExp | undefined\n  ) {\n    if (pattern) {\n      const filteredAttributes: Attributes = {};\n      for (const [key, value] of Object.entries(attributes)) {\n        if (key.match(pattern)) {\n          filteredAttributes[key] = value;\n        }\n      }\n      return filteredAttributes;\n    }\n    return;\n  }\n\n  private _serializeScopeMetrics(scopeMetrics: ScopeMetrics) {\n    let str = '';\n    for (const metric of scopeMetrics.metrics) {\n      str += this._serializeMetricData(metric, scopeMetrics.scope) + '\\n';\n    }\n    return str;\n  }\n\n  private _serializeMetricData(\n    metricData: MetricData,\n    scope: InstrumentationScope\n  ) {\n    let name = sanitizePrometheusMetricName(\n      escapeString(metricData.descriptor.name)\n    );\n    if (this._prefix) {\n      name = `${this._prefix}${name}`;\n    }\n    const dataPointType = metricData.dataPointType;\n\n    name = enforcePrometheusNamingConvention(name, metricData);\n\n    const help = `# HELP ${name} ${escapeString(\n      metricData.descriptor.description || 'description missing'\n    )}`;\n    const unit = metricData.descriptor.unit\n      ? `\\n# UNIT ${name} ${escapeString(metricData.descriptor.unit)}`\n      : '';\n    const type = `# TYPE ${name} ${toPrometheusType(metricData)}`;\n    let additionalAttributes: Attributes | undefined;\n\n    if (this._withoutScopeInfo) {\n      additionalAttributes = this._additionalAttributes;\n    } else {\n      const scopeInfo: Attributes = { [ATTR_OTEL_SCOPE_NAME]: scope.name };\n\n      if (scope.schemaUrl) {\n        scopeInfo[ATTR_OTEL_SCOPE_SCHEMA_URL] = scope.schemaUrl;\n      }\n\n      if (scope.version) {\n        scopeInfo[ATTR_OTEL_SCOPE_VERSION] = scope.version;\n      }\n\n      additionalAttributes = Object.assign(\n        scopeInfo,\n        this._additionalAttributes\n      );\n    }\n\n    let results = '';\n    switch (dataPointType) {\n      case DataPointType.SUM:\n      case DataPointType.GAUGE: {\n        results = metricData.dataPoints\n          .map(it =>\n            this._serializeSingularDataPoint(\n              name,\n              metricData,\n              it,\n              additionalAttributes\n            )\n          )\n          .join('');\n        break;\n      }\n      case DataPointType.HISTOGRAM: {\n        results = metricData.dataPoints\n          .map(it =>\n            this._serializeHistogramDataPoint(\n              name,\n              metricData,\n              it,\n              additionalAttributes\n            )\n          )\n          .join('');\n        break;\n      }\n      default: {\n        diag.error(\n          `Unrecognizable DataPointType: ${dataPointType} for metric \"${name}\"`\n        );\n      }\n    }\n\n    return `${help}${unit}\\n${type}\\n${results}`.trim();\n  }\n\n  private _serializeSingularDataPoint(\n    name: string,\n    data: MetricData,\n    dataPoint: DataPoint<number>,\n    additionalAttributes: Attributes | undefined\n  ): string {\n    let results = '';\n\n    const { value, attributes } = dataPoint;\n    const timestamp = hrTimeToMilliseconds(dataPoint.endTime);\n    results += stringify(\n      name,\n      attributes,\n      value,\n      this._appendTimestamp ? timestamp : undefined,\n      additionalAttributes\n    );\n    return results;\n  }\n\n  private _serializeHistogramDataPoint(\n    name: string,\n    data: MetricData,\n    dataPoint: DataPoint<Histogram>,\n    additionalAttributes: Attributes | undefined\n  ): string {\n    let results = '';\n\n    const attributes = dataPoint.attributes;\n    const histogram = dataPoint.value;\n    const timestamp = hrTimeToMilliseconds(dataPoint.endTime);\n    /** Histogram[\"bucket\"] is not typed with `number` */\n    for (const key of ['count', 'sum'] as ('count' | 'sum')[]) {\n      const value = histogram[key];\n      if (value != null)\n        results += stringify(\n          name + '_' + key,\n          attributes,\n          value,\n          this._appendTimestamp ? timestamp : undefined,\n          additionalAttributes\n        );\n    }\n\n    let cumulativeSum = 0;\n    const countEntries = histogram.buckets.counts.entries();\n    let infiniteBoundaryDefined = false;\n    for (const [idx, val] of countEntries) {\n      cumulativeSum += val;\n      const upperBound = histogram.buckets.boundaries[idx];\n      /** HistogramAggregator is producing different boundary output -\n       * in one case not including infinity values, in other -\n       * full, e.g. [0, 100] and [0, 100, Infinity]\n       * we should consider that in export, if Infinity is defined, use it\n       * as boundary\n       */\n      if (upperBound === undefined && infiniteBoundaryDefined) {\n        break;\n      }\n      if (upperBound === Infinity) {\n        infiniteBoundaryDefined = true;\n      }\n      results += stringify(\n        name + '_bucket',\n        attributes,\n        cumulativeSum,\n        this._appendTimestamp ? timestamp : undefined,\n        Object.assign({}, additionalAttributes, {\n          le:\n            upperBound === undefined || upperBound === Infinity\n              ? '+Inf'\n              : String(upperBound),\n        })\n      );\n    }\n\n    return results;\n  }\n\n  protected _serializeResource(resource: Resource): string {\n    if (this._withoutTargetInfo === true) {\n      return '';\n    }\n\n    const name = 'target_info';\n    const help = `# HELP ${name} Target metadata`;\n    const type = `# TYPE ${name} gauge`;\n\n    const results = stringify(name, resource.attributes, 1).trim();\n    return `${help}\\n${type}\\n${results}\\n`;\n  }\n}\n"]}