diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 10db71fc1c4..36ed94cd207 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -15,6 +15,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 * feat(configuration): add resource detection parsing [#6435](https://github.com/open-telemetry/opentelemetry-js/pull/6435) @MikeGoldsmith * feat(configuration): export interfaces required in other packages [#6462](https://github.com/open-telemetry/opentelemetry-js/pull/6462) @maryliag +* feat(configuration): set MeterProvider on sdk start [#6463](https://github.com/open-telemetry/opentelemetry-js/pull/6463) @maryliag ### :bug: Bug Fixes diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 49c4e94b4df..18ec3a9082e 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -11,11 +11,14 @@ import { context, diag, DiagConsoleLogger, + metrics, propagation, } from '@opentelemetry/api'; import { getInstanceID, getLogRecordProcessorsFromConfiguration, + getMeterReadersFromConfiguration, + getMeterViewsFromConfiguration, getPropagatorFromConfiguration, getResourceDetectorsFromConfiguration, getResourceFromConfiguration, @@ -23,6 +26,7 @@ import { import { registerInstrumentations } from '@opentelemetry/instrumentation'; import type { SDKComponents, SDKOptions } from './types'; import { LoggerProvider } from '@opentelemetry/sdk-logs'; +import { MeterProvider } from '@opentelemetry/sdk-metrics'; import { logs } from '@opentelemetry/api-logs'; import type { Resource, @@ -64,6 +68,9 @@ export function startNodeSDK(sdkOptions: SDKOptions): { if (components.loggerProvider) { logs.setGlobalLoggerProvider(components.loggerProvider); } + if (components.meterProvider) { + metrics.setGlobalMeterProvider(components.meterProvider); + } if (components.propagator) { propagation.setGlobalPropagator(components.propagator); } @@ -73,6 +80,9 @@ export function startNodeSDK(sdkOptions: SDKOptions): { if (components.loggerProvider) { promises.push(components.loggerProvider.shutdown()); } + if (components.meterProvider) { + promises.push(components.meterProvider.shutdown()); + } await Promise.all(promises); }; return { shutdown: shutdownFn }; @@ -113,6 +123,17 @@ function create( components.loggerProvider = loggerProvider; } + const meterReaders = getMeterReadersFromConfiguration(config); + if (meterReaders) { + const meterViews = getMeterViewsFromConfiguration(config); + const meterProvider = new MeterProvider({ + resource: resource, + readers: meterReaders, + views: meterViews ?? [], + }); + components.meterProvider = meterProvider; + } + return components; } diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 9a6973c2d45..ff2b14a97ba 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -11,6 +11,7 @@ import type { LoggerProvider, LogRecordProcessor, } from '@opentelemetry/sdk-logs'; +import type { MeterProvider } from '@opentelemetry/sdk-metrics'; import type { IMetricReader, ViewOptions } from '@opentelemetry/sdk-metrics'; import type { Sampler, @@ -55,5 +56,6 @@ export interface SDKOptions { export interface SDKComponents { contextManager: ContextManager; loggerProvider?: LoggerProvider; + meterProvider?: MeterProvider; propagator?: TextMapPropagator; } diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index 917a3c76d3c..a8bd2c3f505 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -49,12 +49,22 @@ import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'; import type { ConfigurationModel, LogRecordExporterModel, + InstrumentTypeConfigModel, + AggregationConfigModel, + PeriodicMetricReaderConfigModel, } from '@opentelemetry/configuration'; import type { + AggregationOption, IMetricReader, PushMetricExporter, + ViewOptions, +} from '@opentelemetry/sdk-metrics'; +import { + AggregationType, + ConsoleMetricExporter, + InstrumentType, + PeriodicExportingMetricReader, } from '@opentelemetry/sdk-metrics'; -import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; import { OTLPMetricExporter as OTLPHttpMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'; import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; @@ -480,6 +490,58 @@ export function getOtlpMetricExporterFromEnv(): PushMetricExporter { return new OTLPProtoMetricExporter(); } +export function getPeriodicMetricReaderFromConfiguration( + periodic: PeriodicMetricReaderConfigModel +): IMetricReader | undefined { + if (periodic.exporter) { + let exporter; + if (periodic.exporter.otlp_http) { + const encoding = periodic.exporter.otlp_http.encoding; + if (encoding === 'json') { + exporter = new OTLPHttpMetricExporter({ + compression: + periodic.exporter.otlp_http.compression === 'gzip' + ? CompressionAlgorithm.GZIP + : CompressionAlgorithm.NONE, + }); + } else if (encoding === 'protobuf') { + exporter = new OTLPProtoMetricExporter({ + compression: + periodic.exporter.otlp_http.compression === 'gzip' + ? CompressionAlgorithm.GZIP + : CompressionAlgorithm.NONE, + }); + } else { + diag.warn(`Unsupported OTLP metrics encoding: ${encoding}.`); + } + } + if (periodic.exporter.otlp_grpc) { + exporter = new OTLPGrpcMetricExporter({ + compression: + periodic.exporter.otlp_grpc.compression === 'gzip' + ? CompressionAlgorithm.GZIP + : CompressionAlgorithm.NONE, + }); + } + + if (exporter) { + // TODO(6425): add cardinality_limits + return new PeriodicExportingMetricReader({ + exportIntervalMillis: periodic.interval ?? 60_000, + exportTimeoutMillis: periodic.timeout ?? 30_000, + exporter, + }); + } + if (periodic.exporter.console) { + return new PeriodicExportingMetricReader({ + exporter: new ConsoleMetricExporter(), + }); + } + } + diag.warn(`Unsupported Metric Exporter.`); + return undefined; +} + /** * Get LoggerProviderConfig from environment variables. */ @@ -599,6 +661,157 @@ export function getLogRecordProcessorsFromConfiguration( return undefined; } +export function getMeterReadersFromConfiguration( + config: ConfigurationModel +): IMetricReader[] | undefined { + const metricReaders: IMetricReader[] = []; + config.meter_provider?.readers?.forEach(reader => { + if (reader.periodic) { + const periodicReader = getPeriodicMetricReaderFromConfiguration( + reader.periodic + ); + if (periodicReader) { + metricReaders.push(periodicReader); + } + } + }); + if (metricReaders.length > 0) { + return metricReaders; + } + return undefined; +} + +export function getInstrumentType( + instrument: InstrumentTypeConfigModel +): InstrumentType | undefined { + switch (instrument) { + case 'counter': + return InstrumentType.COUNTER; + case 'gauge': + return InstrumentType.GAUGE; + case 'histogram': + return InstrumentType.HISTOGRAM; + case 'observable_counter': + return InstrumentType.OBSERVABLE_COUNTER; + case 'observable_gauge': + return InstrumentType.OBSERVABLE_GAUGE; + case 'observable_up_down_counter': + return InstrumentType.OBSERVABLE_UP_DOWN_COUNTER; + case 'up_down_counter': + return InstrumentType.UP_DOWN_COUNTER; + default: + diag.warn(`Unsupported instrument type: ${instrument}`); + return undefined; + } +} + +export function getAggregationType( + aggregation: AggregationConfigModel +): AggregationOption | undefined { + if (aggregation.default) { + return { + type: AggregationType.DEFAULT, + }; + } + if (aggregation.drop) { + return { + type: AggregationType.DROP, + }; + } + if (aggregation.explicit_bucket_histogram) { + return { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { + recordMinMax: + aggregation.explicit_bucket_histogram.record_min_max ?? true, + boundaries: aggregation.explicit_bucket_histogram.boundaries ?? [ + 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, + 10000, + ], + }, + }; + } + + if (aggregation.base2_exponential_bucket_histogram) { + return { + type: AggregationType.EXPONENTIAL_HISTOGRAM, + options: { + recordMinMax: + aggregation.base2_exponential_bucket_histogram.record_min_max ?? true, + maxSize: aggregation.base2_exponential_bucket_histogram.max_size, + }, + }; + } + if (aggregation.last_value) { + return { + type: AggregationType.LAST_VALUE, + }; + } + if (aggregation.sum) { + return { + type: AggregationType.SUM, + }; + } + + diag.warn(`Unsupported aggregation type`); + return undefined; +} + +export function getMeterViewsFromConfiguration( + config: ConfigurationModel +): ViewOptions[] | undefined { + const metricViews: ViewOptions[] = []; + config.meter_provider?.views?.forEach(view => { + const viewOption: ViewOptions = {}; + if (view.selector) { + if (view.selector.instrument_name) { + viewOption.instrumentName = view.selector.instrument_name; + } + if (view.selector.instrument_type) { + const instrumentType = getInstrumentType(view.selector.instrument_type); + if (instrumentType) { + viewOption.instrumentType = instrumentType; + } + } + if (view.selector.unit) { + viewOption.instrumentUnit = view.selector.unit; + } + if (view.selector.meter_name) { + viewOption.meterName = view.selector.meter_name; + } + if (view.selector.meter_version) { + viewOption.meterVersion = view.selector.meter_version; + } + if (view.selector.meter_schema_url) { + viewOption.meterSchemaUrl = view.selector.meter_schema_url; + } + } + if (view.stream) { + viewOption.name = view.stream.name ?? view.selector?.instrument_name; + viewOption.aggregationCardinalityLimit = + view.stream.aggregation_cardinality_limit ?? 2_000; + if (view.stream.description) { + viewOption.description = view.stream.description; + } + if (view.stream.aggregation) { + const aggregationType = getAggregationType(view.stream.aggregation); + if (aggregationType) { + viewOption.aggregation = aggregationType; + } + } + // TODO(6427): add support for view.stream.attribute_keys and correspondent attributes processor configuration + } + + if (Object.keys(viewOption).length > 0) { + metricViews.push(viewOption); + } + }); + if (metricViews.length > 0) { + return metricViews; + } + return undefined; +} + export function getInstanceID(config: ConfigurationModel): string | undefined { if (config.resource?.attributes) { for (let i = 0; i < config.resource.attributes.length; i++) { diff --git a/experimental/packages/opentelemetry-sdk-node/test/fixtures/meter.yaml b/experimental/packages/opentelemetry-sdk-node/test/fixtures/meter.yaml new file mode 100644 index 00000000000..8273d6c71cc --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-node/test/fixtures/meter.yaml @@ -0,0 +1,138 @@ +file_format: "1.0-rc.3" +disabled: false +meter_provider: + readers: + - periodic: + interval: 60000 + timeout: 30000 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/metrics + tls: + ca_file: /app/cert.pem + key_file: /app/cert.pem + cert_file: /app/cert.pem + headers: + - name: api-key + value: "1234" + headers_list: "api-key=1234" + compression: gzip + timeout: 10000 + encoding: protobuf + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + producers: + - opencensus: + cardinality_limits: + default: 2000 + counter: 2000 + gauge: 2000 + histogram: 2000 + observable_counter: 2000 + observable_gauge: 2000 + observable_up_down_counter: 2000 + up_down_counter: 2000 + - periodic: + interval: 60000 + timeout: 30000 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/metrics + tls: + ca_file: /app/cert.pem + key_file: /app/cert.pem + cert_file: /app/cert.pem + headers: + - name: api-key + value: "1234" + headers_list: "api-key=1234" + compression: gzip + timeout: 10000 + encoding: json + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + producers: + - opencensus: + cardinality_limits: + default: 2000 + counter: 2000 + gauge: 2000 + histogram: 2000 + observable_counter: 2000 + observable_gauge: 2000 + observable_up_down_counter: 2000 + up_down_counter: 2000 + - periodic: + exporter: + otlp_grpc: + endpoint: http://localhost:4317 + tls: + ca_file: /app/cert.pem + key_file: /app/cert.pem + cert_file: /app/cert.pem + insecure: false + headers: + - name: api-key + value: "1234" + headers_list: "api-key=1234" + compression: gzip + timeout: 10000 + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + - periodic: + exporter: + otlp_file/development: + output_stream: file:///var/log/metrics.jsonl + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + - periodic: + exporter: + otlp_file/development: + output_stream: stdout + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + - periodic: + exporter: + console: + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + views: + - selector: + instrument_name: my-instrument + instrument_type: histogram + unit: ms + meter_name: my-meter + meter_version: 1.0.0 + meter_schema_url: https://opentelemetry.io/schemas/1.16.0 + stream: + name: new_instrument_name + description: new_description + aggregation: + explicit_bucket_histogram: + boundaries: + [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ] + record_min_max: true + aggregation_cardinality_limit: 2000 + attribute_keys: + included: + - key1 + - key2 + excluded: + - key3 + exemplar_filter: trace_based diff --git a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts index cd8dc02b88b..c4bc240291a 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts @@ -42,6 +42,9 @@ import { createConfigFactory } from '@opentelemetry/configuration'; import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; +import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; +import { OTLPMetricExporter as OTLPHttpMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'; import { ATTR_HOST_NAME, @@ -50,9 +53,15 @@ import { } from '../src/semconv'; import { ATTR_OS_TYPE } from '@opentelemetry/resources/src/semconv'; import { getLogRecordExporter, setupContextManager } from '../src/utils'; +import { + ConsoleMetricExporter, + MeterProvider, + PeriodicExportingMetricReader, +} from '@opentelemetry/sdk-metrics'; describe('startNodeSDK', function () { let setGlobalLoggerProviderSpy: Sinon.SinonSpy; + let setGlobalMeterProviderSpy: Sinon.SinonSpy; beforeEach(() => { diag.disable(); @@ -63,6 +72,7 @@ describe('startNodeSDK', function () { logs.disable(); setGlobalLoggerProviderSpy = Sinon.spy(logs, 'setGlobalLoggerProvider'); + setGlobalMeterProviderSpy = Sinon.spy(metrics, 'setGlobalMeterProvider'); }); const _origEnvVariables = { ...process.env }; @@ -98,6 +108,7 @@ describe('startNodeSDK', function () { setGlobalLoggerProviderSpy.called === false, 'logger provider should not have changed' ); + assert.ok(!(metrics.getMeterProvider() instanceof MeterProvider)); await sdk.shutdown(); }); @@ -243,6 +254,66 @@ describe('startNodeSDK', function () { await sdk.shutdown(); }); + it('should register a meter provider if multiple metric readers are provided', async () => { + const stubLoggerWarn: Sinon.SinonStub = Sinon.stub(diag, 'warn'); + + process.env.OTEL_CONFIG_FILE = 'test/fixtures/meter.yaml'; + const sdk = startNodeSDK({}); + + // Periodic type 'otlp_file/development' is not supported yet + assert.strictEqual( + stubLoggerWarn.args[0][0], + 'Unsupported Metric Exporter.' + ); + assert.strictEqual( + stubLoggerWarn.args[1][0], + 'Unsupported Metric Exporter.' + ); + + const meterProvider = metrics.getMeterProvider() as MeterProvider; + const sharedState = (meterProvider as any)['_sharedState']; + assert.strictEqual(sharedState.metricCollectors.length, 4); + + assert.ok( + sharedState.metricCollectors[0]._metricReader instanceof + PeriodicExportingMetricReader + ); + assert.ok( + sharedState.metricCollectors[0]._metricReader._exporter instanceof + OTLPProtoMetricExporter + ); + + assert.ok( + sharedState.metricCollectors[1]._metricReader instanceof + PeriodicExportingMetricReader + ); + assert.ok( + sharedState.metricCollectors[1]._metricReader._exporter instanceof + OTLPHttpMetricExporter + ); + + assert.ok( + sharedState.metricCollectors[2]._metricReader instanceof + PeriodicExportingMetricReader + ); + assert.ok( + sharedState.metricCollectors[2]._metricReader._exporter instanceof + OTLPGrpcMetricExporter + ); + + assert.ok( + sharedState.metricCollectors[3]._metricReader instanceof + PeriodicExportingMetricReader + ); + assert.ok( + sharedState.metricCollectors[3]._metricReader._exporter instanceof + ConsoleMetricExporter + ); + + stubLoggerWarn.reset(); + await sdk.shutdown(); + }); + describe('setupResources', async function () { beforeEach(() => { process.env.OTEL_RESOURCE_ATTRIBUTES = @@ -604,6 +675,45 @@ describe('startNodeSDK', function () { }); }); + describe('configuring meter provider from env', function () { + it('should register a meter provider if a exporter is provided', async () => { + process.env.OTEL_METRICS_EXPORTER = 'console'; + const sdk = startNodeSDK({}); + + assertDefaultContextManagerRegistered(); + assert.ok(metrics.getMeterProvider() instanceof MeterProvider); + + await sdk.shutdown(); + }); + + it('should register a meter provider if a list of exporters is provided', async () => { + process.env.OTEL_METRICS_EXPORTER = 'console,otlp'; + const sdk = startNodeSDK({}); + + assertDefaultContextManagerRegistered(); + + const meterProvider = metrics.getMeterProvider() as MeterProvider; + assert.ok(meterProvider instanceof MeterProvider); + + // Verify that both metric readers are registered + const sharedState = (meterProvider as any)['_sharedState']; + assert.strictEqual(sharedState.metricCollectors.length, 2); + + await sdk.shutdown(); + }); + + it('should not register the provider if OTEL_METRICS_EXPORTER contains none', async () => { + process.env.OTEL_METRICS_EXPORTER = 'console,none'; + const sdk = startNodeSDK({}); + + assert.ok( + setGlobalMeterProviderSpy.callCount === 0, + 'meter provider should not have changed' + ); + await sdk.shutdown(); + }); + }); + describe('tests to increase code coverage', function () { it('should return undefined for invalid log record exporter model', async () => { const exporter: LogRecordExporterModel = {}; diff --git a/experimental/packages/opentelemetry-sdk-node/test/utils.test.ts b/experimental/packages/opentelemetry-sdk-node/test/utils.test.ts index 23599bace97..dc8bebb5198 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/utils.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/utils.test.ts @@ -9,12 +9,18 @@ import { getPropagatorFromConfiguration, getLoggerProviderConfigFromEnv, getBatchLogRecordProcessorConfigFromEnv, + getPeriodicMetricReaderFromConfiguration, + getInstrumentType, + getAggregationType, getResourceDetectorsFromConfiguration, } from '../src/utils'; import * as assert from 'assert'; import * as sinon from 'sinon'; import { diag } from '@opentelemetry/api'; -import type { ConfigurationModel } from '@opentelemetry/configuration'; +import type { + InstrumentTypeConfigModel, + ConfigurationModel, +} from '@opentelemetry/configuration'; import { envDetector, hostDetector, @@ -23,6 +29,7 @@ import { serviceInstanceIdDetector, } from '@opentelemetry/resources'; import type { LoggerProviderConfig } from '@opentelemetry/sdk-logs'; +import { AggregationType, InstrumentType } from '@opentelemetry/sdk-metrics'; describe('getPropagatorFromEnv', function () { afterEach(() => { @@ -408,6 +415,100 @@ describe('getBatchLogRecordProcessorConfigFromEnv', function () { }); sinon.assert.callCount(warnStub, 4); }); + + it('should return warning message for invalid compression type for meter provider', function () { + const warnStub = sinon.stub(diag, 'warn'); + getPeriodicMetricReaderFromConfiguration({ + exporter: { otlp_http: { encoding: 'invalid' } }, + } as any); + sinon.assert.calledWithExactly( + warnStub, + 'Unsupported OTLP metrics encoding: invalid.' + ); + }); + + it('should return values for getInstrumentType', function () { + assert.deepStrictEqual( + getInstrumentType('counter' as InstrumentTypeConfigModel), + InstrumentType.COUNTER + ); + assert.deepStrictEqual( + getInstrumentType('gauge' as InstrumentTypeConfigModel), + InstrumentType.GAUGE + ); + assert.deepStrictEqual( + getInstrumentType('histogram' as InstrumentTypeConfigModel), + InstrumentType.HISTOGRAM + ); + assert.deepStrictEqual( + getInstrumentType('observable_counter' as InstrumentTypeConfigModel), + InstrumentType.OBSERVABLE_COUNTER + ); + assert.deepStrictEqual( + getInstrumentType('observable_gauge' as InstrumentTypeConfigModel), + InstrumentType.OBSERVABLE_GAUGE + ); + assert.deepStrictEqual( + getInstrumentType( + 'observable_up_down_counter' as InstrumentTypeConfigModel + ), + InstrumentType.OBSERVABLE_UP_DOWN_COUNTER + ); + assert.deepStrictEqual( + getInstrumentType('up_down_counter' as InstrumentTypeConfigModel), + InstrumentType.UP_DOWN_COUNTER + ); + + const warnStub = sinon.stub(diag, 'warn'); + assert.deepStrictEqual( + getInstrumentType('invalid' as InstrumentTypeConfigModel), + undefined + ); + sinon.assert.calledWithExactly( + warnStub, + 'Unsupported instrument type: invalid' + ); + }); + + it('should return correct values for getAggregationType', function () { + assert.deepStrictEqual(getAggregationType({ default: {} }), { + type: AggregationType.DEFAULT, + }); + assert.deepStrictEqual(getAggregationType({ drop: {} }), { + type: AggregationType.DROP, + }); + assert.deepStrictEqual( + getAggregationType({ explicit_bucket_histogram: {} }), + { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { + recordMinMax: true, + boundaries: [ + 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, + 10000, + ], + }, + } + ); + assert.deepStrictEqual( + getAggregationType({ + base2_exponential_bucket_histogram: { max_size: 10 }, + }), + { + type: AggregationType.EXPONENTIAL_HISTOGRAM, + options: { + recordMinMax: true, + maxSize: 10, + }, + } + ); + assert.deepStrictEqual(getAggregationType({ last_value: {} }), { + type: AggregationType.LAST_VALUE, + }); + assert.deepStrictEqual(getAggregationType({ sum: {} }), { + type: AggregationType.SUM, + }); + }); }); describe('getResourceDetectorsFromConfiguration', function () {