feat: Complete zCode CLI X with Telegram bot integration

- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation

🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
This commit is contained in:
admin
2026-05-05 09:01:26 +00:00
Unverified
parent 4a7035dd92
commit 875c7f9b91
24688 changed files with 3224957 additions and 221 deletions

View File

@@ -0,0 +1,14 @@
import { HrTime } from '@opentelemetry/api';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { MetricData, MetricDescriptor } from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregatorKind, Aggregator, AccumulationRecord } from './types';
/** Basic aggregator for None which keeps no recorded value. */
export declare class DropAggregator implements Aggregator<undefined> {
kind: AggregatorKind.DROP;
createAccumulation(): undefined;
merge(_previous: undefined, _delta: undefined): undefined;
diff(_previous: undefined, _current: undefined): undefined;
toMetricData(_descriptor: MetricDescriptor, _aggregationTemporality: AggregationTemporality, _accumulationByAttributes: AccumulationRecord<undefined>[], _endTime: HrTime): Maybe<MetricData>;
}
//# sourceMappingURL=Drop.d.ts.map

View File

@@ -0,0 +1,35 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AggregatorKind } from './types';
/** Basic aggregator for None which keeps no recorded value. */
export class DropAggregator {
constructor() {
this.kind = AggregatorKind.DROP;
}
createAccumulation() {
return undefined;
}
merge(_previous, _delta) {
return undefined;
}
diff(_previous, _current) {
return undefined;
}
toMetricData(_descriptor, _aggregationTemporality, _accumulationByAttributes, _endTime) {
return undefined;
}
}
//# sourceMappingURL=Drop.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Drop.js","sourceRoot":"","sources":["../../../src/aggregator/Drop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,cAAc,EAAkC,MAAM,SAAS,CAAC;AAEzE,+DAA+D;AAC/D,MAAM,OAAO,cAAc;IAA3B;QACE,SAAI,GAAwB,cAAc,CAAC,IAAI,CAAC;IAsBlD,CAAC;IApBC,kBAAkB;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,SAAoB,EAAE,MAAiB;QAC3C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,SAAoB,EAAE,QAAmB;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,YAAY,CACV,WAA6B,EAC7B,uBAA+C,EAC/C,yBAA0D,EAC1D,QAAgB;QAEhB,OAAO,SAAS,CAAC;IACnB,CAAC;CACF","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { HrTime } from '@opentelemetry/api';\nimport { AggregationTemporality } from '../export/AggregationTemporality';\nimport { MetricData, MetricDescriptor } from '../export/MetricData';\nimport { Maybe } from '../utils';\nimport { AggregatorKind, Aggregator, AccumulationRecord } from './types';\n\n/** Basic aggregator for None which keeps no recorded value. */\nexport class DropAggregator implements Aggregator<undefined> {\n kind: AggregatorKind.DROP = AggregatorKind.DROP;\n\n createAccumulation() {\n return undefined;\n }\n\n merge(_previous: undefined, _delta: undefined) {\n return undefined;\n }\n\n diff(_previous: undefined, _current: undefined) {\n return undefined;\n }\n\n toMetricData(\n _descriptor: MetricDescriptor,\n _aggregationTemporality: AggregationTemporality,\n _accumulationByAttributes: AccumulationRecord<undefined>[],\n _endTime: HrTime\n ): Maybe<MetricData> {\n return undefined;\n }\n}\n"]}

View File

@@ -0,0 +1,176 @@
import { Accumulation, AccumulationRecord, Aggregator, AggregatorKind, ExponentialHistogram } from './types';
import { ExponentialHistogramMetricData, MetricDescriptor } from '../export/MetricData';
import { HrTime } from '@opentelemetry/api';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { Buckets } from './exponential-histogram/Buckets';
import { Mapping } from './exponential-histogram/mapping/types';
/**
* Internal value type for ExponentialHistogramAggregation.
* Differs from the exported type as undefined sum/min/max complicate arithmetic
* performed by this aggregation, but are required to be undefined in the exported types.
*/
interface InternalHistogram extends ExponentialHistogram {
hasMinMax: boolean;
min: number;
max: number;
sum: number;
}
export declare class ExponentialHistogramAccumulation implements Accumulation {
startTime: HrTime;
private _maxSize;
private _recordMinMax;
private _sum;
private _count;
private _zeroCount;
private _min;
private _max;
private _positive;
private _negative;
private _mapping;
constructor(startTime?: HrTime, _maxSize?: number, _recordMinMax?: boolean, _sum?: number, _count?: number, _zeroCount?: number, _min?: number, _max?: number, _positive?: Buckets, _negative?: Buckets, _mapping?: Mapping);
/**
* record updates a histogram with a single count
* @param {Number} value
*/
record(value: number): void;
/**
* Sets the start time for this accumulation
* @param {HrTime} startTime
*/
setStartTime(startTime: HrTime): void;
/**
* Returns the datapoint representation of this accumulation
* @param {HrTime} startTime
*/
toPointValue(): InternalHistogram;
/**
* @returns {Number} The sum of values recorded by this accumulation
*/
get sum(): number;
/**
* @returns {Number} The minimum value recorded by this accumulation
*/
get min(): number;
/**
* @returns {Number} The maximum value recorded by this accumulation
*/
get max(): number;
/**
* @returns {Number} The count of values recorded by this accumulation
*/
get count(): number;
/**
* @returns {Number} The number of 0 values recorded by this accumulation
*/
get zeroCount(): number;
/**
* @returns {Number} The scale used by this accumulation
*/
get scale(): number;
/**
* positive holds the positive values
* @returns {Buckets}
*/
get positive(): Buckets;
/**
* negative holds the negative values by their absolute value
* @returns {Buckets}
*/
get negative(): Buckets;
/**
* updateByIncr supports updating a histogram with a non-negative
* increment.
* @param value
* @param increment
*/
updateByIncrement(value: number, increment: number): void;
/**
* merge combines data from previous value into self
* @param {ExponentialHistogramAccumulation} previous
*/
merge(previous: ExponentialHistogramAccumulation): void;
/**
* diff subtracts other from self
* @param {ExponentialHistogramAccumulation} other
*/
diff(other: ExponentialHistogramAccumulation): void;
/**
* clone returns a deep copy of self
* @returns {ExponentialHistogramAccumulation}
*/
clone(): ExponentialHistogramAccumulation;
/**
* _updateBuckets maps the incoming value to a bucket index for the current
* scale. If the bucket index is outside of the range of the backing array,
* it will rescale the backing array and update the mapping for the new scale.
*/
private _updateBuckets;
/**
* _incrementIndexBy increments the count of the bucket specified by `index`.
* If the index is outside of the range [buckets.indexStart, buckets.indexEnd]
* the boundaries of the backing array will be adjusted and more buckets will
* be added if needed.
*/
private _incrementIndexBy;
/**
* grow resizes the backing array by doubling in size up to maxSize.
* This extends the array with a bunch of zeros and copies the
* existing counts to the same position.
*/
private _grow;
/**
* _changeScale computes how much downscaling is needed by shifting the
* high and low values until they are separated by no more than size.
*/
private _changeScale;
/**
* _downscale subtracts `change` from the current mapping scale.
*/
private _downscale;
/**
* _minScale is used by diff and merge to compute an ideal combined scale
*/
private _minScale;
/**
* _highLowAtScale is used by diff and merge to compute an ideal combined scale.
*/
private _highLowAtScale;
/**
* _mergeBuckets translates index values from another histogram and
* adds the values into the corresponding buckets of this histogram.
*/
private _mergeBuckets;
/**
* _diffBuckets translates index values from another histogram and
* subtracts the values in the corresponding buckets of this histogram.
*/
private _diffBuckets;
}
/**
* Aggregator for ExponentialHistogramAccumulations
*/
export declare class ExponentialHistogramAggregator implements Aggregator<ExponentialHistogramAccumulation> {
readonly _maxSize: number;
private readonly _recordMinMax;
kind: AggregatorKind.EXPONENTIAL_HISTOGRAM;
/**
* @param _maxSize Maximum number of buckets for each of the positive
* and negative ranges, exclusive of the zero-bucket.
* @param _recordMinMax If set to true, min and max will be recorded.
* Otherwise, min and max will not be recorded.
*/
constructor(_maxSize: number, _recordMinMax: boolean);
createAccumulation(startTime: HrTime): ExponentialHistogramAccumulation;
/**
* Return the result of the merge of two exponential histogram accumulations.
*/
merge(previous: ExponentialHistogramAccumulation, delta: ExponentialHistogramAccumulation): ExponentialHistogramAccumulation;
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous: ExponentialHistogramAccumulation, current: ExponentialHistogramAccumulation): ExponentialHistogramAccumulation;
toMetricData(descriptor: MetricDescriptor, aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord<ExponentialHistogramAccumulation>[], endTime: HrTime): Maybe<ExponentialHistogramMetricData>;
}
export {};
//# sourceMappingURL=ExponentialHistogram.d.ts.map

View File

@@ -0,0 +1,461 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AggregatorKind, } from './types';
import { DataPointType, } from '../export/MetricData';
import { diag } from '@opentelemetry/api';
import { InstrumentType } from '../InstrumentDescriptor';
import { Buckets } from './exponential-histogram/Buckets';
import { getMapping } from './exponential-histogram/mapping/getMapping';
import { nextGreaterSquare } from './exponential-histogram/util';
// HighLow is a utility class used for computing a common scale for
// two exponential histogram accumulations
class HighLow {
constructor(low, high) {
this.low = low;
this.high = high;
}
static combine(h1, h2) {
return new HighLow(Math.min(h1.low, h2.low), Math.max(h1.high, h2.high));
}
}
const MAX_SCALE = 20;
const DEFAULT_MAX_SIZE = 160;
const MIN_MAX_SIZE = 2;
export class ExponentialHistogramAccumulation {
constructor(startTime = startTime, _maxSize = DEFAULT_MAX_SIZE, _recordMinMax = true, _sum = 0, _count = 0, _zeroCount = 0, _min = Number.POSITIVE_INFINITY, _max = Number.NEGATIVE_INFINITY, _positive = new Buckets(), _negative = new Buckets(), _mapping = getMapping(MAX_SCALE)) {
this.startTime = startTime;
this._maxSize = _maxSize;
this._recordMinMax = _recordMinMax;
this._sum = _sum;
this._count = _count;
this._zeroCount = _zeroCount;
this._min = _min;
this._max = _max;
this._positive = _positive;
this._negative = _negative;
this._mapping = _mapping;
if (this._maxSize < MIN_MAX_SIZE) {
diag.warn(`Exponential Histogram Max Size set to ${this._maxSize}, \
changing to the minimum size of: ${MIN_MAX_SIZE}`);
this._maxSize = MIN_MAX_SIZE;
}
}
/**
* record updates a histogram with a single count
* @param {Number} value
*/
record(value) {
this.updateByIncrement(value, 1);
}
/**
* Sets the start time for this accumulation
* @param {HrTime} startTime
*/
setStartTime(startTime) {
this.startTime = startTime;
}
/**
* Returns the datapoint representation of this accumulation
* @param {HrTime} startTime
*/
toPointValue() {
return {
hasMinMax: this._recordMinMax,
min: this.min,
max: this.max,
sum: this.sum,
positive: {
offset: this.positive.offset,
bucketCounts: this.positive.counts(),
},
negative: {
offset: this.negative.offset,
bucketCounts: this.negative.counts(),
},
count: this.count,
scale: this.scale,
zeroCount: this.zeroCount,
};
}
/**
* @returns {Number} The sum of values recorded by this accumulation
*/
get sum() {
return this._sum;
}
/**
* @returns {Number} The minimum value recorded by this accumulation
*/
get min() {
return this._min;
}
/**
* @returns {Number} The maximum value recorded by this accumulation
*/
get max() {
return this._max;
}
/**
* @returns {Number} The count of values recorded by this accumulation
*/
get count() {
return this._count;
}
/**
* @returns {Number} The number of 0 values recorded by this accumulation
*/
get zeroCount() {
return this._zeroCount;
}
/**
* @returns {Number} The scale used by this accumulation
*/
get scale() {
if (this._count === this._zeroCount) {
// all zeros! scale doesn't matter, use zero
return 0;
}
return this._mapping.scale;
}
/**
* positive holds the positive values
* @returns {Buckets}
*/
get positive() {
return this._positive;
}
/**
* negative holds the negative values by their absolute value
* @returns {Buckets}
*/
get negative() {
return this._negative;
}
/**
* updateByIncr supports updating a histogram with a non-negative
* increment.
* @param value
* @param increment
*/
updateByIncrement(value, increment) {
// NaN does not fall into any bucket, is not zero and should not be counted,
// NaN is never greater than max nor less than min, therefore return as there's nothing for us to do.
if (Number.isNaN(value)) {
return;
}
if (value > this._max) {
this._max = value;
}
if (value < this._min) {
this._min = value;
}
this._count += increment;
if (value === 0) {
this._zeroCount += increment;
return;
}
this._sum += value * increment;
if (value > 0) {
this._updateBuckets(this._positive, value, increment);
}
else {
this._updateBuckets(this._negative, -value, increment);
}
}
/**
* merge combines data from previous value into self
* @param {ExponentialHistogramAccumulation} previous
*/
merge(previous) {
if (this._count === 0) {
this._min = previous.min;
this._max = previous.max;
}
else if (previous.count !== 0) {
if (previous.min < this.min) {
this._min = previous.min;
}
if (previous.max > this.max) {
this._max = previous.max;
}
}
this.startTime = previous.startTime;
this._sum += previous.sum;
this._count += previous.count;
this._zeroCount += previous.zeroCount;
const minScale = this._minScale(previous);
this._downscale(this.scale - minScale);
this._mergeBuckets(this.positive, previous, previous.positive, minScale);
this._mergeBuckets(this.negative, previous, previous.negative, minScale);
}
/**
* diff subtracts other from self
* @param {ExponentialHistogramAccumulation} other
*/
diff(other) {
this._min = Infinity;
this._max = -Infinity;
this._sum -= other.sum;
this._count -= other.count;
this._zeroCount -= other.zeroCount;
const minScale = this._minScale(other);
this._downscale(this.scale - minScale);
this._diffBuckets(this.positive, other, other.positive, minScale);
this._diffBuckets(this.negative, other, other.negative, minScale);
}
/**
* clone returns a deep copy of self
* @returns {ExponentialHistogramAccumulation}
*/
clone() {
return new ExponentialHistogramAccumulation(this.startTime, this._maxSize, this._recordMinMax, this._sum, this._count, this._zeroCount, this._min, this._max, this.positive.clone(), this.negative.clone(), this._mapping);
}
/**
* _updateBuckets maps the incoming value to a bucket index for the current
* scale. If the bucket index is outside of the range of the backing array,
* it will rescale the backing array and update the mapping for the new scale.
*/
_updateBuckets(buckets, value, increment) {
let index = this._mapping.mapToIndex(value);
// rescale the mapping if needed
let rescalingNeeded = false;
let high = 0;
let low = 0;
if (buckets.length === 0) {
buckets.indexStart = index;
buckets.indexEnd = buckets.indexStart;
buckets.indexBase = buckets.indexStart;
}
else if (index < buckets.indexStart &&
buckets.indexEnd - index >= this._maxSize) {
rescalingNeeded = true;
low = index;
high = buckets.indexEnd;
}
else if (index > buckets.indexEnd &&
index - buckets.indexStart >= this._maxSize) {
rescalingNeeded = true;
low = buckets.indexStart;
high = index;
}
// rescale and compute index at new scale
if (rescalingNeeded) {
const change = this._changeScale(high, low);
this._downscale(change);
index = this._mapping.mapToIndex(value);
}
this._incrementIndexBy(buckets, index, increment);
}
/**
* _incrementIndexBy increments the count of the bucket specified by `index`.
* If the index is outside of the range [buckets.indexStart, buckets.indexEnd]
* the boundaries of the backing array will be adjusted and more buckets will
* be added if needed.
*/
_incrementIndexBy(buckets, index, increment) {
if (increment === 0) {
// nothing to do for a zero increment, can happen during a merge operation
return;
}
if (buckets.length === 0) {
buckets.indexStart = buckets.indexEnd = buckets.indexBase = index;
}
if (index < buckets.indexStart) {
const span = buckets.indexEnd - index;
if (span >= buckets.backing.length) {
this._grow(buckets, span + 1);
}
buckets.indexStart = index;
}
else if (index > buckets.indexEnd) {
const span = index - buckets.indexStart;
if (span >= buckets.backing.length) {
this._grow(buckets, span + 1);
}
buckets.indexEnd = index;
}
let bucketIndex = index - buckets.indexBase;
if (bucketIndex < 0) {
bucketIndex += buckets.backing.length;
}
buckets.incrementBucket(bucketIndex, increment);
}
/**
* grow resizes the backing array by doubling in size up to maxSize.
* This extends the array with a bunch of zeros and copies the
* existing counts to the same position.
*/
_grow(buckets, needed) {
const size = buckets.backing.length;
const bias = buckets.indexBase - buckets.indexStart;
const oldPositiveLimit = size - bias;
let newSize = nextGreaterSquare(needed);
if (newSize > this._maxSize) {
newSize = this._maxSize;
}
const newPositiveLimit = newSize - bias;
buckets.backing.growTo(newSize, oldPositiveLimit, newPositiveLimit);
}
/**
* _changeScale computes how much downscaling is needed by shifting the
* high and low values until they are separated by no more than size.
*/
_changeScale(high, low) {
let change = 0;
while (high - low >= this._maxSize) {
high >>= 1;
low >>= 1;
change++;
}
return change;
}
/**
* _downscale subtracts `change` from the current mapping scale.
*/
_downscale(change) {
if (change === 0) {
return;
}
if (change < 0) {
// Note: this should be impossible. If we get here it's because
// there is a bug in the implementation.
throw new Error(`impossible change of scale: ${this.scale}`);
}
const newScale = this._mapping.scale - change;
this._positive.downscale(change);
this._negative.downscale(change);
this._mapping = getMapping(newScale);
}
/**
* _minScale is used by diff and merge to compute an ideal combined scale
*/
_minScale(other) {
const minScale = Math.min(this.scale, other.scale);
const highLowPos = HighLow.combine(this._highLowAtScale(this.positive, this.scale, minScale), this._highLowAtScale(other.positive, other.scale, minScale));
const highLowNeg = HighLow.combine(this._highLowAtScale(this.negative, this.scale, minScale), this._highLowAtScale(other.negative, other.scale, minScale));
return Math.min(minScale - this._changeScale(highLowPos.high, highLowPos.low), minScale - this._changeScale(highLowNeg.high, highLowNeg.low));
}
/**
* _highLowAtScale is used by diff and merge to compute an ideal combined scale.
*/
_highLowAtScale(buckets, currentScale, newScale) {
if (buckets.length === 0) {
return new HighLow(0, -1);
}
const shift = currentScale - newScale;
return new HighLow(buckets.indexStart >> shift, buckets.indexEnd >> shift);
}
/**
* _mergeBuckets translates index values from another histogram and
* adds the values into the corresponding buckets of this histogram.
*/
_mergeBuckets(ours, other, theirs, scale) {
const theirOffset = theirs.offset;
const theirChange = other.scale - scale;
for (let i = 0; i < theirs.length; i++) {
this._incrementIndexBy(ours, (theirOffset + i) >> theirChange, theirs.at(i));
}
}
/**
* _diffBuckets translates index values from another histogram and
* subtracts the values in the corresponding buckets of this histogram.
*/
_diffBuckets(ours, other, theirs, scale) {
const theirOffset = theirs.offset;
const theirChange = other.scale - scale;
for (let i = 0; i < theirs.length; i++) {
const ourIndex = (theirOffset + i) >> theirChange;
let bucketIndex = ourIndex - ours.indexBase;
if (bucketIndex < 0) {
bucketIndex += ours.backing.length;
}
ours.decrementBucket(bucketIndex, theirs.at(i));
}
ours.trim();
}
}
/**
* Aggregator for ExponentialHistogramAccumulations
*/
export class ExponentialHistogramAggregator {
/**
* @param _maxSize Maximum number of buckets for each of the positive
* and negative ranges, exclusive of the zero-bucket.
* @param _recordMinMax If set to true, min and max will be recorded.
* Otherwise, min and max will not be recorded.
*/
constructor(_maxSize, _recordMinMax) {
this._maxSize = _maxSize;
this._recordMinMax = _recordMinMax;
this.kind = AggregatorKind.EXPONENTIAL_HISTOGRAM;
}
createAccumulation(startTime) {
return new ExponentialHistogramAccumulation(startTime, this._maxSize, this._recordMinMax);
}
/**
* Return the result of the merge of two exponential histogram accumulations.
*/
merge(previous, delta) {
const result = delta.clone();
result.merge(previous);
return result;
}
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous, current) {
const result = current.clone();
result.diff(previous);
return result;
}
toMetricData(descriptor, aggregationTemporality, accumulationByAttributes, endTime) {
return {
descriptor,
aggregationTemporality,
dataPointType: DataPointType.EXPONENTIAL_HISTOGRAM,
dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => {
const pointValue = accumulation.toPointValue();
// determine if instrument allows negative values.
const allowsNegativeValues = descriptor.type === InstrumentType.GAUGE ||
descriptor.type === InstrumentType.UP_DOWN_COUNTER ||
descriptor.type === InstrumentType.OBSERVABLE_GAUGE ||
descriptor.type === InstrumentType.OBSERVABLE_UP_DOWN_COUNTER;
return {
attributes,
startTime: accumulation.startTime,
endTime,
value: {
min: pointValue.hasMinMax ? pointValue.min : undefined,
max: pointValue.hasMinMax ? pointValue.max : undefined,
sum: !allowsNegativeValues ? pointValue.sum : undefined,
positive: {
offset: pointValue.positive.offset,
bucketCounts: pointValue.positive.bucketCounts,
},
negative: {
offset: pointValue.negative.offset,
bucketCounts: pointValue.negative.bucketCounts,
},
count: pointValue.count,
scale: pointValue.scale,
zeroCount: pointValue.zeroCount,
},
};
}),
};
}
}
//# sourceMappingURL=ExponentialHistogram.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,59 @@
import { Accumulation, AccumulationRecord, Aggregator, AggregatorKind } from './types';
import { HistogramMetricData, MetricDescriptor } from '../export/MetricData';
import { HrTime } from '@opentelemetry/api';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
/**
* Internal value type for HistogramAggregation.
* Differs from the exported type as undefined sum/min/max complicate arithmetic
* performed by this aggregation, but are required to be undefined in the exported types.
*/
interface InternalHistogram {
buckets: {
boundaries: number[];
counts: number[];
};
sum: number;
count: number;
hasMinMax: boolean;
min: number;
max: number;
}
export declare class HistogramAccumulation implements Accumulation {
startTime: HrTime;
private readonly _boundaries;
private _recordMinMax;
private _current;
constructor(startTime: HrTime, _boundaries: number[], _recordMinMax?: boolean, _current?: InternalHistogram);
record(value: number): void;
setStartTime(startTime: HrTime): void;
toPointValue(): InternalHistogram;
}
/**
* Basic aggregator which observes events and counts them in pre-defined buckets
* and provides the total sum and count of all observations.
*/
export declare class HistogramAggregator implements Aggregator<HistogramAccumulation> {
private readonly _boundaries;
private readonly _recordMinMax;
kind: AggregatorKind.HISTOGRAM;
/**
* @param _boundaries sorted upper bounds of recorded values.
* @param _recordMinMax If set to true, min and max will be recorded. Otherwise, min and max will not be recorded.
*/
constructor(_boundaries: number[], _recordMinMax: boolean);
createAccumulation(startTime: HrTime): HistogramAccumulation;
/**
* Return the result of the merge of two histogram accumulations. As long as one Aggregator
* instance produces all Accumulations with constant boundaries we don't need to worry about
* merging accumulations with different boundaries.
*/
merge(previous: HistogramAccumulation, delta: HistogramAccumulation): HistogramAccumulation;
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous: HistogramAccumulation, current: HistogramAccumulation): HistogramAccumulation;
toMetricData(descriptor: MetricDescriptor, aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord<HistogramAccumulation>[], endTime: HrTime): Maybe<HistogramMetricData>;
}
export {};
//# sourceMappingURL=Histogram.d.ts.map

View File

@@ -0,0 +1,177 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AggregatorKind, } from './types';
import { DataPointType, } from '../export/MetricData';
import { InstrumentType } from '../InstrumentDescriptor';
import { binarySearchUB } from '../utils';
function createNewEmptyCheckpoint(boundaries) {
const counts = boundaries.map(() => 0);
counts.push(0);
return {
buckets: {
boundaries,
counts,
},
sum: 0,
count: 0,
hasMinMax: false,
min: Infinity,
max: -Infinity,
};
}
export class HistogramAccumulation {
constructor(startTime, _boundaries, _recordMinMax = true, _current = createNewEmptyCheckpoint(_boundaries)) {
this.startTime = startTime;
this._boundaries = _boundaries;
this._recordMinMax = _recordMinMax;
this._current = _current;
}
record(value) {
// NaN does not fall into any bucket, is not zero and should not be counted,
// NaN is never greater than max nor less than min, therefore return as there's nothing for us to do.
if (Number.isNaN(value)) {
return;
}
this._current.count += 1;
this._current.sum += value;
if (this._recordMinMax) {
this._current.min = Math.min(value, this._current.min);
this._current.max = Math.max(value, this._current.max);
this._current.hasMinMax = true;
}
const idx = binarySearchUB(this._boundaries, value);
this._current.buckets.counts[idx] += 1;
}
setStartTime(startTime) {
this.startTime = startTime;
}
toPointValue() {
return this._current;
}
}
/**
* Basic aggregator which observes events and counts them in pre-defined buckets
* and provides the total sum and count of all observations.
*/
export class HistogramAggregator {
/**
* @param _boundaries sorted upper bounds of recorded values.
* @param _recordMinMax If set to true, min and max will be recorded. Otherwise, min and max will not be recorded.
*/
constructor(_boundaries, _recordMinMax) {
this._boundaries = _boundaries;
this._recordMinMax = _recordMinMax;
this.kind = AggregatorKind.HISTOGRAM;
}
createAccumulation(startTime) {
return new HistogramAccumulation(startTime, this._boundaries, this._recordMinMax);
}
/**
* Return the result of the merge of two histogram accumulations. As long as one Aggregator
* instance produces all Accumulations with constant boundaries we don't need to worry about
* merging accumulations with different boundaries.
*/
merge(previous, delta) {
const previousValue = previous.toPointValue();
const deltaValue = delta.toPointValue();
const previousCounts = previousValue.buckets.counts;
const deltaCounts = deltaValue.buckets.counts;
const mergedCounts = new Array(previousCounts.length);
for (let idx = 0; idx < previousCounts.length; idx++) {
mergedCounts[idx] = previousCounts[idx] + deltaCounts[idx];
}
let min = Infinity;
let max = -Infinity;
if (this._recordMinMax) {
if (previousValue.hasMinMax && deltaValue.hasMinMax) {
min = Math.min(previousValue.min, deltaValue.min);
max = Math.max(previousValue.max, deltaValue.max);
}
else if (previousValue.hasMinMax) {
min = previousValue.min;
max = previousValue.max;
}
else if (deltaValue.hasMinMax) {
min = deltaValue.min;
max = deltaValue.max;
}
}
return new HistogramAccumulation(previous.startTime, previousValue.buckets.boundaries, this._recordMinMax, {
buckets: {
boundaries: previousValue.buckets.boundaries,
counts: mergedCounts,
},
count: previousValue.count + deltaValue.count,
sum: previousValue.sum + deltaValue.sum,
hasMinMax: this._recordMinMax &&
(previousValue.hasMinMax || deltaValue.hasMinMax),
min: min,
max: max,
});
}
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous, current) {
const previousValue = previous.toPointValue();
const currentValue = current.toPointValue();
const previousCounts = previousValue.buckets.counts;
const currentCounts = currentValue.buckets.counts;
const diffedCounts = new Array(previousCounts.length);
for (let idx = 0; idx < previousCounts.length; idx++) {
diffedCounts[idx] = currentCounts[idx] - previousCounts[idx];
}
return new HistogramAccumulation(current.startTime, previousValue.buckets.boundaries, this._recordMinMax, {
buckets: {
boundaries: previousValue.buckets.boundaries,
counts: diffedCounts,
},
count: currentValue.count - previousValue.count,
sum: currentValue.sum - previousValue.sum,
hasMinMax: false,
min: Infinity,
max: -Infinity,
});
}
toMetricData(descriptor, aggregationTemporality, accumulationByAttributes, endTime) {
return {
descriptor,
aggregationTemporality,
dataPointType: DataPointType.HISTOGRAM,
dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => {
const pointValue = accumulation.toPointValue();
// determine if instrument allows negative values.
const allowsNegativeValues = descriptor.type === InstrumentType.GAUGE ||
descriptor.type === InstrumentType.UP_DOWN_COUNTER ||
descriptor.type === InstrumentType.OBSERVABLE_GAUGE ||
descriptor.type === InstrumentType.OBSERVABLE_UP_DOWN_COUNTER;
return {
attributes,
startTime: accumulation.startTime,
endTime,
value: {
min: pointValue.hasMinMax ? pointValue.min : undefined,
max: pointValue.hasMinMax ? pointValue.max : undefined,
sum: !allowsNegativeValues ? pointValue.sum : undefined,
buckets: pointValue.buckets,
count: pointValue.count,
},
};
}),
};
}
}
//# sourceMappingURL=Histogram.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
import { Accumulation, AccumulationRecord, Aggregator, AggregatorKind, LastValue } from './types';
import { HrTime } from '@opentelemetry/api';
import { GaugeMetricData, MetricDescriptor } from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
export declare class LastValueAccumulation implements Accumulation {
startTime: HrTime;
private _current;
sampleTime: HrTime;
constructor(startTime: HrTime, _current?: number, sampleTime?: HrTime);
record(value: number): void;
setStartTime(startTime: HrTime): void;
toPointValue(): LastValue;
}
/** Basic aggregator which calculates a LastValue from individual measurements. */
export declare class LastValueAggregator implements Aggregator<LastValueAccumulation> {
kind: AggregatorKind.LAST_VALUE;
createAccumulation(startTime: HrTime): LastValueAccumulation;
/**
* Returns the result of the merge of the given accumulations.
*
* Return the newly captured (delta) accumulation for LastValueAggregator.
*/
merge(previous: LastValueAccumulation, delta: LastValueAccumulation): LastValueAccumulation;
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*
* A delta aggregation is not meaningful to LastValueAggregator, just return
* the newly captured (delta) accumulation for LastValueAggregator.
*/
diff(previous: LastValueAccumulation, current: LastValueAccumulation): LastValueAccumulation;
toMetricData(descriptor: MetricDescriptor, aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord<LastValueAccumulation>[], endTime: HrTime): Maybe<GaugeMetricData>;
}
//# sourceMappingURL=LastValue.d.ts.map

View File

@@ -0,0 +1,87 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AggregatorKind, } from './types';
import { millisToHrTime, hrTimeToMicroseconds } from '@opentelemetry/core';
import { DataPointType, } from '../export/MetricData';
export class LastValueAccumulation {
constructor(startTime, _current = 0, sampleTime = [0, 0]) {
this.startTime = startTime;
this._current = _current;
this.sampleTime = sampleTime;
}
record(value) {
this._current = value;
this.sampleTime = millisToHrTime(Date.now());
}
setStartTime(startTime) {
this.startTime = startTime;
}
toPointValue() {
return this._current;
}
}
/** Basic aggregator which calculates a LastValue from individual measurements. */
export class LastValueAggregator {
constructor() {
this.kind = AggregatorKind.LAST_VALUE;
}
createAccumulation(startTime) {
return new LastValueAccumulation(startTime);
}
/**
* Returns the result of the merge of the given accumulations.
*
* Return the newly captured (delta) accumulation for LastValueAggregator.
*/
merge(previous, delta) {
// nanoseconds may lose precisions.
const latestAccumulation = hrTimeToMicroseconds(delta.sampleTime) >=
hrTimeToMicroseconds(previous.sampleTime)
? delta
: previous;
return new LastValueAccumulation(previous.startTime, latestAccumulation.toPointValue(), latestAccumulation.sampleTime);
}
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*
* A delta aggregation is not meaningful to LastValueAggregator, just return
* the newly captured (delta) accumulation for LastValueAggregator.
*/
diff(previous, current) {
// nanoseconds may lose precisions.
const latestAccumulation = hrTimeToMicroseconds(current.sampleTime) >=
hrTimeToMicroseconds(previous.sampleTime)
? current
: previous;
return new LastValueAccumulation(current.startTime, latestAccumulation.toPointValue(), latestAccumulation.sampleTime);
}
toMetricData(descriptor, aggregationTemporality, accumulationByAttributes, endTime) {
return {
descriptor,
aggregationTemporality,
dataPointType: DataPointType.GAUGE,
dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => {
return {
attributes,
startTime: accumulation.startTime,
endTime,
value: accumulation.toPointValue(),
};
}),
};
}
}
//# sourceMappingURL=LastValue.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
import { Sum, AggregatorKind, Aggregator, Accumulation, AccumulationRecord } from './types';
import { HrTime } from '@opentelemetry/api';
import { MetricDescriptor, SumMetricData } from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
export declare class SumAccumulation implements Accumulation {
startTime: HrTime;
monotonic: boolean;
private _current;
reset: boolean;
constructor(startTime: HrTime, monotonic: boolean, _current?: number, reset?: boolean);
record(value: number): void;
setStartTime(startTime: HrTime): void;
toPointValue(): Sum;
}
/** Basic aggregator which calculates a Sum from individual measurements. */
export declare class SumAggregator implements Aggregator<SumAccumulation> {
monotonic: boolean;
kind: AggregatorKind.SUM;
constructor(monotonic: boolean);
createAccumulation(startTime: HrTime): SumAccumulation;
/**
* Returns the result of the merge of the given accumulations.
*/
merge(previous: SumAccumulation, delta: SumAccumulation): SumAccumulation;
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous: SumAccumulation, current: SumAccumulation): SumAccumulation;
toMetricData(descriptor: MetricDescriptor, aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord<SumAccumulation>[], endTime: HrTime): Maybe<SumMetricData>;
}
//# sourceMappingURL=Sum.d.ts.map

View File

@@ -0,0 +1,91 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AggregatorKind, } from './types';
import { DataPointType, } from '../export/MetricData';
export class SumAccumulation {
constructor(startTime, monotonic, _current = 0, reset = false) {
this.startTime = startTime;
this.monotonic = monotonic;
this._current = _current;
this.reset = reset;
}
record(value) {
if (this.monotonic && value < 0) {
return;
}
this._current += value;
}
setStartTime(startTime) {
this.startTime = startTime;
}
toPointValue() {
return this._current;
}
}
/** Basic aggregator which calculates a Sum from individual measurements. */
export class SumAggregator {
constructor(monotonic) {
this.monotonic = monotonic;
this.kind = AggregatorKind.SUM;
}
createAccumulation(startTime) {
return new SumAccumulation(startTime, this.monotonic);
}
/**
* Returns the result of the merge of the given accumulations.
*/
merge(previous, delta) {
const prevPv = previous.toPointValue();
const deltaPv = delta.toPointValue();
if (delta.reset) {
return new SumAccumulation(delta.startTime, this.monotonic, deltaPv, delta.reset);
}
return new SumAccumulation(previous.startTime, this.monotonic, prevPv + deltaPv);
}
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*/
diff(previous, current) {
const prevPv = previous.toPointValue();
const currPv = current.toPointValue();
/**
* If the SumAggregator is a monotonic one and the previous point value is
* greater than the current one, a reset is deemed to be happened.
* Return the current point value to prevent the value from been reset.
*/
if (this.monotonic && prevPv > currPv) {
return new SumAccumulation(current.startTime, this.monotonic, currPv, true);
}
return new SumAccumulation(current.startTime, this.monotonic, currPv - prevPv);
}
toMetricData(descriptor, aggregationTemporality, accumulationByAttributes, endTime) {
return {
descriptor,
aggregationTemporality,
dataPointType: DataPointType.SUM,
dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => {
return {
attributes,
startTime: accumulation.startTime,
endTime,
value: accumulation.toPointValue(),
};
}),
isMonotonic: this.monotonic,
};
}
}
//# sourceMappingURL=Sum.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,133 @@
export declare class Buckets {
backing: BucketsBacking;
indexBase: number;
indexStart: number;
indexEnd: number;
/**
* The term index refers to the number of the exponential histogram bucket
* used to determine its boundaries. The lower boundary of a bucket is
* determined by base ** index and the upper boundary of a bucket is
* determined by base ** (index + 1). index values are signed to account
* for values less than or equal to 1.
*
* indexBase is the index of the 0th position in the
* backing array, i.e., backing[0] is the count
* in the bucket with index `indexBase`.
*
* indexStart is the smallest index value represented
* in the backing array.
*
* indexEnd is the largest index value represented in
* the backing array.
*/
constructor(backing?: BucketsBacking, indexBase?: number, indexStart?: number, indexEnd?: number);
/**
* Offset is the bucket index of the smallest entry in the counts array
* @returns {number}
*/
get offset(): number;
/**
* Buckets is a view into the backing array.
* @returns {number}
*/
get length(): number;
/**
* An array of counts, where count[i] carries the count
* of the bucket at index (offset+i). count[i] is the count of
* values greater than base^(offset+i) and less than or equal to
* base^(offset+i+1).
* @returns {number} The logical counts based on the backing array
*/
counts(): number[];
/**
* At returns the count of the bucket at a position in the logical
* array of counts.
* @param position
* @returns {number}
*/
at(position: number): number;
/**
* incrementBucket increments the backing array index by `increment`
* @param bucketIndex
* @param increment
*/
incrementBucket(bucketIndex: number, increment: number): void;
/**
* decrementBucket decrements the backing array index by `decrement`
* if decrement is greater than the current value, it's set to 0.
* @param bucketIndex
* @param decrement
*/
decrementBucket(bucketIndex: number, decrement: number): void;
/**
* trim removes leading and / or trailing zero buckets (which can occur
* after diffing two histos) and rotates the backing array so that the
* smallest non-zero index is in the 0th position of the backing array
*/
trim(): void;
/**
* downscale first rotates, then collapses 2**`by`-to-1 buckets.
* @param by
*/
downscale(by: number): void;
/**
* Clone returns a deep copy of Buckets
* @returns {Buckets}
*/
clone(): Buckets;
/**
* _rotate shifts the backing array contents so that indexStart ==
* indexBase to simplify the downscale logic.
*/
private _rotate;
/**
* _relocateBucket adds the count in counts[src] to counts[dest] and
* resets count[src] to zero.
*/
private _relocateBucket;
}
/**
* BucketsBacking holds the raw buckets and some utility methods to
* manage them.
*/
declare class BucketsBacking {
private _counts;
constructor(_counts?: number[]);
/**
* length returns the physical size of the backing array, which
* is >= buckets.length()
*/
get length(): number;
/**
* countAt returns the count in a specific bucket
*/
countAt(pos: number): number;
/**
* growTo grows a backing array and copies old entries
* into their correct new positions.
*/
growTo(newSize: number, oldPositiveLimit: number, newPositiveLimit: number): void;
/**
* reverse the items in the backing array in the range [from, limit).
*/
reverse(from: number, limit: number): void;
/**
* emptyBucket empties the count from a bucket, for
* moving into another.
*/
emptyBucket(src: number): number;
/**
* increments a bucket by `increment`
*/
increment(bucketIndex: number, increment: number): void;
/**
* decrements a bucket by `decrement`
*/
decrement(bucketIndex: number, decrement: number): void;
/**
* clone returns a deep copy of BucketsBacking
*/
clone(): BucketsBacking;
}
export {};
//# sourceMappingURL=Buckets.d.ts.map

View File

@@ -0,0 +1,268 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class Buckets {
/**
* The term index refers to the number of the exponential histogram bucket
* used to determine its boundaries. The lower boundary of a bucket is
* determined by base ** index and the upper boundary of a bucket is
* determined by base ** (index + 1). index values are signed to account
* for values less than or equal to 1.
*
* indexBase is the index of the 0th position in the
* backing array, i.e., backing[0] is the count
* in the bucket with index `indexBase`.
*
* indexStart is the smallest index value represented
* in the backing array.
*
* indexEnd is the largest index value represented in
* the backing array.
*/
constructor(backing = new BucketsBacking(), indexBase = 0, indexStart = 0, indexEnd = 0) {
this.backing = backing;
this.indexBase = indexBase;
this.indexStart = indexStart;
this.indexEnd = indexEnd;
}
/**
* Offset is the bucket index of the smallest entry in the counts array
* @returns {number}
*/
get offset() {
return this.indexStart;
}
/**
* Buckets is a view into the backing array.
* @returns {number}
*/
get length() {
if (this.backing.length === 0) {
return 0;
}
if (this.indexEnd === this.indexStart && this.at(0) === 0) {
return 0;
}
return this.indexEnd - this.indexStart + 1;
}
/**
* An array of counts, where count[i] carries the count
* of the bucket at index (offset+i). count[i] is the count of
* values greater than base^(offset+i) and less than or equal to
* base^(offset+i+1).
* @returns {number} The logical counts based on the backing array
*/
counts() {
return Array.from({ length: this.length }, (_, i) => this.at(i));
}
/**
* At returns the count of the bucket at a position in the logical
* array of counts.
* @param position
* @returns {number}
*/
at(position) {
const bias = this.indexBase - this.indexStart;
if (position < bias) {
position += this.backing.length;
}
position -= bias;
return this.backing.countAt(position);
}
/**
* incrementBucket increments the backing array index by `increment`
* @param bucketIndex
* @param increment
*/
incrementBucket(bucketIndex, increment) {
this.backing.increment(bucketIndex, increment);
}
/**
* decrementBucket decrements the backing array index by `decrement`
* if decrement is greater than the current value, it's set to 0.
* @param bucketIndex
* @param decrement
*/
decrementBucket(bucketIndex, decrement) {
this.backing.decrement(bucketIndex, decrement);
}
/**
* trim removes leading and / or trailing zero buckets (which can occur
* after diffing two histos) and rotates the backing array so that the
* smallest non-zero index is in the 0th position of the backing array
*/
trim() {
for (let i = 0; i < this.length; i++) {
if (this.at(i) !== 0) {
this.indexStart += i;
break;
}
else if (i === this.length - 1) {
//the entire array is zeroed out
this.indexStart = this.indexEnd = this.indexBase = 0;
return;
}
}
for (let i = this.length - 1; i >= 0; i--) {
if (this.at(i) !== 0) {
this.indexEnd -= this.length - i - 1;
break;
}
}
this._rotate();
}
/**
* downscale first rotates, then collapses 2**`by`-to-1 buckets.
* @param by
*/
downscale(by) {
this._rotate();
const size = 1 + this.indexEnd - this.indexStart;
const each = 1 << by;
let inpos = 0;
let outpos = 0;
for (let pos = this.indexStart; pos <= this.indexEnd;) {
let mod = pos % each;
if (mod < 0) {
mod += each;
}
for (let i = mod; i < each && inpos < size; i++) {
this._relocateBucket(outpos, inpos);
inpos++;
pos++;
}
outpos++;
}
this.indexStart >>= by;
this.indexEnd >>= by;
this.indexBase = this.indexStart;
}
/**
* Clone returns a deep copy of Buckets
* @returns {Buckets}
*/
clone() {
return new Buckets(this.backing.clone(), this.indexBase, this.indexStart, this.indexEnd);
}
/**
* _rotate shifts the backing array contents so that indexStart ==
* indexBase to simplify the downscale logic.
*/
_rotate() {
const bias = this.indexBase - this.indexStart;
if (bias === 0) {
return;
}
else if (bias > 0) {
this.backing.reverse(0, this.backing.length);
this.backing.reverse(0, bias);
this.backing.reverse(bias, this.backing.length);
}
else {
// negative bias, this can happen when diffing two histograms
this.backing.reverse(0, this.backing.length);
this.backing.reverse(0, this.backing.length + bias);
}
this.indexBase = this.indexStart;
}
/**
* _relocateBucket adds the count in counts[src] to counts[dest] and
* resets count[src] to zero.
*/
_relocateBucket(dest, src) {
if (dest === src) {
return;
}
this.incrementBucket(dest, this.backing.emptyBucket(src));
}
}
/**
* BucketsBacking holds the raw buckets and some utility methods to
* manage them.
*/
class BucketsBacking {
constructor(_counts = [0]) {
this._counts = _counts;
}
/**
* length returns the physical size of the backing array, which
* is >= buckets.length()
*/
get length() {
return this._counts.length;
}
/**
* countAt returns the count in a specific bucket
*/
countAt(pos) {
return this._counts[pos];
}
/**
* growTo grows a backing array and copies old entries
* into their correct new positions.
*/
growTo(newSize, oldPositiveLimit, newPositiveLimit) {
const tmp = new Array(newSize).fill(0);
tmp.splice(newPositiveLimit, this._counts.length - oldPositiveLimit, ...this._counts.slice(oldPositiveLimit));
tmp.splice(0, oldPositiveLimit, ...this._counts.slice(0, oldPositiveLimit));
this._counts = tmp;
}
/**
* reverse the items in the backing array in the range [from, limit).
*/
reverse(from, limit) {
const num = Math.floor((from + limit) / 2) - from;
for (let i = 0; i < num; i++) {
const tmp = this._counts[from + i];
this._counts[from + i] = this._counts[limit - i - 1];
this._counts[limit - i - 1] = tmp;
}
}
/**
* emptyBucket empties the count from a bucket, for
* moving into another.
*/
emptyBucket(src) {
const tmp = this._counts[src];
this._counts[src] = 0;
return tmp;
}
/**
* increments a bucket by `increment`
*/
increment(bucketIndex, increment) {
this._counts[bucketIndex] += increment;
}
/**
* decrements a bucket by `decrement`
*/
decrement(bucketIndex, decrement) {
if (this._counts[bucketIndex] >= decrement) {
this._counts[bucketIndex] -= decrement;
}
else {
// this should not happen, but we're being defensive against
// negative counts.
this._counts[bucketIndex] = 0;
}
}
/**
* clone returns a deep copy of BucketsBacking
*/
clone() {
return new BucketsBacking([...this._counts]);
}
}
//# sourceMappingURL=Buckets.js.map

View File

@@ -0,0 +1,31 @@
import { Mapping } from './types';
/**
* ExponentMapping implements exponential mapping functions for
* scales <=0. For scales > 0 LogarithmMapping should be used.
*/
export declare class ExponentMapping implements Mapping {
private readonly _shift;
constructor(scale: number);
/**
* Maps positive floating point values to indexes corresponding to scale
* @param value
* @returns {number} index for provided value at the current scale
*/
mapToIndex(value: number): number;
/**
* Returns the lower bucket boundary for the given index for scale
*
* @param index
* @returns {number}
*/
lowerBoundary(index: number): number;
/**
* The scale used by this mapping
* @returns {number}
*/
get scale(): number;
private _minNormalLowerBoundaryIndex;
private _maxNormalLowerBoundaryIndex;
private _rightShift;
}
//# sourceMappingURL=ExponentMapping.d.ts.map

View File

@@ -0,0 +1,85 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as ieee754 from './ieee754';
import * as util from '../util';
import { MappingError } from './types';
/**
* ExponentMapping implements exponential mapping functions for
* scales <=0. For scales > 0 LogarithmMapping should be used.
*/
export class ExponentMapping {
constructor(scale) {
this._shift = -scale;
}
/**
* Maps positive floating point values to indexes corresponding to scale
* @param value
* @returns {number} index for provided value at the current scale
*/
mapToIndex(value) {
if (value < ieee754.MIN_VALUE) {
return this._minNormalLowerBoundaryIndex();
}
const exp = ieee754.getNormalBase2(value);
// In case the value is an exact power of two, compute a
// correction of -1. Note, we are using a custom _rightShift
// to accommodate a 52-bit argument, which the native bitwise
// operators do not support
const correction = this._rightShift(ieee754.getSignificand(value) - 1, ieee754.SIGNIFICAND_WIDTH);
return (exp + correction) >> this._shift;
}
/**
* Returns the lower bucket boundary for the given index for scale
*
* @param index
* @returns {number}
*/
lowerBoundary(index) {
const minIndex = this._minNormalLowerBoundaryIndex();
if (index < minIndex) {
throw new MappingError(`underflow: ${index} is < minimum lower boundary: ${minIndex}`);
}
const maxIndex = this._maxNormalLowerBoundaryIndex();
if (index > maxIndex) {
throw new MappingError(`overflow: ${index} is > maximum lower boundary: ${maxIndex}`);
}
return util.ldexp(1, index << this._shift);
}
/**
* The scale used by this mapping
* @returns {number}
*/
get scale() {
if (this._shift === 0) {
return 0;
}
return -this._shift;
}
_minNormalLowerBoundaryIndex() {
let index = ieee754.MIN_NORMAL_EXPONENT >> this._shift;
if (this._shift < 2) {
index--;
}
return index;
}
_maxNormalLowerBoundaryIndex() {
return ieee754.MAX_NORMAL_EXPONENT >> this._shift;
}
_rightShift(value, shift) {
return Math.floor(value * Math.pow(2, -shift));
}
}
//# sourceMappingURL=ExponentMapping.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExponentMapping.js","sourceRoot":"","sources":["../../../../../src/aggregator/exponential-histogram/mapping/ExponentMapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAW,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAO,eAAe;IAG1B,YAAY,KAAa;QACvB,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,KAAa;QACtB,IAAI,KAAK,GAAG,OAAO,CAAC,SAAS,EAAE;YAC7B,OAAO,IAAI,CAAC,4BAA4B,EAAE,CAAC;SAC5C;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAE1C,wDAAwD;QACxD,4DAA4D;QAC5D,6DAA6D;QAC7D,2BAA2B;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CACjC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,EACjC,OAAO,CAAC,iBAAiB,CAC1B,CAAC;QAEF,OAAO,CAAC,GAAG,GAAG,UAAU,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,KAAa;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAC;QACrD,IAAI,KAAK,GAAG,QAAQ,EAAE;YACpB,MAAM,IAAI,YAAY,CACpB,cAAc,KAAK,iCAAiC,QAAQ,EAAE,CAC/D,CAAC;SACH;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAC;QACrD,IAAI,KAAK,GAAG,QAAQ,EAAE;YACpB,MAAM,IAAI,YAAY,CACpB,aAAa,KAAK,iCAAiC,QAAQ,EAAE,CAC9D,CAAC;SACH;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,IAAI,KAAK;QACP,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;YACrB,OAAO,CAAC,CAAC;SACV;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;IACtB,CAAC;IAEO,4BAA4B;QAClC,IAAI,KAAK,GAAG,OAAO,CAAC,mBAAmB,IAAI,IAAI,CAAC,MAAM,CAAC;QACvD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACnB,KAAK,EAAE,CAAC;SACT;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,4BAA4B;QAClC,OAAO,OAAO,CAAC,mBAAmB,IAAI,IAAI,CAAC,MAAM,CAAC;IACpD,CAAC;IAEO,WAAW,CAAC,KAAa,EAAE,KAAa;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as ieee754 from './ieee754';\nimport * as util from '../util';\nimport { Mapping, MappingError } from './types';\n\n/**\n * ExponentMapping implements exponential mapping functions for\n * scales <=0. For scales > 0 LogarithmMapping should be used.\n */\nexport class ExponentMapping implements Mapping {\n private readonly _shift: number;\n\n constructor(scale: number) {\n this._shift = -scale;\n }\n\n /**\n * Maps positive floating point values to indexes corresponding to scale\n * @param value\n * @returns {number} index for provided value at the current scale\n */\n mapToIndex(value: number): number {\n if (value < ieee754.MIN_VALUE) {\n return this._minNormalLowerBoundaryIndex();\n }\n\n const exp = ieee754.getNormalBase2(value);\n\n // In case the value is an exact power of two, compute a\n // correction of -1. Note, we are using a custom _rightShift\n // to accommodate a 52-bit argument, which the native bitwise\n // operators do not support\n const correction = this._rightShift(\n ieee754.getSignificand(value) - 1,\n ieee754.SIGNIFICAND_WIDTH\n );\n\n return (exp + correction) >> this._shift;\n }\n\n /**\n * Returns the lower bucket boundary for the given index for scale\n *\n * @param index\n * @returns {number}\n */\n lowerBoundary(index: number): number {\n const minIndex = this._minNormalLowerBoundaryIndex();\n if (index < minIndex) {\n throw new MappingError(\n `underflow: ${index} is < minimum lower boundary: ${minIndex}`\n );\n }\n const maxIndex = this._maxNormalLowerBoundaryIndex();\n if (index > maxIndex) {\n throw new MappingError(\n `overflow: ${index} is > maximum lower boundary: ${maxIndex}`\n );\n }\n\n return util.ldexp(1, index << this._shift);\n }\n\n /**\n * The scale used by this mapping\n * @returns {number}\n */\n get scale(): number {\n if (this._shift === 0) {\n return 0;\n }\n return -this._shift;\n }\n\n private _minNormalLowerBoundaryIndex(): number {\n let index = ieee754.MIN_NORMAL_EXPONENT >> this._shift;\n if (this._shift < 2) {\n index--;\n }\n\n return index;\n }\n\n private _maxNormalLowerBoundaryIndex(): number {\n return ieee754.MAX_NORMAL_EXPONENT >> this._shift;\n }\n\n private _rightShift(value: number, shift: number): number {\n return Math.floor(value * Math.pow(2, -shift));\n }\n}\n"]}

View File

@@ -0,0 +1,32 @@
import { Mapping } from './types';
/**
* LogarithmMapping implements exponential mapping functions for scale > 0.
* For scales <= 0 the exponent mapping should be used.
*/
export declare class LogarithmMapping implements Mapping {
private readonly _scale;
private readonly _scaleFactor;
private readonly _inverseFactor;
constructor(scale: number);
/**
* Maps positive floating point values to indexes corresponding to scale
* @param value
* @returns {number} index for provided value at the current scale
*/
mapToIndex(value: number): number;
/**
* Returns the lower bucket boundary for the given index for scale
*
* @param index
* @returns {number}
*/
lowerBoundary(index: number): number;
/**
* The scale used by this mapping
* @returns {number}
*/
get scale(): number;
private _minNormalLowerBoundaryIndex;
private _maxNormalLowerBoundaryIndex;
}
//# sourceMappingURL=LogarithmMapping.d.ts.map

View File

@@ -0,0 +1,91 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as ieee754 from './ieee754';
import * as util from '../util';
import { MappingError } from './types';
/**
* LogarithmMapping implements exponential mapping functions for scale > 0.
* For scales <= 0 the exponent mapping should be used.
*/
export class LogarithmMapping {
constructor(scale) {
this._scale = scale;
this._scaleFactor = util.ldexp(Math.LOG2E, scale);
this._inverseFactor = util.ldexp(Math.LN2, -scale);
}
/**
* Maps positive floating point values to indexes corresponding to scale
* @param value
* @returns {number} index for provided value at the current scale
*/
mapToIndex(value) {
if (value <= ieee754.MIN_VALUE) {
return this._minNormalLowerBoundaryIndex() - 1;
}
// exact power of two special case
if (ieee754.getSignificand(value) === 0) {
const exp = ieee754.getNormalBase2(value);
return (exp << this._scale) - 1;
}
// non-power of two cases. use Math.floor to round the scaled logarithm
const index = Math.floor(Math.log(value) * this._scaleFactor);
const maxIndex = this._maxNormalLowerBoundaryIndex();
if (index >= maxIndex) {
return maxIndex;
}
return index;
}
/**
* Returns the lower bucket boundary for the given index for scale
*
* @param index
* @returns {number}
*/
lowerBoundary(index) {
const maxIndex = this._maxNormalLowerBoundaryIndex();
if (index >= maxIndex) {
if (index === maxIndex) {
return 2 * Math.exp((index - (1 << this._scale)) / this._scaleFactor);
}
throw new MappingError(`overflow: ${index} is > maximum lower boundary: ${maxIndex}`);
}
const minIndex = this._minNormalLowerBoundaryIndex();
if (index <= minIndex) {
if (index === minIndex) {
return ieee754.MIN_VALUE;
}
else if (index === minIndex - 1) {
return Math.exp((index + (1 << this._scale)) / this._scaleFactor) / 2;
}
throw new MappingError(`overflow: ${index} is < minimum lower boundary: ${minIndex}`);
}
return Math.exp(index * this._inverseFactor);
}
/**
* The scale used by this mapping
* @returns {number}
*/
get scale() {
return this._scale;
}
_minNormalLowerBoundaryIndex() {
return ieee754.MIN_NORMAL_EXPONENT << this._scale;
}
_maxNormalLowerBoundaryIndex() {
return ((ieee754.MAX_NORMAL_EXPONENT + 1) << this._scale) - 1;
}
}
//# sourceMappingURL=LogarithmMapping.js.map

View File

@@ -0,0 +1,10 @@
import { Mapping } from './types';
/**
* getMapping returns an appropriate mapping for the given scale. For scales -10
* to 0 the underlying type will be ExponentMapping. For scales 1 to 20 the
* underlying type will be LogarithmMapping.
* @param scale a number in the range [-10, 20]
* @returns {Mapping}
*/
export declare function getMapping(scale: number): Mapping;
//# sourceMappingURL=getMapping.d.ts.map

View File

@@ -0,0 +1,41 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ExponentMapping } from './ExponentMapping';
import { LogarithmMapping } from './LogarithmMapping';
import { MappingError } from './types';
const MIN_SCALE = -10;
const MAX_SCALE = 20;
const PREBUILT_MAPPINGS = Array.from({ length: 31 }, (_, i) => {
if (i > 10) {
return new LogarithmMapping(i - 10);
}
return new ExponentMapping(i - 10);
});
/**
* getMapping returns an appropriate mapping for the given scale. For scales -10
* to 0 the underlying type will be ExponentMapping. For scales 1 to 20 the
* underlying type will be LogarithmMapping.
* @param scale a number in the range [-10, 20]
* @returns {Mapping}
*/
export function getMapping(scale) {
if (scale > MAX_SCALE || scale < MIN_SCALE) {
throw new MappingError(`expected scale >= ${MIN_SCALE} && <= ${MAX_SCALE}, got: ${scale}`);
}
// mappings are offset by 10. scale -10 is at position 0 and scale 20 is at 30
return PREBUILT_MAPPINGS[scale + 10];
}
//# sourceMappingURL=getMapping.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getMapping.js","sourceRoot":"","sources":["../../../../../src/aggregator/exponential-histogram/mapping/getMapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAW,MAAM,SAAS,CAAC;AAEhD,MAAM,SAAS,GAAG,CAAC,EAAE,CAAC;AACtB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;IAC5D,IAAI,CAAC,GAAG,EAAE,EAAE;QACV,OAAO,IAAI,gBAAgB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;KACrC;IACD,OAAO,IAAI,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,GAAG,SAAS,IAAI,KAAK,GAAG,SAAS,EAAE;QAC1C,MAAM,IAAI,YAAY,CACpB,qBAAqB,SAAS,UAAU,SAAS,UAAU,KAAK,EAAE,CACnE,CAAC;KACH;IACD,8EAA8E;IAC9E,OAAO,iBAAiB,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;AACvC,CAAC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ExponentMapping } from './ExponentMapping';\nimport { LogarithmMapping } from './LogarithmMapping';\nimport { MappingError, Mapping } from './types';\n\nconst MIN_SCALE = -10;\nconst MAX_SCALE = 20;\nconst PREBUILT_MAPPINGS = Array.from({ length: 31 }, (_, i) => {\n if (i > 10) {\n return new LogarithmMapping(i - 10);\n }\n return new ExponentMapping(i - 10);\n});\n\n/**\n * getMapping returns an appropriate mapping for the given scale. For scales -10\n * to 0 the underlying type will be ExponentMapping. For scales 1 to 20 the\n * underlying type will be LogarithmMapping.\n * @param scale a number in the range [-10, 20]\n * @returns {Mapping}\n */\nexport function getMapping(scale: number): Mapping {\n if (scale > MAX_SCALE || scale < MIN_SCALE) {\n throw new MappingError(\n `expected scale >= ${MIN_SCALE} && <= ${MAX_SCALE}, got: ${scale}`\n );\n }\n // mappings are offset by 10. scale -10 is at position 0 and scale 20 is at 30\n return PREBUILT_MAPPINGS[scale + 10];\n}\n"]}

View File

@@ -0,0 +1,41 @@
/**
* The functions and constants in this file allow us to interact
* with the internal representation of an IEEE 64-bit floating point
* number. We need to work with all 64-bits, thus, care needs to be
* taken when working with Javascript's bitwise operators (<<, >>, &,
* |, etc) as they truncate operands to 32-bits. In order to work around
* this we work with the 64-bits as two 32-bit halves, perform bitwise
* operations on them independently, and combine the results (if needed).
*/
export declare const SIGNIFICAND_WIDTH = 52;
/**
* MIN_NORMAL_EXPONENT is the minimum exponent of a normalized
* floating point: -1022.
*/
export declare const MIN_NORMAL_EXPONENT: number;
/**
* MAX_NORMAL_EXPONENT is the maximum exponent of a normalized
* floating point: 1023.
*/
export declare const MAX_NORMAL_EXPONENT = 1023;
/**
* MIN_VALUE is the smallest normal number
*/
export declare const MIN_VALUE: number;
/**
* getNormalBase2 extracts the normalized base-2 fractional exponent.
* This returns k for the equation f x 2**k where f is
* in the range [1, 2). Note that this function is not called for
* subnormal numbers.
* @param {number} value - the value to determine normalized base-2 fractional
* exponent for
* @returns {number} the normalized base-2 exponent
*/
export declare function getNormalBase2(value: number): number;
/**
* GetSignificand returns the 52 bit (unsigned) significand as a signed value.
* @param {number} value - the floating point number to extract the significand from
* @returns {number} The 52-bit significand
*/
export declare function getSignificand(value: number): number;
//# sourceMappingURL=ieee754.d.ts.map

View File

@@ -0,0 +1,89 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The functions and constants in this file allow us to interact
* with the internal representation of an IEEE 64-bit floating point
* number. We need to work with all 64-bits, thus, care needs to be
* taken when working with Javascript's bitwise operators (<<, >>, &,
* |, etc) as they truncate operands to 32-bits. In order to work around
* this we work with the 64-bits as two 32-bit halves, perform bitwise
* operations on them independently, and combine the results (if needed).
*/
export const SIGNIFICAND_WIDTH = 52;
/**
* EXPONENT_MASK is set to 1 for the hi 32-bits of an IEEE 754
* floating point exponent: 0x7ff00000.
*/
const EXPONENT_MASK = 0x7ff00000;
/**
* SIGNIFICAND_MASK is the mask for the significand portion of the hi 32-bits
* of an IEEE 754 double-precision floating-point value: 0xfffff
*/
const SIGNIFICAND_MASK = 0xfffff;
/**
* EXPONENT_BIAS is the exponent bias specified for encoding
* the IEEE 754 double-precision floating point exponent: 1023
*/
const EXPONENT_BIAS = 1023;
/**
* MIN_NORMAL_EXPONENT is the minimum exponent of a normalized
* floating point: -1022.
*/
export const MIN_NORMAL_EXPONENT = -EXPONENT_BIAS + 1;
/**
* MAX_NORMAL_EXPONENT is the maximum exponent of a normalized
* floating point: 1023.
*/
export const MAX_NORMAL_EXPONENT = EXPONENT_BIAS;
/**
* MIN_VALUE is the smallest normal number
*/
export const MIN_VALUE = Math.pow(2, -1022);
/**
* getNormalBase2 extracts the normalized base-2 fractional exponent.
* This returns k for the equation f x 2**k where f is
* in the range [1, 2). Note that this function is not called for
* subnormal numbers.
* @param {number} value - the value to determine normalized base-2 fractional
* exponent for
* @returns {number} the normalized base-2 exponent
*/
export function getNormalBase2(value) {
const dv = new DataView(new ArrayBuffer(8));
dv.setFloat64(0, value);
// access the raw 64-bit float as 32-bit uints
const hiBits = dv.getUint32(0);
const expBits = (hiBits & EXPONENT_MASK) >> 20;
return expBits - EXPONENT_BIAS;
}
/**
* GetSignificand returns the 52 bit (unsigned) significand as a signed value.
* @param {number} value - the floating point number to extract the significand from
* @returns {number} The 52-bit significand
*/
export function getSignificand(value) {
const dv = new DataView(new ArrayBuffer(8));
dv.setFloat64(0, value);
// access the raw 64-bit float as two 32-bit uints
const hiBits = dv.getUint32(0);
const loBits = dv.getUint32(4);
// extract the significand bits from the hi bits and left shift 32 places note:
// we can't use the native << operator as it will truncate the result to 32-bits
const significandHiBits = (hiBits & SIGNIFICAND_MASK) * Math.pow(2, 32);
// combine the hi and lo bits and return
return significandHiBits + loBits;
}
//# sourceMappingURL=ieee754.js.map

View File

@@ -0,0 +1,13 @@
export declare class MappingError extends Error {
}
/**
* The mapping interface is used by the exponential histogram to determine
* where to bucket values. The interface is implemented by ExponentMapping,
* used for scales [-10, 0] and LogarithmMapping, used for scales [1, 20].
*/
export interface Mapping {
mapToIndex(value: number): number;
lowerBoundary(index: number): number;
get scale(): number;
}
//# sourceMappingURL=types.d.ts.map

View File

@@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class MappingError extends Error {
}
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/aggregator/exponential-histogram/mapping/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;CAAG","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport class MappingError extends Error {}\n\n/**\n * The mapping interface is used by the exponential histogram to determine\n * where to bucket values. The interface is implemented by ExponentMapping,\n * used for scales [-10, 0] and LogarithmMapping, used for scales [1, 20].\n */\nexport interface Mapping {\n mapToIndex(value: number): number;\n lowerBoundary(index: number): number;\n get scale(): number;\n}\n"]}

View File

@@ -0,0 +1,23 @@
/**
* Note: other languages provide this as a built in function. This is
* a naive, but functionally correct implementation. This is used sparingly,
* when creating a new mapping in a running application.
*
* ldexp returns frac × 2**exp. With the following special cases:
* ldexp(±0, exp) = ±0
* ldexp(±Inf, exp) = ±Inf
* ldexp(NaN, exp) = NaN
* @param frac
* @param exp
* @returns {number}
*/
export declare function ldexp(frac: number, exp: number): number;
/**
* Computes the next power of two that is greater than or equal to v.
* This implementation more efficient than, but functionally equivalent
* to Math.pow(2, Math.ceil(Math.log(x)/Math.log(2))).
* @param v
* @returns {number}
*/
export declare function nextGreaterSquare(v: number): number;
//# sourceMappingURL=util.d.ts.map

View File

@@ -0,0 +1,58 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Note: other languages provide this as a built in function. This is
* a naive, but functionally correct implementation. This is used sparingly,
* when creating a new mapping in a running application.
*
* ldexp returns frac × 2**exp. With the following special cases:
* ldexp(±0, exp) = ±0
* ldexp(±Inf, exp) = ±Inf
* ldexp(NaN, exp) = NaN
* @param frac
* @param exp
* @returns {number}
*/
export function ldexp(frac, exp) {
if (frac === 0 ||
frac === Number.POSITIVE_INFINITY ||
frac === Number.NEGATIVE_INFINITY ||
Number.isNaN(frac)) {
return frac;
}
return frac * Math.pow(2, exp);
}
/**
* Computes the next power of two that is greater than or equal to v.
* This implementation more efficient than, but functionally equivalent
* to Math.pow(2, Math.ceil(Math.log(x)/Math.log(2))).
* @param v
* @returns {number}
*/
export function nextGreaterSquare(v) {
// The following expression computes the least power-of-two
// that is >= v. There are a number of tricky ways to
// do this, see https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
//# sourceMappingURL=util.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../../src/aggregator/exponential-histogram/util.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,GAAW;IAC7C,IACE,IAAI,KAAK,CAAC;QACV,IAAI,KAAK,MAAM,CAAC,iBAAiB;QACjC,IAAI,KAAK,MAAM,CAAC,iBAAiB;QACjC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAClB;QACA,OAAO,IAAI,CAAC;KACb;IACD,OAAO,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,2DAA2D;IAC3D,sDAAsD;IACtD,yFAAyF;IACzF,CAAC,EAAE,CAAC;IACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACZ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC,EAAE,CAAC;IACJ,OAAO,CAAC,CAAC;AACX,CAAC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Note: other languages provide this as a built in function. This is\n * a naive, but functionally correct implementation. This is used sparingly,\n * when creating a new mapping in a running application.\n *\n * ldexp returns frac × 2**exp. With the following special cases:\n * ldexp(±0, exp) = ±0\n * ldexp(±Inf, exp) = ±Inf\n * ldexp(NaN, exp) = NaN\n * @param frac\n * @param exp\n * @returns {number}\n */\nexport function ldexp(frac: number, exp: number): number {\n if (\n frac === 0 ||\n frac === Number.POSITIVE_INFINITY ||\n frac === Number.NEGATIVE_INFINITY ||\n Number.isNaN(frac)\n ) {\n return frac;\n }\n return frac * Math.pow(2, exp);\n}\n\n/**\n * Computes the next power of two that is greater than or equal to v.\n * This implementation more efficient than, but functionally equivalent\n * to Math.pow(2, Math.ceil(Math.log(x)/Math.log(2))).\n * @param v\n * @returns {number}\n */\nexport function nextGreaterSquare(v: number): number {\n // The following expression computes the least power-of-two\n // that is >= v. There are a number of tricky ways to\n // do this, see https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2\n v--;\n v |= v >> 1;\n v |= v >> 2;\n v |= v >> 4;\n v |= v >> 8;\n v |= v >> 16;\n v++;\n return v;\n}\n"]}

View File

@@ -0,0 +1,7 @@
export { DropAggregator } from './Drop';
export { HistogramAccumulation, HistogramAggregator } from './Histogram';
export { ExponentialHistogramAccumulation, ExponentialHistogramAggregator, } from './ExponentialHistogram';
export { LastValueAccumulation, LastValueAggregator } from './LastValue';
export { SumAccumulation, SumAggregator } from './Sum';
export { Aggregator } from './types';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { DropAggregator } from './Drop';
export { HistogramAccumulation, HistogramAggregator } from './Histogram';
export { ExponentialHistogramAccumulation, ExponentialHistogramAggregator, } from './ExponentialHistogram';
export { LastValueAccumulation, LastValueAggregator } from './LastValue';
export { SumAccumulation, SumAggregator } from './Sum';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/aggregator/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EACL,gCAAgC,EAChC,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport { DropAggregator } from './Drop';\nexport { HistogramAccumulation, HistogramAggregator } from './Histogram';\nexport {\n ExponentialHistogramAccumulation,\n ExponentialHistogramAggregator,\n} from './ExponentialHistogram';\nexport { LastValueAccumulation, LastValueAggregator } from './LastValue';\nexport { SumAccumulation, SumAggregator } from './Sum';\nexport { Aggregator } from './types';\n"]}

View File

@@ -0,0 +1,110 @@
import { HrTime, Attributes } from '@opentelemetry/api';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { MetricData, MetricDescriptor } from '../export/MetricData';
import { Maybe } from '../utils';
/** The kind of aggregator. */
export declare enum AggregatorKind {
DROP = 0,
SUM = 1,
LAST_VALUE = 2,
HISTOGRAM = 3,
EXPONENTIAL_HISTOGRAM = 4
}
/** DataPoint value type for SumAggregation. */
export declare type Sum = number;
/** DataPoint value type for LastValueAggregation. */
export declare type LastValue = number;
/** DataPoint value type for HistogramAggregation. */
export interface Histogram {
/**
* Buckets are implemented using two different arrays:
* - boundaries: contains every finite bucket boundary, which are inclusive upper bounds
* - counts: contains event counts for each bucket
*
* Note that we'll always have n+1 buckets, where n is the number of boundaries.
* This is because we need to count events that are higher than the upper boundary.
*
* Example: if we measure the values: [5, 30, 5, 40, 5, 15, 15, 15, 25]
* with the boundaries [ 10, 20, 30 ], we will have the following state:
*
* buckets: {
* boundaries: [10, 20, 30],
* counts: [3, 3, 2, 1],
* }
*/
buckets: {
boundaries: number[];
counts: number[];
};
sum?: number;
count: number;
min?: number;
max?: number;
}
/** DataPoint value type for ExponentialHistogramAggregation. */
export interface ExponentialHistogram {
count: number;
sum?: number;
scale: number;
zeroCount: number;
positive: {
offset: number;
bucketCounts: number[];
};
negative: {
offset: number;
bucketCounts: number[];
};
min?: number;
max?: number;
}
/**
* An Aggregator accumulation state.
*/
export interface Accumulation {
setStartTime(startTime: HrTime): void;
record(value: number): void;
}
export declare type AccumulationRecord<T> = [Attributes, T];
/**
* Base interface for aggregators. Aggregators are responsible for holding
* aggregated values and taking a snapshot of these values upon export.
*/
export interface Aggregator<T> {
/** The kind of the aggregator. */
kind: AggregatorKind;
/**
* Create a clean state of accumulation.
*/
createAccumulation(startTime: HrTime): T;
/**
* Returns the result of the merge of the given accumulations.
*
* This should always assume that the accumulations do not overlap and merge together for a new
* cumulative report.
*
* @param previous the previously captured accumulation
* @param delta the newly captured (delta) accumulation
* @returns the result of the merge of the given accumulations
*/
merge(previous: T, delta: T): T;
/**
* Returns a new DELTA aggregation by comparing two cumulative measurements.
*
* @param previous the previously captured accumulation
* @param current the newly captured (cumulative) accumulation
* @returns The resulting delta accumulation
*/
diff(previous: T, current: T): T;
/**
* Returns the {@link MetricData} that this {@link Aggregator} will produce.
*
* @param descriptor the metric descriptor.
* @param aggregationTemporality the temporality of the resulting {@link MetricData}
* @param accumulationByAttributes the array of attributes and accumulation pairs.
* @param endTime the end time of the metric data.
* @return the {@link MetricData} that this {@link Aggregator} will produce.
*/
toMetricData(descriptor: MetricDescriptor, aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord<T>[], endTime: HrTime): Maybe<MetricData>;
}
//# sourceMappingURL=types.d.ts.map

View File

@@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** The kind of aggregator. */
export var AggregatorKind;
(function (AggregatorKind) {
AggregatorKind[AggregatorKind["DROP"] = 0] = "DROP";
AggregatorKind[AggregatorKind["SUM"] = 1] = "SUM";
AggregatorKind[AggregatorKind["LAST_VALUE"] = 2] = "LAST_VALUE";
AggregatorKind[AggregatorKind["HISTOGRAM"] = 3] = "HISTOGRAM";
AggregatorKind[AggregatorKind["EXPONENTIAL_HISTOGRAM"] = 4] = "EXPONENTIAL_HISTOGRAM";
})(AggregatorKind || (AggregatorKind = {}));
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/aggregator/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,8BAA8B;AAC9B,MAAM,CAAN,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,mDAAI,CAAA;IACJ,iDAAG,CAAA;IACH,+DAAU,CAAA;IACV,6DAAS,CAAA;IACT,qFAAqB,CAAA;AACvB,CAAC,EANW,cAAc,KAAd,cAAc,QAMzB","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { HrTime, Attributes } from '@opentelemetry/api';\nimport { AggregationTemporality } from '../export/AggregationTemporality';\nimport { MetricData, MetricDescriptor } from '../export/MetricData';\nimport { Maybe } from '../utils';\n\n/** The kind of aggregator. */\nexport enum AggregatorKind {\n DROP,\n SUM,\n LAST_VALUE,\n HISTOGRAM,\n EXPONENTIAL_HISTOGRAM,\n}\n\n/** DataPoint value type for SumAggregation. */\nexport type Sum = number;\n\n/** DataPoint value type for LastValueAggregation. */\nexport type LastValue = number;\n\n/** DataPoint value type for HistogramAggregation. */\nexport interface Histogram {\n /**\n * Buckets are implemented using two different arrays:\n * - boundaries: contains every finite bucket boundary, which are inclusive upper bounds\n * - counts: contains event counts for each bucket\n *\n * Note that we'll always have n+1 buckets, where n is the number of boundaries.\n * This is because we need to count events that are higher than the upper boundary.\n *\n * Example: if we measure the values: [5, 30, 5, 40, 5, 15, 15, 15, 25]\n * with the boundaries [ 10, 20, 30 ], we will have the following state:\n *\n * buckets: {\n *\tboundaries: [10, 20, 30],\n *\tcounts: [3, 3, 2, 1],\n * }\n */\n buckets: {\n boundaries: number[];\n counts: number[];\n };\n sum?: number;\n count: number;\n min?: number;\n max?: number;\n}\n\n/** DataPoint value type for ExponentialHistogramAggregation. */\nexport interface ExponentialHistogram {\n count: number;\n sum?: number;\n scale: number;\n zeroCount: number;\n positive: {\n offset: number;\n bucketCounts: number[];\n };\n negative: {\n offset: number;\n bucketCounts: number[];\n };\n min?: number;\n max?: number;\n}\n\n/**\n * An Aggregator accumulation state.\n */\nexport interface Accumulation {\n setStartTime(startTime: HrTime): void;\n record(value: number): void;\n}\n\nexport type AccumulationRecord<T> = [Attributes, T];\n\n/**\n * Base interface for aggregators. Aggregators are responsible for holding\n * aggregated values and taking a snapshot of these values upon export.\n */\nexport interface Aggregator<T> {\n /** The kind of the aggregator. */\n kind: AggregatorKind;\n\n /**\n * Create a clean state of accumulation.\n */\n createAccumulation(startTime: HrTime): T;\n\n /**\n * Returns the result of the merge of the given accumulations.\n *\n * This should always assume that the accumulations do not overlap and merge together for a new\n * cumulative report.\n *\n * @param previous the previously captured accumulation\n * @param delta the newly captured (delta) accumulation\n * @returns the result of the merge of the given accumulations\n */\n merge(previous: T, delta: T): T;\n\n /**\n * Returns a new DELTA aggregation by comparing two cumulative measurements.\n *\n * @param previous the previously captured accumulation\n * @param current the newly captured (cumulative) accumulation\n * @returns The resulting delta accumulation\n */\n diff(previous: T, current: T): T;\n\n /**\n * Returns the {@link MetricData} that this {@link Aggregator} will produce.\n *\n * @param descriptor the metric descriptor.\n * @param aggregationTemporality the temporality of the resulting {@link MetricData}\n * @param accumulationByAttributes the array of attributes and accumulation pairs.\n * @param endTime the end time of the metric data.\n * @return the {@link MetricData} that this {@link Aggregator} will produce.\n */\n toMetricData(\n descriptor: MetricDescriptor,\n aggregationTemporality: AggregationTemporality,\n accumulationByAttributes: AccumulationRecord<T>[],\n endTime: HrTime\n ): Maybe<MetricData>;\n}\n"]}