diff --git a/packages/opentelemetry-api/src/metrics/Meter.ts b/packages/opentelemetry-api/src/metrics/Meter.ts
index 5ed8bbf3a9..687dea4603 100644
--- a/packages/opentelemetry-api/src/metrics/Meter.ts
+++ b/packages/opentelemetry-api/src/metrics/Meter.ts
@@ -14,7 +14,13 @@
* limitations under the License.
*/
-import { MetricOptions, Counter, ValueRecorder, Observer } from './Metric';
+import {
+ MetricOptions,
+ Counter,
+ ValueRecorder,
+ Observer,
+ UpDownCounter,
+} from './Metric';
/**
* An interface to allow the recording metrics.
@@ -40,6 +46,25 @@ export interface Meter {
*/
createCounter(name: string, options?: MetricOptions): Counter;
+ /**
+ * Creates a new `UpDownCounter` metric. UpDownCounter is a synchronous
+ * instrument and very similar to Counter except that Add(increment)
+ * supports negative increments. It is generally useful for capturing changes
+ * in an amount of resources used, or any quantity that rises and falls
+ * during a request.
+ * Example uses for UpDownCounter:
+ *
+ * - count the number of active requests.
+ * - count memory in use by instrumenting new and delete.
+ * - count queue size by instrumenting enqueue and dequeue.
+ * - count semaphore up and down operations.
+ *
+ *
+ * @param name the name of the metric.
+ * @param [options] the metric options.
+ */
+ createUpDownCounter(name: string, options?: MetricOptions): UpDownCounter;
+
/**
* Creates a new `Observer` metric.
* @param name the name of the metric.
diff --git a/packages/opentelemetry-api/src/metrics/Metric.ts b/packages/opentelemetry-api/src/metrics/Metric.ts
index 23118369fa..6effd30946 100644
--- a/packages/opentelemetry-api/src/metrics/Metric.ts
+++ b/packages/opentelemetry-api/src/metrics/Metric.ts
@@ -48,12 +48,7 @@ export interface MetricOptions {
disabled?: boolean;
/**
- * Asserts that this metric may only increase (e.g. time spent).
- */
- monotonic?: boolean;
-
- /**
- * (ValueRecorder only, default true) Asserts that this metric will only accept
+ * (Measure only, default true) Asserts that this metric will only accept
* non-negative values (e.g. disk usage).
*/
absolute?: boolean;
@@ -125,6 +120,13 @@ export interface Counter extends UnboundMetric {
add(value: number, labels?: Labels): void;
}
+export interface UpDownCounter extends UnboundMetric {
+ /**
+ * Adds the given value to the current value. Values can be negative.
+ */
+ add(value: number, labels?: Labels): void;
+}
+
export interface ValueRecorder extends UnboundMetric {
/**
* Records the given value to this value recorder.
diff --git a/packages/opentelemetry-api/src/metrics/NoopMeter.ts b/packages/opentelemetry-api/src/metrics/NoopMeter.ts
index eed8c4e9bf..3cd7e42ebd 100644
--- a/packages/opentelemetry-api/src/metrics/NoopMeter.ts
+++ b/packages/opentelemetry-api/src/metrics/NoopMeter.ts
@@ -22,6 +22,7 @@ import {
Counter,
ValueRecorder,
Observer,
+ UpDownCounter,
} from './Metric';
import { BoundValueRecorder, BoundCounter } from './BoundInstrument';
import { CorrelationContext } from '../correlation_context/CorrelationContext';
@@ -53,6 +54,15 @@ export class NoopMeter implements Meter {
return NOOP_COUNTER_METRIC;
}
+ /**
+ * Returns a constant noop UpDownCounter.
+ * @param name the name of the metric.
+ * @param [options] the metric options.
+ */
+ createUpDownCounter(name: string, options?: MetricOptions): UpDownCounter {
+ return NOOP_COUNTER_METRIC;
+ }
+
/**
* Returns constant noop observer.
* @param name the name of the metric.
diff --git a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts
index fa1bdc3a35..1532717b48 100644
--- a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts
+++ b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts
@@ -191,10 +191,9 @@ export class PrometheusExporter implements MetricExporter {
switch (record.descriptor.metricKind) {
case MetricKind.COUNTER:
- // there is no such thing as a non-monotonic counter in prometheus
- return record.descriptor.monotonic
- ? new Counter(metricObject)
- : new Gauge(metricObject);
+ return new Counter(metricObject);
+ case MetricKind.UP_DOWN_COUNTER:
+ return new Gauge(metricObject);
case MetricKind.OBSERVER:
return new Gauge(metricObject);
default:
diff --git a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts
index 5e1e426862..e31c154bae 100644
--- a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts
+++ b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts
@@ -384,10 +384,9 @@ describe('PrometheusExporter', () => {
});
});
- it('should export a non-monotonic counter as a gauge', done => {
- const counter = meter.createCounter('counter', {
+ it('should export a UpDownCounter as a gauge', done => {
+ const counter = meter.createUpDownCounter('counter', {
description: 'a test description',
- monotonic: false,
});
counter.bind({ key1: 'labelValue1' }).add(20);
diff --git a/packages/opentelemetry-metrics/src/BoundInstrument.ts b/packages/opentelemetry-metrics/src/BoundInstrument.ts
index 8f660c3722..fd6966b1b3 100644
--- a/packages/opentelemetry-metrics/src/BoundInstrument.ts
+++ b/packages/opentelemetry-metrics/src/BoundInstrument.ts
@@ -24,19 +24,16 @@ import { Aggregator } from './export/types';
export class BaseBoundInstrument {
protected _labels: api.Labels;
protected _logger: api.Logger;
- protected _monotonic: boolean;
constructor(
labels: api.Labels,
logger: api.Logger,
- monotonic: boolean,
private readonly _disabled: boolean,
private readonly _valueType: api.ValueType,
private readonly _aggregator: Aggregator
) {
this._labels = labels;
this._logger = logger;
- this._monotonic = monotonic;
}
update(value: number): void {
@@ -72,18 +69,17 @@ export class BoundCounter extends BaseBoundInstrument
constructor(
labels: api.Labels,
disabled: boolean,
- monotonic: boolean,
valueType: api.ValueType,
logger: api.Logger,
aggregator: Aggregator
) {
- super(labels, logger, monotonic, disabled, valueType, aggregator);
+ super(labels, logger, disabled, valueType, aggregator);
}
add(value: number): void {
- if (this._monotonic && value < 0) {
+ if (value < 0) {
this._logger.error(
- `Monotonic counter cannot descend for ${Object.values(this._labels)}`
+ `Counter cannot descend for ${Object.values(this._labels)}`
);
return;
}
@@ -93,7 +89,29 @@ export class BoundCounter extends BaseBoundInstrument
}
/**
- * BoundValueRecorder is an implementation of the {@link BoundValueRecorder} interface.
+ * BoundUpDownCounter allows the SDK to observe/record a single metric event.
+ * The value of single instrument in the `UpDownCounter` associated with
+ * specified Labels.
+ */
+export class BoundUpDownCounter extends BaseBoundInstrument
+ implements api.BoundCounter {
+ constructor(
+ labels: api.Labels,
+ disabled: boolean,
+ valueType: api.ValueType,
+ logger: api.Logger,
+ aggregator: Aggregator
+ ) {
+ super(labels, logger, disabled, valueType, aggregator);
+ }
+
+ add(value: number): void {
+ this.update(value);
+ }
+}
+
+/**
+ * BoundMeasure is an implementation of the {@link BoundMeasure} interface.
*/
export class BoundValueRecorder extends BaseBoundInstrument
implements api.BoundValueRecorder {
@@ -102,13 +120,12 @@ export class BoundValueRecorder extends BaseBoundInstrument
constructor(
labels: api.Labels,
disabled: boolean,
- monotonic: boolean,
absolute: boolean,
valueType: api.ValueType,
logger: api.Logger,
aggregator: Aggregator
) {
- super(labels, logger, monotonic, disabled, valueType, aggregator);
+ super(labels, logger, disabled, valueType, aggregator);
this._absolute = absolute;
}
@@ -137,11 +154,10 @@ export class BoundObserver extends BaseBoundInstrument {
constructor(
labels: api.Labels,
disabled: boolean,
- monotonic: boolean,
valueType: api.ValueType,
logger: api.Logger,
aggregator: Aggregator
) {
- super(labels, logger, monotonic, disabled, valueType, aggregator);
+ super(labels, logger, disabled, valueType, aggregator);
}
}
diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts
index dd760cc5a2..a8678751df 100644
--- a/packages/opentelemetry-metrics/src/Meter.ts
+++ b/packages/opentelemetry-metrics/src/Meter.ts
@@ -18,6 +18,7 @@ import * as api from '@opentelemetry/api';
import { ConsoleLogger } from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { BaseBoundInstrument } from './BoundInstrument';
+import { UpDownCounterMetric } from './UpDownCounterMetric';
import {
Metric,
CounterMetric,
@@ -72,10 +73,9 @@ export class Meter implements api.Meter {
return api.NOOP_VALUE_RECORDER_METRIC;
}
const opt: MetricOptions = {
- absolute: true, // value recorders are defined as absolute by default
- monotonic: false, // not applicable to value recorder, set to false
logger: this._logger,
...DEFAULT_METRIC_OPTIONS,
+ absolute: true, // value recorders are defined as absolute by default
...options,
};
@@ -104,8 +104,6 @@ export class Meter implements api.Meter {
return api.NOOP_COUNTER_METRIC;
}
const opt: MetricOptions = {
- monotonic: true, // Counters are defined as monotonic by default
- absolute: false, // not applicable to counter, set to false
logger: this._logger,
...DEFAULT_METRIC_OPTIONS,
...options,
@@ -115,6 +113,41 @@ export class Meter implements api.Meter {
return counter;
}
+ /**
+ * Creates a new `UpDownCounter` metric. UpDownCounter is a synchronous
+ * instrument and very similar to Counter except that Add(increment)
+ * supports negative increments. It is generally useful for capturing changes
+ * in an amount of resources used, or any quantity that rises and falls
+ * during a request.
+ *
+ * @param name the name of the metric.
+ * @param [options] the metric options.
+ */
+ createUpDownCounter(
+ name: string,
+ options?: api.MetricOptions
+ ): api.UpDownCounter {
+ if (!this._isValidName(name)) {
+ this._logger.warn(
+ `Invalid metric name ${name}. Defaulting to noop metric implementation.`
+ );
+ return api.NOOP_COUNTER_METRIC;
+ }
+ const opt: MetricOptions = {
+ logger: this._logger,
+ ...DEFAULT_METRIC_OPTIONS,
+ ...options,
+ };
+ const upDownCounter = new UpDownCounterMetric(
+ name,
+ opt,
+ this._batcher,
+ this._resource
+ );
+ this._registerMetric(name, upDownCounter);
+ return upDownCounter;
+ }
+
/**
* Creates a new observer metric.
* @param name the name of the metric.
@@ -128,8 +161,6 @@ export class Meter implements api.Meter {
return api.NOOP_OBSERVER_METRIC;
}
const opt: MetricOptions = {
- monotonic: false, // Observers are defined as non-monotonic by default
- absolute: false, // not applicable to observer, set to false
logger: this._logger,
...DEFAULT_METRIC_OPTIONS,
...options,
@@ -188,7 +219,8 @@ export class Meter implements api.Meter {
*
* 2. The first character must be non-numeric, non-space, non-punctuation
*
- * 3. Subsequent characters must be belong to the alphanumeric characters, '_', '.', and '-'.
+ * 3. Subsequent characters must be belong to the alphanumeric characters,
+ * '_', '.', and '-'.
*
* Names are case insensitive
*
diff --git a/packages/opentelemetry-metrics/src/Metric.ts b/packages/opentelemetry-metrics/src/Metric.ts
index 09aa518028..194971ba5e 100644
--- a/packages/opentelemetry-metrics/src/Metric.ts
+++ b/packages/opentelemetry-metrics/src/Metric.ts
@@ -31,7 +31,6 @@ import { hashLabels } from './Utils';
/** This is a SDK implementation of {@link Metric} interface. */
export abstract class Metric
implements api.UnboundMetric {
- protected readonly _monotonic: boolean;
protected readonly _disabled: boolean;
protected readonly _valueType: api.ValueType;
protected readonly _logger: api.Logger;
@@ -44,7 +43,6 @@ export abstract class Metric
private readonly _kind: MetricKind,
readonly resource: Resource
) {
- this._monotonic = _options.monotonic;
this._disabled = _options.disabled;
this._valueType = _options.valueType;
this._logger = _options.logger;
@@ -98,7 +96,6 @@ export abstract class Metric
unit: this._options.unit,
metricKind: this._kind,
valueType: this._valueType,
- monotonic: this._monotonic,
};
}
@@ -119,7 +116,6 @@ export class CounterMetric extends Metric implements api.Counter {
return new BoundCounter(
labels,
this._disabled,
- this._monotonic,
this._valueType,
this._logger,
// @todo: consider to set to CounterSumAggregator always.
@@ -130,8 +126,8 @@ export class CounterMetric extends Metric implements api.Counter {
/**
* Adds the given value to the current value. Values cannot be negative.
* @param value the value to add.
- * @param [labels = {}] key-values pairs that are associated with a specific metric
- * that you want to record.
+ * @param [labels = {}] key-values pairs that are associated with a specific
+ * metric that you want to record.
*/
add(value: number, labels: api.Labels = {}) {
this.bind(labels).add(value);
@@ -156,7 +152,6 @@ export class ValueRecorderMetric extends Metric
return new BoundValueRecorder(
labels,
this._disabled,
- this._monotonic,
this._absolute,
this._valueType,
this._logger,
@@ -187,7 +182,6 @@ export class ObserverMetric extends Metric
return new BoundObserver(
labels,
this._disabled,
- this._monotonic,
this._valueType,
this._logger,
this._batcher.aggregatorFor(this._descriptor)
diff --git a/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts
new file mode 100644
index 0000000000..03a4b1c277
--- /dev/null
+++ b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts
@@ -0,0 +1,55 @@
+/*!
+ * Copyright 2019, 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 api from '@opentelemetry/api';
+import { Resource } from '@opentelemetry/resources';
+import { BoundUpDownCounter } from './BoundInstrument';
+import { MetricOptions } from './types';
+import { MetricKind } from './export/types';
+import { Batcher } from './export/Batcher';
+import { Metric } from './Metric';
+
+/** This is a SDK implementation of UpDownCounter Metric. */
+export class UpDownCounterMetric extends Metric
+ implements api.UpDownCounter {
+ constructor(
+ name: string,
+ options: MetricOptions,
+ private readonly _batcher: Batcher,
+ resource: Resource
+ ) {
+ super(name, options, MetricKind.UP_DOWN_COUNTER, resource);
+ }
+ protected _makeInstrument(labels: api.Labels): BoundUpDownCounter {
+ return new BoundUpDownCounter(
+ labels,
+ this._disabled,
+ this._valueType,
+ this._logger,
+ this._batcher.aggregatorFor(this._descriptor)
+ );
+ }
+
+ /**
+ * Adds the given value to the current value. Values cannot be negative.
+ * @param value the value to add.
+ * @param [labels = {}] key-values pairs that are associated with a specific
+ * metric that you want to record.
+ */
+ add(value: number, labels: api.Labels = {}) {
+ this.bind(labels).add(value);
+ }
+}
diff --git a/packages/opentelemetry-metrics/src/export/Batcher.ts b/packages/opentelemetry-metrics/src/export/Batcher.ts
index 8b3dfa5392..23f2d24fa2 100644
--- a/packages/opentelemetry-metrics/src/export/Batcher.ts
+++ b/packages/opentelemetry-metrics/src/export/Batcher.ts
@@ -55,6 +55,7 @@ export class UngroupedBatcher extends Batcher {
aggregatorFor(metricDescriptor: MetricDescriptor): Aggregator {
switch (metricDescriptor.metricKind) {
case MetricKind.COUNTER:
+ case MetricKind.UP_DOWN_COUNTER:
return new CounterSumAggregator();
case MetricKind.OBSERVER:
return new ObserverAggregator();
diff --git a/packages/opentelemetry-metrics/src/export/types.ts b/packages/opentelemetry-metrics/src/export/types.ts
index a07ca8224e..2dacf02a9f 100644
--- a/packages/opentelemetry-metrics/src/export/types.ts
+++ b/packages/opentelemetry-metrics/src/export/types.ts
@@ -82,7 +82,6 @@ export interface MetricDescriptor {
readonly unit: string;
readonly metricKind: MetricKind;
readonly valueType: ValueType;
- readonly monotonic: boolean;
}
/**
diff --git a/packages/opentelemetry-metrics/src/index.ts b/packages/opentelemetry-metrics/src/index.ts
index 6cb01ff9a8..bc2cce8475 100644
--- a/packages/opentelemetry-metrics/src/index.ts
+++ b/packages/opentelemetry-metrics/src/index.ts
@@ -22,3 +22,4 @@ export * from './MetricObservable';
export * from './export/aggregators';
export * from './export/ConsoleMetricExporter';
export * from './export/types';
+export * from './UpDownCounterMetric';
diff --git a/packages/opentelemetry-metrics/src/types.ts b/packages/opentelemetry-metrics/src/types.ts
index 6f0fea05e7..d3a89cacb7 100644
--- a/packages/opentelemetry-metrics/src/types.ts
+++ b/packages/opentelemetry-metrics/src/types.ts
@@ -37,10 +37,7 @@ export interface MetricOptions {
/** Indicates the metric is a verbose metric that is disabled by default. */
disabled: boolean;
- /** Monotonic metrics may only increase. */
- monotonic: boolean;
-
- /** (ValueRecorder only) Asserts that this metric will only accept non-negative values. */
+ /** (Measure only) Asserts that this metric will only accept non-negative values. */
absolute: boolean;
/** User provided logger. */
@@ -79,6 +76,7 @@ export const DEFAULT_CONFIG = {
/** The default metric creation options value. */
export const DEFAULT_METRIC_OPTIONS = {
disabled: false,
+ absolute: false,
description: '',
unit: '1',
valueType: ValueType.DOUBLE,
diff --git a/packages/opentelemetry-metrics/test/Meter.test.ts b/packages/opentelemetry-metrics/test/Meter.test.ts
index a71c82b41f..451ff27487 100644
--- a/packages/opentelemetry-metrics/test/Meter.test.ts
+++ b/packages/opentelemetry-metrics/test/Meter.test.ts
@@ -29,6 +29,7 @@ import {
Aggregator,
MetricObservable,
MetricDescriptor,
+ UpDownCounterMetric,
} from '../src';
import * as api from '@opentelemetry/api';
import { NoopLogger, hrTime, hrTimeToNanoseconds } from '@opentelemetry/core';
@@ -66,7 +67,6 @@ describe('Meter', () => {
description: 'desc',
unit: '1',
disabled: false,
- monotonic: false,
});
assert.ok(counter instanceof Metric);
});
@@ -97,7 +97,6 @@ describe('Meter', () => {
description: 'desc',
unit: '1',
disabled: false,
- monotonic: true,
});
counter.add(1);
meter.collect();
@@ -136,7 +135,7 @@ describe('Meter', () => {
assert.strictEqual(boundCounter.getLabels(), labels);
});
- it('should add positive values by default', () => {
+ it('should add positive values only', () => {
const counter = meter.createCounter('name') as CounterMetric;
const boundCounter = counter.bind(labels);
boundCounter.add(10);
@@ -160,17 +159,6 @@ describe('Meter', () => {
assert.strictEqual(record1.aggregator.toPoint().value, 0);
});
- it('should add negative value when monotonic is set to false', () => {
- const counter = meter.createCounter('name', {
- monotonic: false,
- }) as CounterMetric;
- const boundCounter = counter.bind(labels);
- boundCounter.add(-10);
- meter.collect();
- const [record1] = meter.getBatcher().checkPointSet();
- assert.strictEqual(record1.aggregator.toPoint().value, -10);
- });
-
it('should return same instrument on same label values', () => {
const counter = meter.createCounter('name') as CounterMetric;
const boundCounter = counter.bind(labels);
@@ -229,7 +217,201 @@ describe('Meter', () => {
assert.deepStrictEqual(record[0].descriptor, {
description: '',
metricKind: MetricKind.COUNTER,
- monotonic: true,
+ name: 'name1',
+ unit: '1',
+ valueType: ValueType.DOUBLE,
+ });
+ assert.strictEqual(record[0].aggregator.toPoint().value, 10);
+ });
+ });
+
+ describe('names', () => {
+ it('should create counter with valid names', () => {
+ const counter1 = meter.createCounter('name1');
+ const counter2 = meter.createCounter(
+ 'Name_with-all.valid_CharacterClasses'
+ );
+ assert.ok(counter1 instanceof CounterMetric);
+ assert.ok(counter2 instanceof CounterMetric);
+ });
+
+ it('should return no op metric if name is an empty string', () => {
+ const counter = meter.createCounter('');
+ assert.ok(counter instanceof api.NoopMetric);
+ });
+
+ it('should return no op metric if name does not start with a letter', () => {
+ const counter1 = meter.createCounter('1name');
+ const counter_ = meter.createCounter('_name');
+ assert.ok(counter1 instanceof api.NoopMetric);
+ assert.ok(counter_ instanceof api.NoopMetric);
+ });
+
+ it('should return no op metric if name is an empty string contain only letters, numbers, ".", "_", and "-"', () => {
+ const counter = meter.createCounter('name with invalid characters^&*(');
+ assert.ok(counter instanceof api.NoopMetric);
+ });
+ });
+ });
+
+ describe('#UpDownCounter', () => {
+ const performanceTimeOrigin = hrTime();
+
+ it('should create a UpDownCounter', () => {
+ const upDownCounter = meter.createUpDownCounter('name');
+ assert.ok(upDownCounter instanceof Metric);
+ });
+
+ it('should create a UpDownCounter with options', () => {
+ const upDownCounter = meter.createUpDownCounter('name', {
+ description: 'desc',
+ unit: '1',
+ disabled: false,
+ });
+ assert.ok(upDownCounter instanceof Metric);
+ });
+
+ it('should be able to call add() directly on UpDownCounter', () => {
+ const upDownCounter = meter.createUpDownCounter('name');
+ upDownCounter.add(10, labels);
+ meter.collect();
+ const [record1] = meter.getBatcher().checkPointSet();
+
+ assert.strictEqual(record1.aggregator.toPoint().value, 10);
+ const lastTimestamp = record1.aggregator.toPoint().timestamp;
+ assert.ok(
+ hrTimeToNanoseconds(lastTimestamp) >
+ hrTimeToNanoseconds(performanceTimeOrigin)
+ );
+ upDownCounter.add(10, labels);
+ assert.strictEqual(record1.aggregator.toPoint().value, 20);
+
+ assert.ok(
+ hrTimeToNanoseconds(record1.aggregator.toPoint().timestamp) >
+ hrTimeToNanoseconds(lastTimestamp)
+ );
+ });
+
+ it('should be able to call add with no labels', () => {
+ const upDownCounter = meter.createUpDownCounter('name', {
+ description: 'desc',
+ unit: '1',
+ disabled: false,
+ });
+ upDownCounter.add(1);
+ meter.collect();
+ const [record1] = meter.getBatcher().checkPointSet();
+ assert.strictEqual(record1.aggregator.toPoint().value, 1);
+ });
+
+ it('should pipe through resource', () => {
+ const upDownCounter = meter.createUpDownCounter(
+ 'name'
+ ) as UpDownCounterMetric;
+ assert.ok(upDownCounter.resource instanceof Resource);
+
+ upDownCounter.add(1, { foo: 'bar' });
+
+ const [record] = upDownCounter.getMetricRecord();
+ assert.ok(record.resource instanceof Resource);
+ });
+
+ describe('.bind()', () => {
+ it('should create a UpDownCounter instrument', () => {
+ const upDownCounter = meter.createUpDownCounter('name');
+ const boundCounter = upDownCounter.bind(labels);
+ boundCounter.add(10);
+ meter.collect();
+ const [record1] = meter.getBatcher().checkPointSet();
+
+ assert.strictEqual(record1.aggregator.toPoint().value, 10);
+ boundCounter.add(-200);
+ assert.strictEqual(record1.aggregator.toPoint().value, -190);
+ });
+
+ it('should return the aggregator', () => {
+ const upDownCounter = meter.createUpDownCounter(
+ 'name'
+ ) as UpDownCounterMetric;
+ const boundCounter = upDownCounter.bind(labels);
+ boundCounter.add(20);
+ assert.ok(boundCounter.getAggregator() instanceof CounterSumAggregator);
+ assert.strictEqual(boundCounter.getLabels(), labels);
+ });
+
+ it('should not add the instrument data when disabled', () => {
+ const upDownCounter = meter.createUpDownCounter('name', {
+ disabled: true,
+ });
+ const boundCounter = upDownCounter.bind(labels);
+ boundCounter.add(10);
+ meter.collect();
+ const [record1] = meter.getBatcher().checkPointSet();
+ assert.strictEqual(record1.aggregator.toPoint().value, 0);
+ });
+
+ it('should return same instrument on same label values', () => {
+ const upDownCounter = meter.createUpDownCounter('name');
+ const boundCounter = upDownCounter.bind(labels);
+ boundCounter.add(10);
+ const boundCounter1 = upDownCounter.bind(labels);
+ boundCounter1.add(10);
+ meter.collect();
+ const [record1] = meter.getBatcher().checkPointSet();
+
+ assert.strictEqual(record1.aggregator.toPoint().value, 20);
+ assert.strictEqual(boundCounter, boundCounter1);
+ });
+ });
+
+ describe('.unbind()', () => {
+ it('should remove a UpDownCounter instrument', () => {
+ const upDownCounter = meter.createUpDownCounter(
+ 'name'
+ ) as UpDownCounterMetric;
+ const boundCounter = upDownCounter.bind(labels);
+ assert.strictEqual(upDownCounter['_instruments'].size, 1);
+ upDownCounter.unbind(labels);
+ assert.strictEqual(upDownCounter['_instruments'].size, 0);
+ const boundCounter1 = upDownCounter.bind(labels);
+ assert.strictEqual(upDownCounter['_instruments'].size, 1);
+ assert.notStrictEqual(boundCounter, boundCounter1);
+ });
+
+ it('should not fail when removing non existing instrument', () => {
+ const upDownCounter = meter.createUpDownCounter('name');
+ upDownCounter.unbind({});
+ });
+
+ it('should clear all instruments', () => {
+ const upDownCounter = meter.createUpDownCounter(
+ 'name'
+ ) as CounterMetric;
+ upDownCounter.bind(labels);
+ assert.strictEqual(upDownCounter['_instruments'].size, 1);
+ upDownCounter.clear();
+ assert.strictEqual(upDownCounter['_instruments'].size, 0);
+ });
+ });
+
+ describe('.registerMetric()', () => {
+ it('skip already registered Metric', () => {
+ const counter1 = meter.createCounter('name1') as CounterMetric;
+ counter1.bind(labels).add(10);
+
+ // should skip below metric
+ const counter2 = meter.createCounter('name1', {
+ valueType: api.ValueType.INT,
+ }) as CounterMetric;
+ counter2.bind(labels).add(500);
+
+ meter.collect();
+ const record = meter.getBatcher().checkPointSet();
+
+ assert.strictEqual(record.length, 1);
+ assert.deepStrictEqual(record[0].descriptor, {
+ description: '',
+ metricKind: MetricKind.COUNTER,
name: 'name1',
unit: '1',
valueType: ValueType.DOUBLE,
@@ -557,7 +739,6 @@ describe('Meter', () => {
name: 'counter',
description: 'test',
metricKind: MetricKind.COUNTER,
- monotonic: true,
unit: '1',
valueType: ValueType.DOUBLE,
});
@@ -584,7 +765,6 @@ describe('Meter', () => {
name: 'counter',
description: 'test',
metricKind: MetricKind.COUNTER,
- monotonic: true,
unit: '1',
valueType: ValueType.INT,
});
@@ -630,5 +810,4 @@ function ensureMetric(metric: MetricRecord) {
assert.strictEqual(descriptor.unit, '1');
assert.strictEqual(descriptor.metricKind, MetricKind.OBSERVER);
assert.strictEqual(descriptor.valueType, ValueType.DOUBLE);
- assert.strictEqual(descriptor.monotonic, false);
}
diff --git a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts
index d47bc2981c..987f468212 100644
--- a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts
+++ b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts
@@ -57,7 +57,6 @@ describe('ConsoleMetricExporter', () => {
{
description: 'a test description',
metricKind: MetricKind.COUNTER,
- monotonic: true,
name: 'counter',
unit: '1',
valueType: ValueType.DOUBLE,