@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
JavaScript
;
// 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