From a2dcb6287790811984366f4fb3520193d79514f1 Mon Sep 17 00:00:00 2001 From: David Green Date: Fri, 3 Feb 2023 19:30:56 -0800 Subject: [PATCH] catch errors from createTimeSeries Avoid crashing NodeJS with an unhandledRejection by catching errors from createTimeSeries. --- .../src/stackdriver-monitoring.ts | 14 ++++-- .../test/nocks.ts | 17 +++++-- .../test/test-stackdriver-monitoring.ts | 46 ++++++++++++++----- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/packages/opencensus-exporter-stackdriver/src/stackdriver-monitoring.ts b/packages/opencensus-exporter-stackdriver/src/stackdriver-monitoring.ts index ca5f68181..5ff132d91 100644 --- a/packages/opencensus-exporter-stackdriver/src/stackdriver-monitoring.ts +++ b/packages/opencensus-exporter-stackdriver/src/stackdriver-monitoring.ts @@ -108,9 +108,7 @@ export class StackdriverStatsExporter implements StatsEventListener { try { await this.export(); } catch (err) { - if (typeof this.onMetricUploadError === 'function') { - this.onMetricUploadError(err); - } + this.reportMetricUploadError(err); } }, this.period); } @@ -134,7 +132,15 @@ export class StackdriverStatsExporter implements StatsEventListener { } } - this.createTimeSeries(metricsList); + this.createTimeSeries(metricsList).catch(err => { + this.reportMetricUploadError(err); + }); + } + + private reportMetricUploadError(err) { + if (typeof this.onMetricUploadError === 'function') { + this.onMetricUploadError(err); + } } /** diff --git a/packages/opencensus-exporter-stackdriver/test/nocks.ts b/packages/opencensus-exporter-stackdriver/test/nocks.ts index 1adddb210..44acf45b2 100644 --- a/packages/opencensus-exporter-stackdriver/test/nocks.ts +++ b/packages/opencensus-exporter-stackdriver/test/nocks.ts @@ -127,17 +127,24 @@ export function batchWrite( return reply ? interceptor.reply(reply) : interceptor.reply(200); } -export function timeSeries( +export function timeSeriesNock( project: string, - validator?: (body: T) => boolean, - reply?: () => string, - withError?: boolean + validator?: (body: T) => boolean ) { validator = validator || accept; - const interceptor = nock('https://monitoring.googleapis.com').post( + return nock('https://monitoring.googleapis.com').post( '/v3/projects/' + project + '/timeSeries', validator ); +} + +export function timeSeries( + project: string, + validator?: (body: T) => boolean, + reply?: () => string, + withError?: boolean +) { + const interceptor = timeSeriesNock(project, validator); return reply ? interceptor.reply(reply) : interceptor.reply(200); } diff --git a/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts b/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts index a0c642a08..3b9845260 100644 --- a/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts +++ b/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts @@ -66,12 +66,31 @@ describe('Stackdriver Stats Exporter', () => { const mockLogger = new MockLogger(); let exporterOptions: StackdriverExporterOptions; let exporter: StackdriverStatsExporter; + const METRIC_NAME = 'metric-name'; + const METRIC_DESCRIPTION = 'metric-description'; + const UNIT = MeasureUnit.UNIT; + const METRIC_OPTIONS = { + description: METRIC_DESCRIPTION, + unit: UNIT, + labelKeys: [{ key: 'code', description: 'desc' }], + }; + + const metricRegistry = Metrics.getMetricRegistry(); + + const gauge = metricRegistry.addInt64Gauge(METRIC_NAME, METRIC_OPTIONS); + + // tslint:disable-next-line:no-any + let metricUploadErrors: any[]; before(() => { + metricUploadErrors = []; exporterOptions = { period: 0, projectId: PROJECT_ID, logger: mockLogger, + onMetricUploadError: err => { + metricUploadErrors.push(err); + }, }; nocks.noDetectResource(); exporter = new StackdriverStatsExporter(exporterOptions); @@ -90,18 +109,6 @@ describe('Stackdriver Stats Exporter', () => { }); it('should export the data', async () => { - const METRIC_NAME = 'metric-name'; - const METRIC_DESCRIPTION = 'metric-description'; - const UNIT = MeasureUnit.UNIT; - const METRIC_OPTIONS = { - description: METRIC_DESCRIPTION, - unit: UNIT, - labelKeys: [{ key: 'code', description: 'desc' }], - }; - - const metricRegistry = Metrics.getMetricRegistry(); - - const gauge = metricRegistry.addInt64Gauge(METRIC_NAME, METRIC_OPTIONS); gauge.getDefaultTimeSeries().add(100); nocks.metricDescriptors(PROJECT_ID); @@ -146,5 +153,20 @@ describe('Stackdriver Stats Exporter', () => { assert.deepStrictEqual(timeSeries.points[0].value.int64Value, 100); }); }); + + it('should export the data with an error', async () => { + gauge.getDefaultTimeSeries().add(100); + + nocks.metricDescriptors(PROJECT_ID); + nocks.timeSeriesNock(PROJECT_ID).replyWithError('intentional failure'); + + await exporter.export(); + + await new Promise(resolve => setTimeout(resolve, DELAY)).then(() => { + assert.strictEqual(metricUploadErrors.length, 1); + const message = metricUploadErrors[0].message; + assert.ok(message.indexOf('intentional failure') >= 0, message); + }); + }); }); });