Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(api): added synchronous gauge #4528

Merged
merged 4 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.

### :rocket: (Enhancement)

* feat(metrics): added synchronous gauge [#4528](https://github.com/open-telemetry/opentelemetry-js/pull/4528) @clintonb
* feat(api): allow adding span links after span creation [#4536](https://github.com/open-telemetry/opentelemetry-js/pull/4536) @seemk
* This change is non-breaking for end-users, but breaking for Trace SDK implmentations in accordance with the [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/a03382ada8afa9415266a84dafac0510ec8c160f/specification/upgrading.md?plain=1#L97-L122) as new features need to be implemented.
* feat: support node 22 [#4666](https://github.com/open-telemetry/opentelemetry-js/pull/4666) @dyladan
Expand Down
1 change: 1 addition & 0 deletions api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export { MeterProvider } from './metrics/MeterProvider';
export {
ValueType,
Counter,
Gauge,
Histogram,
MetricOptions,
Observable,
Expand Down
11 changes: 11 additions & 0 deletions api/src/metrics/Meter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import {
BatchObservableCallback,
Counter,
Gauge,
Histogram,
MetricAttributes,
MetricOptions,
Expand Down Expand Up @@ -45,6 +46,16 @@ export interface MeterOptions {
* for the exported metric are deferred.
*/
export interface Meter {
/**
* Creates and returns a new `Gauge`.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createGauge<AttributesTypes extends MetricAttributes = MetricAttributes>(
name: string,
options?: MetricOptions
): Gauge<AttributesTypes>;

/**
* Creates and returns a new `Histogram`.
* @param name the name of the metric.
Expand Down
9 changes: 9 additions & 0 deletions api/src/metrics/Metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ export interface UpDownCounter<
add(value: number, attributes?: AttributesTypes, context?: Context): void;
}

export interface Gauge<
AttributesTypes extends MetricAttributes = MetricAttributes,
> {
/**
* Records a measurement.
*/
record(value: number, attributes?: AttributesTypes, context?: Context): void;
}

export interface Histogram<
AttributesTypes extends MetricAttributes = MetricAttributes,
> {
Expand Down
17 changes: 15 additions & 2 deletions api/src/metrics/NoopMeter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ import { Meter } from './Meter';
import {
BatchObservableCallback,
Counter,
Gauge,
Histogram,
MetricAttributes,
MetricOptions,
Observable,
ObservableCallback,
ObservableCounter,
ObservableGauge,
ObservableUpDownCounter,
UpDownCounter,
MetricAttributes,
Observable,
} from './Metric';

/**
Expand All @@ -36,6 +37,13 @@ import {
export class NoopMeter implements Meter {
constructor() {}

/**
* @see {@link Meter.createGauge}
*/
createGauge(_name: string, _options?: MetricOptions): Gauge {
return NOOP_GAUGE_METRIC;
}

/**
* @see {@link Meter.createHistogram}
*/
Expand Down Expand Up @@ -114,6 +122,10 @@ export class NoopUpDownCounterMetric
add(_value: number, _attributes: MetricAttributes): void {}
}

export class NoopGaugeMetric extends NoopMetric implements Gauge {
record(_value: number, _attributes: MetricAttributes): void {}
}

export class NoopHistogramMetric extends NoopMetric implements Histogram {
record(_value: number, _attributes: MetricAttributes): void {}
}
Expand All @@ -140,6 +152,7 @@ export const NOOP_METER = new NoopMeter();

// Synchronous instruments
export const NOOP_COUNTER_METRIC = new NoopCounterMetric();
export const NOOP_GAUGE_METRIC = new NoopGaugeMetric();
export const NOOP_HISTOGRAM_METRIC = new NoopHistogramMetric();
export const NOOP_UP_DOWN_COUNTER_METRIC = new NoopUpDownCounterMetric();

Expand Down
12 changes: 12 additions & 0 deletions api/test/common/noop-implementations/noop-meter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
NOOP_OBSERVABLE_UP_DOWN_COUNTER_METRIC,
NOOP_UP_DOWN_COUNTER_METRIC,
createNoopMeter,
NOOP_GAUGE_METRIC,
} from '../../../src/metrics/NoopMeter';
import { NoopMeterProvider } from '../../../src/metrics/NoopMeterProvider';

Expand Down Expand Up @@ -116,6 +117,17 @@ describe('NoopMeter', () => {
);
});

it('gauge should not crash', () => {
const meter = new NoopMeterProvider().getMeter('test-noop');
const observableGauge = meter.createGauge('some-name');

// ensure the correct noop const is returned
assert.strictEqual(observableGauge, NOOP_GAUGE_METRIC);

const gaugeWithOptions = meter.createGauge('some-name', options);
assert.strictEqual(gaugeWithOptions, NOOP_GAUGE_METRIC);
});

it('observable up down counter should not crash', () => {
const meter = new NoopMeterProvider().getMeter('test-noop');
const observableUpDownCounter =
Expand Down
7 changes: 1 addition & 6 deletions packages/sdk-metrics/src/Meter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
ObservableUpDownCounter,
BatchObservableCallback,
Observable,
Attributes,
} from '@opentelemetry/api';
import {
createInstrumentDescriptor,
Expand All @@ -51,12 +50,8 @@ export class Meter implements IMeter {

/**
* Create a {@link Gauge} instrument.
* @experimental
*/
createGauge<AttributesTypes extends Attributes = Attributes>(
name: string,
options?: MetricOptions
): Gauge<AttributesTypes> {
createGauge(name: string, options?: MetricOptions): Gauge {
const descriptor = createInstrumentDescriptor(
name,
InstrumentType.GAUGE,
Expand Down
2 changes: 0 additions & 2 deletions packages/sdk-metrics/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ export type ShutdownOptions = CommonReaderOptions;
export type ForceFlushOptions = CommonReaderOptions;

/**
* @experimental
*
* This is intentionally not using the API's type as it's only available from @opentelemetry/api 1.9.0 and up.
* In SDK 2.0 we'll be able to bump the minimum API version and remove this workaround.
*/
Expand Down
47 changes: 41 additions & 6 deletions packages/sdk-metrics/test/Instruments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ import * as sinon from 'sinon';
import { InstrumentationScope } from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import {
InstrumentType,
MeterProvider,
MetricReader,
DataPoint,
DataPointType,
Histogram,
InstrumentType,
MeterProvider,
MetricDescriptor,
MetricReader,
} from '../src';
import {
TestDeltaMetricReader,
TestMetricReader,
} from './export/TestMetricReader';
import {
assertMetricData,
assertDataPoint,
commonValues,
assertMetricData,
commonAttributes,
defaultResource,
commonValues,
defaultInstrumentationScope,
defaultResource,
} from './util';
import { ObservableResult, ValueType } from '@opentelemetry/api';

Expand Down Expand Up @@ -764,6 +764,41 @@ describe('Instruments', () => {
});
});
});

describe('Gauge', () => {
it('should record common values and attributes without exceptions', async () => {
const { meter } = setup();
const gauge = meter.createGauge('test');

for (const values of commonValues) {
for (const attributes of commonAttributes) {
gauge.record(values, attributes);
}
}
});

it('should record values', async () => {
const { meter, cumulativeReader } = setup();
const gauge = meter.createGauge('test');

gauge.record(1, { foo: 'bar' });
gauge.record(-1);

await validateExport(cumulativeReader, {
dataPointType: DataPointType.GAUGE,
dataPoints: [
{
attributes: { foo: 'bar' },
value: 1,
},
{
attributes: {},
value: -1,
},
],
});
});
});
});

function setup() {
Expand Down