From f734068ad10a71b522e66abc37c0923ddb942f68 Mon Sep 17 00:00:00 2001 From: Jesper Madsen Date: Fri, 1 Oct 2021 19:59:54 +0200 Subject: [PATCH 1/2] Add PullController --- .../src/Meter.ts | 20 +++++++---- .../src/export/Controller.ts | 34 ++++++++++++++++++- .../src/export/types.ts | 6 ++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts index 32f295694c..21fffd49ed 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts @@ -21,7 +21,7 @@ import { Resource } from '@opentelemetry/resources'; import { BatchObserver } from './BatchObserver'; import { BaseBoundInstrument } from './BoundInstrument'; import { CounterMetric } from './CounterMetric'; -import { PushController } from './export/Controller'; +import { PushController, Controller, PullController } from './export/Controller'; import { NoopExporter } from './export/NoopExporter'; import { Processor, UngroupedProcessor } from './export/Processor'; import { Metric } from './Metric'; @@ -31,6 +31,7 @@ import { UpDownCounterMetric } from './UpDownCounterMetric'; import { UpDownSumObserverMetric } from './UpDownSumObserverMetric'; import { ValueObserverMetric } from './ValueObserverMetric'; import { ValueRecorderMetric } from './ValueRecorderMetric'; +import { MetricExporter } from './export/types'; // eslint-disable-next-line @typescript-eslint/no-var-requires const merge = require('lodash.merge'); @@ -43,7 +44,7 @@ export class Meter implements api.Meter { private readonly _processor: Processor; private readonly _resource: Resource; private readonly _instrumentationLibrary: InstrumentationLibrary; - private readonly _controller: PushController; + private readonly _controller: Controller; private _isShutdown = false; private _shuttingDownPromise: Promise = Promise.resolve(); @@ -59,10 +60,17 @@ export class Meter implements api.Meter { this._resource = mergedConfig.resource || Resource.empty(); this._instrumentationLibrary = instrumentationLibrary; - // start the push controller - const exporter = mergedConfig.exporter || new NoopExporter(); - const interval = mergedConfig.interval; - this._controller = new PushController(this, exporter, interval); + const exporter: MetricExporter = mergedConfig.exporter || new NoopExporter(); + + // start the pull or push controller, depending on if the exporter defines the optional function registerPullController + if(typeof exporter.registerPullController === 'function') { + const pullController = new PullController(this, exporter); + this._controller = pullController; + exporter.registerPullController(pullController); + } else { + const interval = mergedConfig.interval; + this._controller = new PushController(this, exporter, interval); + } } /** diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts index 7c0c82700c..db2ed3105e 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts @@ -26,7 +26,7 @@ const DEFAULT_EXPORT_INTERVAL = 60_000; export class Controller {} -/** Controller organizes a periodic push of metric data. */ +/** PushController organizes a periodic push of metric data. */ export class PushController extends Controller { private _timer: NodeJS.Timeout; @@ -67,3 +67,35 @@ export class PushController extends Controller { }); } } + +/** PullController pulls metric data whenever the exporter requests it. */ +export class PullController extends Controller { + constructor( + private readonly _meter: Meter, + private readonly _exporter: MetricExporter, + ) { + super(); + } + + shutdown(): Promise { + return this._collect(); + } + + public async _collect(): Promise { + await this._meter.collect(); + return new Promise(resolve => { + this._exporter.export( + this._meter.getProcessor().checkPointSet(), + result => { + if (result.code !== ExportResultCode.SUCCESS) { + globalErrorHandler( + result.error ?? + new Error('PullController: export failed in _collect') + ); + } + resolve(); + } + ); + }); + } +} diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts index 889e96598d..36eeef34f5 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts @@ -22,6 +22,7 @@ import { } from '@opentelemetry/api-metrics'; import { ExportResult, InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; +import { PullController } from './Controller'; /** The kind of metric. */ export enum MetricKind { @@ -104,6 +105,11 @@ export interface MetricExporter { resultCallback: (result: ExportResult) => void ): void; + /** Registers a {@Link PullController}. If this function is defined, the MetricsExporter will use a {@Link PullController} instead of a {@Link PushController} */ + registerPullController?( + pullController: PullController + ): void; + /** Stops the exporter. */ shutdown(): Promise; } From 3770da36130423adc0ba2850cc0a94a803b97d23 Mon Sep 17 00:00:00 2001 From: Jesper Madsen Date: Fri, 1 Oct 2021 20:06:56 +0200 Subject: [PATCH 2/2] _collect to collect to follow naming standards --- .../opentelemetry-sdk-metrics-base/src/export/Controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts index db2ed3105e..924db6830e 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Controller.ts @@ -78,10 +78,10 @@ export class PullController extends Controller { } shutdown(): Promise { - return this._collect(); + return this.collect(); } - public async _collect(): Promise { + public async collect(): Promise { await this._meter.collect(); return new Promise(resolve => { this._exporter.export(