UNPKG

@google-cloud/opentelemetry-cloud-monitoring-exporter

Version:

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

227 lines 8.72 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 = exports.OPENTELEMETRY_TASK_VALUE_DEFAULT = void 0; const metrics_1 = require("@opentelemetry/metrics"); const api_1 = require("@opentelemetry/api"); const resources_1 = require("@opentelemetry/resources"); const types_1 = require("./types"); const path = require("path"); const os = require("os"); const OPENTELEMETRY_TASK = 'opentelemetry_task'; const OPENTELEMETRY_TASK_DESCRIPTION = 'OpenTelemetry task identifier'; const AWS_REGION_VALUE_PREFIX = 'aws:'; const GCP_GCE_INSTANCE = 'gce_instance'; const AWS_EC2_INSTANCE = 'aws_ec2_instance'; exports.OPENTELEMETRY_TASK_VALUE_DEFAULT = generateDefaultTaskValue(); function transformMetricDescriptor(metricDescriptor, metricPrefix, displayNamePrefix) { return { type: transformMetricType(metricPrefix, metricDescriptor.name), description: metricDescriptor.description, displayName: transformDisplayName(displayNamePrefix, metricDescriptor.name), metricKind: transformMetricKind(metricDescriptor.metricKind), valueType: transformValueType(metricDescriptor.valueType), unit: metricDescriptor.unit, labels: [ { key: OPENTELEMETRY_TASK, description: OPENTELEMETRY_TASK_DESCRIPTION, }, ], }; } exports.transformMetricDescriptor = transformMetricDescriptor; /** Transforms Metric type. */ function transformMetricType(metricPrefix, name) { return path.join(metricPrefix, name); } /** Transforms Metric display name. */ function transformDisplayName(displayNamePrefix, name) { return path.join(displayNamePrefix, name); } /** Transforms a OpenTelemetry Type to a StackDriver MetricKind. */ function transformMetricKind(kind) { switch (kind) { case metrics_1.MetricKind.COUNTER: case metrics_1.MetricKind.SUM_OBSERVER: return types_1.MetricKind.CUMULATIVE; case metrics_1.MetricKind.UP_DOWN_COUNTER: case metrics_1.MetricKind.VALUE_OBSERVER: case metrics_1.MetricKind.UP_DOWN_SUM_OBSERVER: return types_1.MetricKind.GAUGE; default: // TODO: Add support for OTMetricKind.ValueRecorder // OTMetricKind.Measure was renamed to ValueRecorder in #1117 return types_1.MetricKind.UNSPECIFIED; } } /** Transforms a OpenTelemetry ValueType to a StackDriver ValueType. */ function transformValueType(valueType) { if (valueType === api_1.ValueType.DOUBLE) { return types_1.ValueType.DOUBLE; } else if (valueType === api_1.ValueType.INT) { return types_1.ValueType.INT64; } else { return types_1.ValueType.VALUE_TYPE_UNSPECIFIED; } } /** * Converts metric's timeseries to a TimeSeries, so that metric can be * uploaded to StackDriver. */ function createTimeSeries(metric, metricPrefix, startTime, projectId) { return { metric: transformMetric(metric, metricPrefix), resource: transformResource(metric.resource, projectId), metricKind: transformMetricKind(metric.descriptor.metricKind), valueType: transformValueType(metric.descriptor.valueType), points: [ transformPoint(metric.aggregator.toPoint(), metric.descriptor, startTime), ], }; } exports.createTimeSeries = createTimeSeries; /** * Given a resource, return a MonitoredResource * If any field is missing, return the default resource * @param resource * @param projectId */ function transformResource(resource, projectId) { const templateResource = getTypeAndMappings(resource); const type = templateResource.type; const labels = { project_id: projectId }; for (const key of Object.keys(templateResource.labels)) { // Checks the resource's value for a required key const resourceValue = resource.attributes[templateResource.labels[key]]; if (!resourceValue) { return { type: 'global', labels: { project_id: projectId } }; } if (type === AWS_EC2_INSTANCE && templateResource.labels[key] === resources_1.CLOUD_RESOURCE.REGION) { labels[key] = `${AWS_REGION_VALUE_PREFIX}${resourceValue}`; } else { labels[key] = `${resourceValue}`; } } return { type, labels }; } /** * Returns the type and mappings of a resource for a given cloud provider * The only currently supported cloud providers are GCP and AWS * @param resource */ function getTypeAndMappings(resource) { const cloudProvider = `${resource.attributes[resources_1.CLOUD_RESOURCE.PROVIDER]}`; if (cloudProvider === 'gcp') { return { type: GCP_GCE_INSTANCE, labels: { instance_id: resources_1.HOST_RESOURCE.ID, zone: resources_1.CLOUD_RESOURCE.ZONE, }, }; } else if (cloudProvider === 'aws') { return { type: AWS_EC2_INSTANCE, labels: { instance_id: resources_1.HOST_RESOURCE.ID, region: resources_1.CLOUD_RESOURCE.REGION, aws_account: resources_1.CLOUD_RESOURCE.ACCOUNT_ID, }, }; } return { type: 'global', labels: {} }; } function transformMetric(metric, metricPrefix) { const type = transformMetricType(metricPrefix, metric.descriptor.name); const labels = {}; Object.keys(metric.labels).forEach(key => (labels[key] = `${metric.labels[key]}`)); labels[OPENTELEMETRY_TASK] = exports.OPENTELEMETRY_TASK_VALUE_DEFAULT; return { type, labels }; } /** * Transform timeseries's point, so that metric can be uploaded to StackDriver. */ function transformPoint(point, metricDescriptor, startTime) { // TODO: Add endTime and startTime support, once available in OpenTelemetry // Related issues: https://github.com/open-telemetry/opentelemetry-js/pull/893 // and https://github.com/open-telemetry/opentelemetry-js/issues/488 switch (metricDescriptor.metricKind) { case metrics_1.MetricKind.COUNTER: case metrics_1.MetricKind.SUM_OBSERVER: return { value: transformValue(metricDescriptor.valueType, point.value), interval: { startTime, endTime: new Date().toISOString(), }, }; default: return { value: transformValue(metricDescriptor.valueType, point.value), interval: { endTime: new Date().toISOString(), }, }; } } /** Transforms a OpenTelemetry Point's value to a StackDriver Point value. */ function transformValue(valueType, value) { if (isHistogramValue(value)) { return { distributionValue: { // sumOfSquaredDeviation param not aggregated count: value.count, mean: value.sum / value.count, bucketOptions: { explicitBuckets: { bounds: value.buckets.boundaries }, }, bucketCounts: value.buckets.counts, }, }; } if (valueType === api_1.ValueType.INT) { return { int64Value: value }; } else if (valueType === api_1.ValueType.DOUBLE) { return { doubleValue: value }; } throw Error(`unsupported value type: ${valueType}`); } /** Returns true if value is of type OTHistogram */ function isHistogramValue(value) { return Object.prototype.hasOwnProperty.call(value, 'buckets'); } /** Returns a task label value in the format of 'nodejs-<pid>@<hostname>'. */ function generateDefaultTaskValue() { const pid = process.pid; const hostname = os.hostname() || 'localhost'; return 'nodejs-' + pid + '@' + hostname; } exports.TEST_ONLY = { transformMetricKind, transformValueType, transformDisplayName, transformMetricType, transformMetric, transformPoint, OPENTELEMETRY_TASK, }; //# sourceMappingURL=transform.js.map