diff --git a/packages/opentelemetry-cloud-monitoring-exporter/src/monitoring.ts b/packages/opentelemetry-cloud-monitoring-exporter/src/monitoring.ts index d8391611..e0c3c7f3 100644 --- a/packages/opentelemetry-cloud-monitoring-exporter/src/monitoring.ts +++ b/packages/opentelemetry-cloud-monitoring-exporter/src/monitoring.ts @@ -107,9 +107,7 @@ export class MetricExporter implements IMetricExporter { this._logger.debug('Google Cloud Monitoring export'); const timeSeries: TimeSeries[] = []; for (const metric of metrics) { - const isRegistered = await this._registerMetricDescriptor( - metric.descriptor - ); + const isRegistered = await this._registerMetricDescriptor(metric); if (isRegistered) { timeSeries.push( createTimeSeries( @@ -149,9 +147,8 @@ export class MetricExporter implements IMetricExporter { * registered. Returns false otherwise. * @param metricDescriptor The OpenTelemetry MetricDescriptor. */ - private async _registerMetricDescriptor( - metricDescriptor: OTMetricDescriptor - ) { + private async _registerMetricDescriptor(metric: MetricRecord) { + const metricDescriptor = metric.descriptor; const existingMetricDescriptor = this.registeredMetricDescriptors.get( metricDescriptor.name ); @@ -167,7 +164,7 @@ export class MetricExporter implements IMetricExporter { return false; } } - const isRegistered = await this._createMetricDescriptor(metricDescriptor) + const isRegistered = await this._createMetricDescriptor(metric) .then(() => { this.registeredMetricDescriptors.set( metricDescriptor.name, @@ -186,14 +183,15 @@ export class MetricExporter implements IMetricExporter { * Creates a new metric descriptor. * @param metricDescriptor The OpenTelemetry MetricDescriptor. */ - private async _createMetricDescriptor(metricDescriptor: OTMetricDescriptor) { + private async _createMetricDescriptor(metric: MetricRecord) { const authClient = await this._authorize(); const request = { name: `projects/${this._projectId}`, resource: transformMetricDescriptor( - metricDescriptor, + metric.descriptor, this._metricPrefix, - this._displayNamePrefix + this._displayNamePrefix, + metric.aggregator.toPoint() ), auth: authClient, }; diff --git a/packages/opentelemetry-cloud-monitoring-exporter/src/transform.ts b/packages/opentelemetry-cloud-monitoring-exporter/src/transform.ts index 89132464..e0d278a3 100644 --- a/packages/opentelemetry-cloud-monitoring-exporter/src/transform.ts +++ b/packages/opentelemetry-cloud-monitoring-exporter/src/transform.ts @@ -47,14 +47,15 @@ export const OPENTELEMETRY_TASK_VALUE_DEFAULT = generateDefaultTaskValue(); export function transformMetricDescriptor( metricDescriptor: OTMetricDescriptor, metricPrefix: string, - displayNamePrefix: string + displayNamePrefix: string, + point: OTPoint ): MetricDescriptor { return { type: transformMetricType(metricPrefix, metricDescriptor.name), description: metricDescriptor.description, displayName: transformDisplayName(displayNamePrefix, metricDescriptor.name), metricKind: transformMetricKind(metricDescriptor.metricKind), - valueType: transformValueType(metricDescriptor.valueType), + valueType: transformValueType(metricDescriptor.valueType, point), unit: metricDescriptor.unit, labels: [ { @@ -86,17 +87,18 @@ function transformMetricKind(kind: OTMetricKind): MetricKind { case OTMetricKind.UP_DOWN_COUNTER: case OTMetricKind.VALUE_OBSERVER: case OTMetricKind.UP_DOWN_SUM_OBSERVER: + case OTMetricKind.VALUE_RECORDER: return MetricKind.GAUGE; default: - // TODO: Add support for OTMetricKind.ValueRecorder - // OTMetricKind.Measure was renamed to ValueRecorder in #1117 return MetricKind.UNSPECIFIED; } } /** Transforms a OpenTelemetry ValueType to a StackDriver ValueType. */ -function transformValueType(valueType: OTValueType): ValueType { - if (valueType === OTValueType.DOUBLE) { +function transformValueType(valueType: OTValueType, point: OTPoint): ValueType { + if (isDistributionValue(point.value) || isHistogramValue(point.value)) { + return ValueType.DISTRIBUTION; + } else if (valueType === OTValueType.DOUBLE) { return ValueType.DOUBLE; } else if (valueType === OTValueType.INT) { return ValueType.INT64; @@ -115,14 +117,13 @@ export function createTimeSeries( startTime: string, projectId: string ): TimeSeries { + const point = metric.aggregator.toPoint(); 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), - ], + valueType: transformValueType(metric.descriptor.valueType, point), + points: [transformPoint(point, metric.descriptor, startTime)], }; } diff --git a/packages/opentelemetry-cloud-monitoring-exporter/test/transform.test.ts b/packages/opentelemetry-cloud-monitoring-exporter/test/transform.test.ts index 7d178f01..2bb08027 100644 --- a/packages/opentelemetry-cloud-monitoring-exporter/test/transform.test.ts +++ b/packages/opentelemetry-cloud-monitoring-exporter/test/transform.test.ts @@ -49,6 +49,30 @@ describe('transform', () => { metricKind: OTMetricKind.OBSERVER, valueType: OTValueType.DOUBLE, }; + const point: OTPoint = { + value: 50, + timestamp: process.hrtime(), + }; + const distributionPoint: OTPoint = { + value: { + min: 0, + max: 100, + count: 5, + sum: 200, + }, + timestamp: process.hrtime(), + }; + const historgramPoint: OTPoint = { + value: { + buckets: { + boundaries: [5], + counts: [1, 1], + }, + sum: 10, + count: 2, + }, + timestamp: process.hrtime(), + }; it('should return a Google Cloud Monitoring MetricKind', () => { assert.strictEqual( @@ -77,23 +101,40 @@ describe('transform', () => { ); assert.strictEqual( TEST_ONLY.transformMetricKind(OTMetricKind.VALUE_RECORDER), + MetricKind.GAUGE + ); + assert.strictEqual( + TEST_ONLY.transformMetricKind(100), MetricKind.UNSPECIFIED ); }); it('should return a Google Cloud Monitoring ValueType', () => { assert.strictEqual( - TEST_ONLY.transformValueType(OTValueType.INT), + TEST_ONLY.transformValueType(OTValueType.INT, point), ValueType.INT64 ); assert.strictEqual( - TEST_ONLY.transformValueType(OTValueType.DOUBLE), + TEST_ONLY.transformValueType(OTValueType.DOUBLE, point), ValueType.DOUBLE ); assert.strictEqual( - TEST_ONLY.transformValueType(2), + TEST_ONLY.transformValueType(OTValueType.DOUBLE, distributionPoint), + ValueType.DISTRIBUTION + ); + assert.strictEqual( + TEST_ONLY.transformValueType(OTValueType.DOUBLE, historgramPoint), + ValueType.DISTRIBUTION + ); + assert.strictEqual( + TEST_ONLY.transformValueType(2, point), ValueType.VALUE_TYPE_UNSPECIFIED ); + try { + TEST_ONLY.transformValueType(100, point); + } catch (err) { + assert.equal(err, 'unsupported value type: 100'); + } }); it('should return a Google Cloud Monitoring DisplayName', () => { @@ -117,7 +158,8 @@ describe('transform', () => { const descriptor: MetricDescriptor = transformMetricDescriptor( metricDescriptor, 'custom.googleapis.com/myorg/', - 'myorg/' + 'myorg/', + point ); assert.strictEqual(descriptor.description, METRIC_DESCRIPTION); @@ -135,7 +177,8 @@ describe('transform', () => { const descriptor: MetricDescriptor = transformMetricDescriptor( metricDescriptor1, 'custom.googleapis.com/myorg/', - 'myorg/' + 'myorg/', + point ); assert.strictEqual(descriptor.description, METRIC_DESCRIPTION);