Skip to content

Commit

Permalink
feat(metrics): adds NoopMeter implementation (open-telemetry#278)
Browse files Browse the repository at this point in the history
* feat(metrics): adds NoopMeter implementation

Resolves open-telemetry/opentelemetry-js#264

* yarn fix

* rename test file

* fix the build attempt 1

* respond to comments

* fix the build part 2

* yarn fix
  • Loading branch information
bg451 authored Sep 19, 2019
1 parent b58965c commit a9df567
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/opentelemetry-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export * from './trace/sampler/ProbabilitySampler';
export * from './trace/spancontext-utils';
export * from './trace/TracerDelegate';
export * from './trace/TraceState';
export * from './metrics/NoopMeter';
139 changes: 139 additions & 0 deletions packages/opentelemetry-core/src/metrics/NoopMeter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*!
* 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 {
CounterHandle,
DistributedContext,
GaugeHandle,
Meter,
Metric,
MetricOptions,
MeasureHandle,
SpanContext,
} from '@opentelemetry/types';

/**
* NoopMeter is a noop implementation of the {@link Meter} interface. It reuses constant
* NoopMetrics for all of its methods.
*/
export class NoopMeter implements Meter {
constructor() {}

/**
* Returns constant noop measure.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createMeasure(name: string, options?: MetricOptions): Metric<MeasureHandle> {
return NOOP_MEASURE_METRIC;
}

/**
* Returns a constant noop counter.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createCounter(name: string, options?: MetricOptions): Metric<CounterHandle> {
return NOOP_COUNTER_METRIC;
}

/**
* Returns a constant gauge metric.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createGauge(name: string, options?: MetricOptions): Metric<GaugeHandle> {
return NOOP_GAUGE_METRIC;
}
}

export class NoopMetric<T> implements Metric<T> {
private readonly _handle: T;

constructor(handle: T) {
this._handle = handle;
}
/**
* Returns a Handle associated with specified label values.
* It is recommended to keep a reference to the Handle instead of always
* calling this method for every operations.
* @param labelValues the list of label values.
*/
getHandle(labelValues: string[]): T {
return this._handle;
}

/**
* Returns a Handle for a metric with all labels not set.
*/
getDefaultHandle(): T {
return this._handle;
}

/**
* Removes the Handle from the metric, if it is present.
* @param labelValues the list of label values.
*/
removeHandle(labelValues: string[]): void {
return;
}

/**
* Clears all timeseries from the Metric.
*/
clear(): void {
return;
}

setCallback(fn: () => void): void {
return;
}
}

export class NoopCounterHandle implements CounterHandle {
add(value: number): void {
return;
}
}

export class NoopGaugeHandle implements GaugeHandle {
set(value: number): void {
return;
}
}

export class NoopMeasureHandle implements MeasureHandle {
record(
value: number,
distContext?: DistributedContext,
spanContext?: SpanContext
): void {
return;
}
}

export const NOOP_GAUGE_HANDLE = new NoopGaugeHandle();
export const NOOP_GAUGE_METRIC = new NoopMetric<GaugeHandle>(NOOP_GAUGE_HANDLE);

export const NOOP_COUNTER_HANDLE = new NoopCounterHandle();
export const NOOP_COUNTER_METRIC = new NoopMetric<CounterHandle>(
NOOP_COUNTER_HANDLE
);

export const NOOP_MEASURE_HANDLE = new NoopMeasureHandle();
export const NOOP_MEASURE_METRIC = new NoopMetric<MeasureHandle>(
NOOP_MEASURE_HANDLE
);
90 changes: 90 additions & 0 deletions packages/opentelemetry-core/test/metrics/NoopMeter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*!
* 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 assert from 'assert';
import {
NoopMeter,
NOOP_GAUGE_HANDLE,
NOOP_GAUGE_METRIC,
NOOP_COUNTER_HANDLE,
NOOP_COUNTER_METRIC,
NOOP_MEASURE_HANDLE,
NOOP_MEASURE_METRIC,
} from '../../src/metrics/NoopMeter';

describe('NoopMeter', () => {
it('should not crash', () => {
const meter = new NoopMeter();
const counter = meter.createCounter('some-name');
// ensure NoopMetric does not crash.
counter.setCallback(() => {
assert.fail('callback occurred');
});
counter.getHandle(['val1', 'val2']).add(1);
counter.getDefaultHandle().add(1);
counter.removeHandle(['val1', 'val2']);

// ensure the correct noop const is returned
assert.strictEqual(counter, NOOP_COUNTER_METRIC);
assert.strictEqual(
counter.getHandle(['val1', 'val2']),
NOOP_COUNTER_HANDLE
);
assert.strictEqual(counter.getDefaultHandle(), NOOP_COUNTER_HANDLE);
counter.clear();

const measure = meter.createMeasure('some-name');
measure.getDefaultHandle().record(1);
measure.getDefaultHandle().record(1, { key: { value: 'value' } });
measure.getDefaultHandle().record(
1,
{ key: { value: 'value' } },
{
traceId: 'a3cda95b652f4a1592b449d5929fda1b',
spanId: '5e0c63257de34c92',
}
);

// ensure the correct noop const is returned
assert.strictEqual(measure, NOOP_MEASURE_METRIC);
assert.strictEqual(measure.getDefaultHandle(), NOOP_MEASURE_HANDLE);
assert.strictEqual(
measure.getHandle(['val1', 'val2']),
NOOP_MEASURE_HANDLE
);

const gauge = meter.createGauge('some-name');
gauge.getDefaultHandle().set(1);

// ensure the correct noop const is returned
assert.strictEqual(gauge, NOOP_GAUGE_METRIC);
assert.strictEqual(gauge.getDefaultHandle(), NOOP_GAUGE_HANDLE);
assert.strictEqual(gauge.getHandle(['val1', 'val2']), NOOP_GAUGE_HANDLE);

const options = {
component: 'tests',
description: 'the testing package',
labelKeys: ['key1', 'key2'],
};

const measureWithOptions = meter.createMeasure('some-name', options);
assert.strictEqual(measureWithOptions, NOOP_MEASURE_METRIC);
const counterWithOptions = meter.createCounter('some-name', options);
assert.strictEqual(counterWithOptions, NOOP_COUNTER_METRIC);
const gaugeWithOptions = meter.createGauge('some-name', options);
assert.strictEqual(gaugeWithOptions, NOOP_GAUGE_METRIC);
});
});

0 comments on commit a9df567

Please sign in to comment.