UNPKG

@jpg-store/opentelemetry-cloud-monitoring-exporter

Version:

OpenTelemetry Google Cloud Monitoring Exporter allows the user to send collected metrics to Google Cloud Monitoring.

198 lines 7.89 kB
"use strict"; // Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. Object.defineProperty(exports, "__esModule", { value: true }); exports._TEST_ONLY = exports.createTimeSeries = exports.transformMetricDescriptor = void 0; const sdk_metrics_1 = require("@opentelemetry/sdk-metrics"); const api_1 = require("@opentelemetry/api"); const types_1 = require("./types"); const path = require("path"); const precise_date_1 = require("@google-cloud/precise-date"); /** * * @param metric the MetricData to create a descriptor for * @param metricPrefix prefix to add to metric names * @param displayNamePrefix prefix to add to display name in the descriptor * @returns the GCM MetricDescriptor or null if the MetricData was empty */ function transformMetricDescriptor(metric, metricPrefix) { const { descriptor: { name, description, unit }, } = metric; return { type: transformMetricType(metricPrefix, name), description, displayName: name, metricKind: transformMetricKind(metric), valueType: transformValueType(metric), unit, labels: transformLabelDescriptors(metric), }; } exports.transformMetricDescriptor = transformMetricDescriptor; function transformLabelDescriptors(metric) { if (metric.dataPoints.length === 0) { return []; } const attrs = metric.dataPoints[0].attributes; return Object.keys(attrs).map(key => ({ key: normalizeLabelKey(key), description: '', })); } /** Transforms Metric type. */ function transformMetricType(metricPrefix, name) { return path.posix.join(metricPrefix, name); } /** Transforms a OpenTelemetry instrument type to a GCM MetricKind. */ function transformMetricKind(metric) { switch (metric.dataPointType) { case sdk_metrics_1.DataPointType.SUM: return metric.isMonotonic ? types_1.MetricKind.CUMULATIVE : types_1.MetricKind.GAUGE; case sdk_metrics_1.DataPointType.GAUGE: return types_1.MetricKind.GAUGE; case sdk_metrics_1.DataPointType.HISTOGRAM: return types_1.MetricKind.CUMULATIVE; default: exhaust(metric); api_1.diag.info('Encountered unexpected data point type %s', metric.dataPointType); return types_1.MetricKind.UNSPECIFIED; } } /** Transforms a OpenTelemetry ValueType to a GCM ValueType. */ function transformValueType(metric) { if (metric.dataPointType === sdk_metrics_1.DataPointType.HISTOGRAM) { return types_1.ValueType.DISTRIBUTION; } const { valueType } = metric.descriptor; if (valueType === api_1.ValueType.DOUBLE) { return types_1.ValueType.DOUBLE; } else if (valueType === api_1.ValueType.INT) { return types_1.ValueType.INT64; } else { exhaust(valueType); api_1.diag.info('Encountered unexpected value type %s', valueType); return types_1.ValueType.VALUE_TYPE_UNSPECIFIED; } } /** * Converts metric's timeseries to a TimeSeries, so that metric can be * uploaded to GCM. */ function createTimeSeries(metric, resource, metricPrefix) { const metricKind = transformMetricKind(metric); const valueType = transformValueType(metric); return transformPoints(metric, metricPrefix).map(({ point, metric }) => ({ metric, resource, metricKind, valueType, points: [point], })); } exports.createTimeSeries = createTimeSeries; function transformMetric(point, instrumentDescriptor, metricPrefix) { const type = transformMetricType(metricPrefix, instrumentDescriptor.name); const labels = {}; Object.keys(point.attributes).forEach(key => { labels[normalizeLabelKey(key)] = `${point.attributes[key]}`; }); return { type, labels }; } /** * Transform timeseries's point, so that metric can be uploaded to GCM. */ function transformPoints(metric, metricPrefix) { switch (metric.dataPointType) { case sdk_metrics_1.DataPointType.SUM: case sdk_metrics_1.DataPointType.GAUGE: return metric.dataPoints.map(dataPoint => ({ metric: transformMetric(dataPoint, metric.descriptor, metricPrefix), point: { value: transformNumberValue(metric.descriptor.valueType, dataPoint.value), interval: { // Add start time for non-gauge points ...(metric.dataPointType === sdk_metrics_1.DataPointType.SUM && metric.isMonotonic ? { startTime: new precise_date_1.PreciseDate(dataPoint.startTime).toISOString(), } : null), endTime: new precise_date_1.PreciseDate(dataPoint.endTime).toISOString(), }, }, })); case sdk_metrics_1.DataPointType.HISTOGRAM: return metric.dataPoints.map(dataPoint => ({ metric: transformMetric(dataPoint, metric.descriptor, metricPrefix), point: { value: transformHistogramValue(dataPoint.value), interval: { startTime: new precise_date_1.PreciseDate(dataPoint.startTime).toISOString(), endTime: new precise_date_1.PreciseDate(dataPoint.endTime).toISOString(), }, }, })); default: exhaust(metric); api_1.diag.info('Encountered unexpected dataPointType=%s, dropping the point', metric.dataPointType); break; } return []; } /** Transforms a OpenTelemetry Point's value to a GCM Point value. */ function transformNumberValue(valueType, value) { if (valueType === api_1.ValueType.INT) { return { int64Value: value.toString() }; } else if (valueType === api_1.ValueType.DOUBLE) { return { doubleValue: value }; } exhaust(valueType); throw Error(`unsupported value type: ${valueType}`); } function transformHistogramValue(value) { return { distributionValue: { // sumOfSquaredDeviation param not aggregated count: value.count.toString(), mean: value.count && value.sum ? value.sum / value.count : 0, bucketOptions: { explicitBuckets: { bounds: value.buckets.boundaries }, }, bucketCounts: value.buckets.counts.map(count => count.toString()), }, }; } function normalizeLabelKey(key) { // Replace characters which are not Letter or Decimal_Number unicode category with "_", see // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes // // Reimplementation of reference impl in Go: // https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/e955c204f4f2bfdc92ff0ad52786232b975efcc2/exporter/metric/metric.go#L595-L604 let sanitized = key.replace(/[^\p{Letter}\p{Decimal_Number}_]/gu, '_'); if (sanitized[0].match(/\p{Decimal_Number}/u)) { sanitized = 'key_' + sanitized; } return sanitized; } /** * Assert switch case is exhaustive */ function exhaust(switchValue) { return switchValue; } exports._TEST_ONLY = { normalizeLabelKey, }; //# sourceMappingURL=transform.js.map