Skip to content

Commit

Permalink
feat: exponential histogram - part 3 - export (open-telemetry#3506)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwear authored Mar 28, 2023
1 parent dbe005f commit 8c78859
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/

### :rocket: (Enhancement)

* feat(sdk-metrics): add exponential histogram accumulation / aggregator [#3505](https://github.com/open-telemetry/opentelemetry-js/pull/3505) @mwear
* feat(sdk-metrics): add exponential histogram support [#3505](https://github.com/open-telemetry/opentelemetry-js/pull/3505), [#3506](https://github.com/open-telemetry/opentelemetry-js/pull/3506) @mwear
* feat(resources): collect additional process attributes [#3605](https://github.com/open-telemetry/opentelemetry-js/pull/3605) @mwear

### :bug: (Bug Fix)
Expand Down
33 changes: 33 additions & 0 deletions experimental/packages/otlp-transformer/src/metrics/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import { toAttributes } from '../common/internal';
import {
EAggregationTemporality,
IExponentialHistogramDataPoint,
IHistogramDataPoint,
IMetric,
INumberDataPoint,
Expand Down Expand Up @@ -91,6 +92,11 @@ export function toMetric(metricData: MetricData): IMetric {
aggregationTemporality,
dataPoints: toHistogramDataPoints(metricData),
};
} else if (metricData.dataPointType === DataPointType.EXPONENTIAL_HISTOGRAM) {
out.exponentialHistogram = {
aggregationTemporality,
dataPoints: toExponentialHistogramDataPoints(metricData),
};
}

return out;
Expand Down Expand Up @@ -141,6 +147,33 @@ function toHistogramDataPoints(metricData: MetricData): IHistogramDataPoint[] {
});
}

function toExponentialHistogramDataPoints(
metricData: MetricData
): IExponentialHistogramDataPoint[] {
return metricData.dataPoints.map(dataPoint => {
const histogram = dataPoint.value as ExponentialHistogram;
return {
attributes: toAttributes(dataPoint.attributes),
count: histogram.count,
min: histogram.min,
max: histogram.max,
sum: histogram.sum,
positive: {
offset: histogram.positive.offset,
bucketCounts: histogram.positive.bucketCounts,
},
negative: {
offset: histogram.negative.offset,
bucketCounts: histogram.negative.bucketCounts,
},
scale: histogram.scale,
zeroCount: histogram.zeroCount,
startTimeUnixNano: hrTimeToNanoseconds(dataPoint.startTime),
timeUnixNano: hrTimeToNanoseconds(dataPoint.endTime),
};
});
}

function toAggregationTemporality(
temporality: AggregationTemporality
): EAggregationTemporality {
Expand Down
8 changes: 7 additions & 1 deletion experimental/packages/otlp-transformer/src/metrics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export interface IExponentialHistogramDataPoint {
startTimeUnixNano?: number;

/** ExponentialHistogramDataPoint timeUnixNano */
timeUnixNano?: string;
timeUnixNano?: number;

/** ExponentialHistogramDataPoint count */
count?: number;
Expand All @@ -209,6 +209,12 @@ export interface IExponentialHistogramDataPoint {

/** ExponentialHistogramDataPoint exemplars */
exemplars?: IExemplar[];

/** ExponentialHistogramDataPoint min */
min?: number;

/** ExponentialHistogramDataPoint max */
max?: number;
}

/** Properties of a SummaryDataPoint. */
Expand Down
169 changes: 169 additions & 0 deletions experimental/packages/otlp-transformer/test/metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,47 @@ describe('Metrics', () => {
};
}

function createExponentialHistogramMetrics(
count: number,
sum: number,
scale: number,
zeroCount: number,
positive: { offset: number; bucketCounts: number[] },
negative: { offset: number; bucketCounts: number[] },
aggregationTemporality: AggregationTemporality,
min?: number,
max?: number
): MetricData {
return {
descriptor: {
description: 'this is a description',
type: InstrumentType.HISTOGRAM,
name: 'xhist',
unit: '1',
valueType: ValueType.INT,
},
aggregationTemporality,
dataPointType: DataPointType.EXPONENTIAL_HISTOGRAM,
dataPoints: [
{
value: {
sum: sum,
count: count,
min: min,
max: max,
zeroCount: zeroCount,
scale: scale,
positive: positive,
negative: negative,
},
startTime: START_TIME,
endTime: END_TIME,
attributes: ATTRIBUTES,
},
],
};
}

function createResourceMetrics(metricData: MetricData[]): ResourceMetrics {
const resource = new Resource({
'resource-attribute': 'resource attribute value',
Expand Down Expand Up @@ -608,5 +649,133 @@ describe('Metrics', () => {
});
});
});

describe('serializes an exponential histogram metric record', () => {
it('with min/max', () => {
const exportRequest = createExportMetricsServiceRequest([
createResourceMetrics([
createExponentialHistogramMetrics(
3,
10,
1,
0,
{ offset: 0, bucketCounts: [1, 0, 0, 0, 1, 0, 1, 0] },
{ offset: 0, bucketCounts: [0] },
AggregationTemporality.CUMULATIVE,
1,
8
),
]),
]);

assert.ok(exportRequest);

assert.deepStrictEqual(exportRequest, {
resourceMetrics: [
{
resource: expectedResource,
schemaUrl: undefined,
scopeMetrics: [
{
scope: expectedScope,
schemaUrl: expectedSchemaUrl,
metrics: [
{
name: 'xhist',
description: 'this is a description',
unit: '1',
exponentialHistogram: {
aggregationTemporality:
EAggregationTemporality.AGGREGATION_TEMPORALITY_CUMULATIVE,
dataPoints: [
{
attributes: expectedAttributes,
count: 3,
sum: 10,
min: 1,
max: 8,
zeroCount: 0,
scale: 1,
positive: {
offset: 0,
bucketCounts: [1, 0, 0, 0, 1, 0, 1, 0],
},
negative: { offset: 0, bucketCounts: [0] },
startTimeUnixNano: hrTimeToNanoseconds(START_TIME),
timeUnixNano: hrTimeToNanoseconds(END_TIME),
},
],
},
},
],
},
],
},
],
});
});

it('without min/max', () => {
const exportRequest = createExportMetricsServiceRequest([
createResourceMetrics([
createExponentialHistogramMetrics(
3,
10,
1,
0,
{ offset: 0, bucketCounts: [1, 0, 0, 0, 1, 0, 1, 0] },
{ offset: 0, bucketCounts: [0] },
AggregationTemporality.CUMULATIVE
),
]),
]);

assert.ok(exportRequest);

assert.deepStrictEqual(exportRequest, {
resourceMetrics: [
{
resource: expectedResource,
schemaUrl: undefined,
scopeMetrics: [
{
scope: expectedScope,
schemaUrl: expectedSchemaUrl,
metrics: [
{
name: 'xhist',
description: 'this is a description',
unit: '1',
exponentialHistogram: {
aggregationTemporality:
EAggregationTemporality.AGGREGATION_TEMPORALITY_CUMULATIVE,
dataPoints: [
{
attributes: expectedAttributes,
count: 3,
sum: 10,
min: undefined,
max: undefined,
zeroCount: 0,
scale: 1,
positive: {
offset: 0,
bucketCounts: [1, 0, 0, 0, 1, 0, 1, 0],
},
negative: { offset: 0, bucketCounts: [0] },
startTimeUnixNano: hrTimeToNanoseconds(START_TIME),
timeUnixNano: hrTimeToNanoseconds(END_TIME),
},
],
},
},
],
},
],
},
],
});
});
});
});
});
1 change: 1 addition & 0 deletions packages/sdk-metrics/src/aggregator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export * from './Drop';
export * from './Histogram';
export * from './ExponentialHistogram';
export * from './LastValue';
export * from './Sum';
export { Aggregator } from './types';
2 changes: 2 additions & 0 deletions packages/sdk-metrics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {
SumMetricData,
GaugeMetricData,
HistogramMetricData,
ExponentialHistogramMetricData,
ResourceMetrics,
ScopeMetrics,
MetricData,
Expand All @@ -60,6 +61,7 @@ export { MeterProvider, MeterProviderOptions } from './MeterProvider';
export {
DefaultAggregation,
ExplicitBucketHistogramAggregation,
ExponentialHistogramAggregation,
DropAggregation,
HistogramAggregation,
LastValueAggregation,
Expand Down
21 changes: 21 additions & 0 deletions packages/sdk-metrics/src/view/Aggregation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
DropAggregator,
LastValueAggregator,
HistogramAggregator,
ExponentialHistogramAggregator,
} from '../aggregator';
import { Accumulation } from '../aggregator/types';
import { InstrumentDescriptor, InstrumentType } from '../InstrumentDescriptor';
Expand Down Expand Up @@ -52,6 +53,10 @@ export abstract class Aggregation {
return HISTOGRAM_AGGREGATION;
}

static ExponentialHistogram(): Aggregation {
return EXPONENTIAL_HISTOGRAM_AGGREGATION;
}

static Default(): Aggregation {
return DEFAULT_AGGREGATION;
}
Expand Down Expand Up @@ -144,6 +149,21 @@ export class ExplicitBucketHistogramAggregation extends Aggregation {
}
}

export class ExponentialHistogramAggregation extends Aggregation {
constructor(
private readonly _maxSize: number = 160,
private readonly _recordMinMax = true
) {
super();
}
createAggregator(_instrument: InstrumentDescriptor) {
return new ExponentialHistogramAggregator(
this._maxSize,
this._recordMinMax
);
}
}

/**
* The default aggregation.
*/
Expand Down Expand Up @@ -179,4 +199,5 @@ const DROP_AGGREGATION = new DropAggregation();
const SUM_AGGREGATION = new SumAggregation();
const LAST_VALUE_AGGREGATION = new LastValueAggregation();
const HISTOGRAM_AGGREGATION = new HistogramAggregation();
const EXPONENTIAL_HISTOGRAM_AGGREGATION = new ExponentialHistogramAggregation();
const DEFAULT_AGGREGATION = new DefaultAggregation();

0 comments on commit 8c78859

Please sign in to comment.