Skip to content

Commit

Permalink
feat: add the UpDownCounter instrument (#1120)
Browse files Browse the repository at this point in the history
  • Loading branch information
mayurkale22 authored Jun 12, 2020
1 parent 6ab7984 commit 469b759
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 65 deletions.
27 changes: 26 additions & 1 deletion packages/opentelemetry-api/src/metrics/Meter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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:
* <ol>
* <li> count the number of active requests. </li>
* <li> count memory in use by instrumenting new and delete. </li>
* <li> count queue size by instrumenting enqueue and dequeue. </li>
* <li> count semaphore up and down operations. </li>
* </ol>
*
* @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.
Expand Down
14 changes: 8 additions & 6 deletions packages/opentelemetry-api/src/metrics/Metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -125,6 +120,13 @@ export interface Counter extends UnboundMetric<BoundCounter> {
add(value: number, labels?: Labels): void;
}

export interface UpDownCounter extends UnboundMetric<BoundCounter> {
/**
* Adds the given value to the current value. Values can be negative.
*/
add(value: number, labels?: Labels): void;
}

export interface ValueRecorder extends UnboundMetric<BoundValueRecorder> {
/**
* Records the given value to this value recorder.
Expand Down
10 changes: 10 additions & 0 deletions packages/opentelemetry-api/src/metrics/NoopMeter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Counter,
ValueRecorder,
Observer,
UpDownCounter,
} from './Metric';
import { BoundValueRecorder, BoundCounter } from './BoundInstrument';
import { CorrelationContext } from '../correlation_context/CorrelationContext';
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 3 additions & 4 deletions packages/opentelemetry-exporter-prometheus/src/prometheus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
40 changes: 28 additions & 12 deletions packages/opentelemetry-metrics/src/BoundInstrument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}
}
46 changes: 39 additions & 7 deletions packages/opentelemetry-metrics/src/Meter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand All @@ -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,
Expand Down Expand Up @@ -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
*
Expand Down
10 changes: 2 additions & 8 deletions packages/opentelemetry-metrics/src/Metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { hashLabels } from './Utils';
/** This is a SDK implementation of {@link Metric} interface. */
export abstract class Metric<T extends BaseBoundInstrument>
implements api.UnboundMetric<T> {
protected readonly _monotonic: boolean;
protected readonly _disabled: boolean;
protected readonly _valueType: api.ValueType;
protected readonly _logger: api.Logger;
Expand All @@ -44,7 +43,6 @@ export abstract class Metric<T extends BaseBoundInstrument>
private readonly _kind: MetricKind,
readonly resource: Resource
) {
this._monotonic = _options.monotonic;
this._disabled = _options.disabled;
this._valueType = _options.valueType;
this._logger = _options.logger;
Expand Down Expand Up @@ -98,7 +96,6 @@ export abstract class Metric<T extends BaseBoundInstrument>
unit: this._options.unit,
metricKind: this._kind,
valueType: this._valueType,
monotonic: this._monotonic,
};
}

Expand All @@ -119,7 +116,6 @@ export class CounterMetric extends Metric<BoundCounter> implements api.Counter {
return new BoundCounter(
labels,
this._disabled,
this._monotonic,
this._valueType,
this._logger,
// @todo: consider to set to CounterSumAggregator always.
Expand All @@ -130,8 +126,8 @@ export class CounterMetric extends Metric<BoundCounter> 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);
Expand All @@ -156,7 +152,6 @@ export class ValueRecorderMetric extends Metric<BoundValueRecorder>
return new BoundValueRecorder(
labels,
this._disabled,
this._monotonic,
this._absolute,
this._valueType,
this._logger,
Expand Down Expand Up @@ -187,7 +182,6 @@ export class ObserverMetric extends Metric<BoundObserver>
return new BoundObserver(
labels,
this._disabled,
this._monotonic,
this._valueType,
this._logger,
this._batcher.aggregatorFor(this._descriptor)
Expand Down
Loading

0 comments on commit 469b759

Please sign in to comment.