@cjanietz/opentelemetry-cloud-monitoring-exporter
Version:
OpenTelemetry Google Cloud Monitoring Exporter allows the user to send collected metrics to Google Cloud Monitoring.
174 lines • 7.42 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 sdk_metrics_base_1 = require("@opentelemetry/sdk-metrics-base");
const api_metrics_1 = require("@opentelemetry/api-metrics");
const opentelemetry_resource_util_1 = require("@google-cloud/opentelemetry-resource-util");
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';
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, metricDescriptor.metricKind),
unit: metricDescriptor.unit,
labels: [
{
key: OPENTELEMETRY_TASK,
description: OPENTELEMETRY_TASK_DESCRIPTION,
},
],
};
}
exports.transformMetricDescriptor = transformMetricDescriptor;
/** Transforms Metric type. */
function transformMetricType(metricPrefix, name) {
return path.posix.join(metricPrefix, name);
}
/** Transforms Metric display name. */
function transformDisplayName(displayNamePrefix, name) {
return path.posix.join(displayNamePrefix, name);
}
/** Transforms a OpenTelemetry Type to a StackDriver MetricKind. */
function transformMetricKind(kind) {
switch (kind) {
case sdk_metrics_base_1.MetricKind.COUNTER:
case sdk_metrics_base_1.MetricKind.OBSERVABLE_COUNTER:
case sdk_metrics_base_1.MetricKind.HISTOGRAM:
return types_1.MetricKind.CUMULATIVE;
case sdk_metrics_base_1.MetricKind.UP_DOWN_COUNTER:
case sdk_metrics_base_1.MetricKind.OBSERVABLE_GAUGE:
case sdk_metrics_base_1.MetricKind.OBSERVABLE_UP_DOWN_COUNTER:
return types_1.MetricKind.GAUGE;
default:
return types_1.MetricKind.UNSPECIFIED;
}
}
/** Transforms a OpenTelemetry ValueType to a StackDriver ValueType. */
function transformValueType(valueType, metricKind) {
// Stackdriver ValueType is not a 1 to 1 with OTel ValueType
if (valueType === api_metrics_1.ValueType.DOUBLE) {
if (metricKind === sdk_metrics_base_1.MetricKind.HISTOGRAM) {
return types_1.ValueType.DISTRIBUTION;
}
return types_1.ValueType.DOUBLE;
}
else if (valueType === api_metrics_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: (0, opentelemetry_resource_util_1.mapOtelResourceToMonitoredResource)(metric.resource, projectId),
metricKind: transformMetricKind(metric.descriptor.metricKind),
valueType: transformValueType(metric.descriptor.valueType, metric.descriptor.metricKind),
points: [
transformPoint(metric.aggregator.toPoint(), metric.descriptor, startTime),
],
};
}
exports.createTimeSeries = createTimeSeries;
function transformMetric(metric, metricPrefix) {
const type = transformMetricType(metricPrefix, metric.descriptor.name);
const labels = {};
Object.keys(metric.attributes).forEach(key => (labels[key] = `${metric.attributes[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 sdk_metrics_base_1.MetricKind.COUNTER:
case sdk_metrics_base_1.MetricKind.OBSERVABLE_COUNTER:
case sdk_metrics_base_1.MetricKind.HISTOGRAM:
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.toString(),
mean: value.sum / value.count,
bucketOptions: {
explicitBuckets: { bounds: value.buckets.boundaries },
},
bucketCounts: value.buckets.counts.map(count => count.toString()),
},
};
}
if (valueType === api_metrics_1.ValueType.INT) {
return { int64Value: value.toString() };
}
else if (valueType === api_metrics_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