Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: exponential histogram - part 3 - export #3506

Merged
merged 5 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this a mistake that got through before?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was an existing issue on main that predates my work on the exponential histogram.


/** 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();