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: implement named meter #691

Closed
wants to merge 9 commits into from
4 changes: 2 additions & 2 deletions examples/prometheus/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use strict";

const { Meter } = require("@opentelemetry/metrics");
const { MeterRegistry } = require("@opentelemetry/metrics");
const { PrometheusExporter } = require("@opentelemetry/exporter-prometheus");

const meter = new Meter();
const meter = new MeterRegistry().getMeter('example-prometheus');

const exporter = new PrometheusExporter(
{
Expand Down
12 changes: 6 additions & 6 deletions getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,19 +238,19 @@ Create a file named `monitoring.js` and add the following code:
```javascript
'use strict';

const { Meter } = require("@opentelemetry/metrics");
const { MeterRegistry } = require("@opentelemetry/metrics");

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');
```

Now, you can require this file from your application code and use the `Meter` to create and manage metrics. The simplest of these metrics is a counter. Let's create and export from our `monitoring.js` file a middleware function that express can use to count all requests by route. Modify the `monitoring.js` file so that it looks like this:

```javascript
'use strict';

const { Meter } = require("@opentelemetry/metrics");
const { MeterRegistry } = require("@opentelemetry/metrics");

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

const requestCount = meter.createCounter("requests", {
monotonic: true,
Expand Down Expand Up @@ -301,10 +301,10 @@ Next, modify your `monitoring.js` file to look like this:
```javascript
"use strict";

const { Meter } = require("@opentelemetry/metrics");
const { MeterRegistry } = require("@opentelemetry/metrics");
const { PrometheusExporter } = require("@opentelemetry/exporter-prometheus");

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

meter.addExporter(
new PrometheusExporter(
Expand Down
4 changes: 2 additions & 2 deletions getting-started/monitored-example/monitoring.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use strict";

const { Meter } = require("@opentelemetry/metrics");
const { MeterRegistry } = require("@opentelemetry/metrics");
const { PrometheusExporter } = require("@opentelemetry/exporter-prometheus");

const meter = new Meter();
const meter = new MeterRegistry().getMeter('example-monitored');

meter.addExporter(
new PrometheusExporter(
Expand Down
12 changes: 6 additions & 6 deletions getting-started/ts-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,18 @@ In order to create and monitor metrics, we will need a `Meter`. In OpenTelemetry
Create a file named `monitoring.ts` and add the following code:

```typescript
import { Meter } from "@opentelemetry/metrics";
import { MeterRegistry } from "@opentelemetry/metrics";

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');
```

Now, you can require this file from your application code and use the `Meter` to create and manage metrics. The simplest of these metrics is a counter. Let's create and export from our `monitoring.ts` file a middleware function that express can use to count all requests by route. Modify the `monitoring.ts` file so that it looks like this:

```typescript
import { Meter } from "@opentelemetry/metrics";
import { MeterRegistry } from "@opentelemetry/metrics";
import { Metric, BoundCounter } from "@opentelemetry/types";

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

const requestCount: Metric<BoundCounter> = meter.createCounter("requests", {
monotonic: true,
Expand Down Expand Up @@ -296,11 +296,11 @@ $ npm install @opentelemetry/exporter-prometheus
Next, modify your `monitoring.ts` file to look like this:

```typescript
import { Meter } from "@opentelemetry/metrics";
import { MeterRegistry } from "@opentelemetry/metrics";
import { Metric, BoundCounter } from "@opentelemetry/types";
import { PrometheusExporter } from "@opentelemetry/exporter-prometheus";

const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

meter.addExporter(
new PrometheusExporter({ startServer: true }, () => {
Expand Down
4 changes: 2 additions & 2 deletions getting-started/ts-example/monitoring.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Meter } from "@opentelemetry/metrics";
import { MeterRegistry } from "@opentelemetry/metrics";
import { Metric, BoundCounter } from "@opentelemetry/types";
import { PrometheusExporter } from "@opentelemetry/exporter-prometheus";

const meter = new Meter();
const meter = new MeterRegistry().getMeter('example-ts');

meter.addExporter(
new PrometheusExporter({ startServer: true }, () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/metrics/NoopMeter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ export class NoopBoundMeasure implements BoundMeasure {
}
}

export const noopMeter = new NoopMeter();

export const NOOP_BOUND_GAUGE = new NoopBoundGauge();
export const NOOP_GAUGE_METRIC = new NoopGaugeMetric(NOOP_BOUND_GAUGE);

Expand Down
28 changes: 28 additions & 0 deletions packages/opentelemetry-core/src/metrics/NoopMeterRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*!
* 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 types from '@opentelemetry/types';
import { noopMeter } from './NoopMeter';

/**
* An implementation of the {@link MeterRegistry} which returns an impotent Meter
* for all calls to `getMeter`
*/
export class NoopMeterRegistry implements types.MeterRegistry {
getMeter(_name?: string, _version?: string): types.Meter {
return noopMeter;
}
}
4 changes: 2 additions & 2 deletions packages/opentelemetry-core/test/metrics/NoopMeter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import * as assert from 'assert';
import {
NoopMeter,
NOOP_BOUND_GAUGE,
NOOP_GAUGE_METRIC,
NOOP_BOUND_COUNTER,
Expand All @@ -25,10 +24,11 @@ import {
NOOP_MEASURE_METRIC,
} from '../../src/metrics/NoopMeter';
import { Labels } from '@opentelemetry/types';
import { NoopMeterRegistry } from '../../src/metrics/NoopMeterRegistry';

describe('NoopMeter', () => {
it('should not crash', () => {
const meter = new NoopMeter();
const meter = new NoopMeterRegistry().getMeter('test-noop');
const counter = meter.createCounter('some-name');
const labels = {} as Labels;
const labelSet = meter.labels(labels);
Expand Down
4 changes: 2 additions & 2 deletions packages/opentelemetry-exporter-prometheus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ Create & register the exporter on your application.

```js
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
const { Meter } = require('@opentelemetry/metrics');
const { MeterRegistry } = require('@opentelemetry/metrics');

// Add your port and startServer to the Prometheus options
const options = {port: 9464, startServer: true};
const exporter = new PrometheusExporter(options);

// Register the exporter
const meter = new Meter();
const meter = new MeterRegistry().getMeter('exporter-prometheus');
meter.addExporter(exporter);

// Now, start recording data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
* limitations under the License.
*/

import { CounterMetric, GaugeMetric, Meter } from '@opentelemetry/metrics';
import {
CounterMetric,
GaugeMetric,
Meter,
MeterRegistry,
} from '@opentelemetry/metrics';
import * as assert from 'assert';
import * as http from 'http';
import { PrometheusExporter } from '../src';
Expand Down Expand Up @@ -166,7 +171,7 @@ describe('PrometheusExporter', () => {

beforeEach(done => {
exporter = new PrometheusExporter();
meter = new Meter();
meter = new MeterRegistry().getMeter('test-prometheus');
exporter.startServer(done);
});

Expand Down Expand Up @@ -382,7 +387,7 @@ describe('PrometheusExporter', () => {
let exporter: PrometheusExporter | undefined;

beforeEach(() => {
meter = new Meter();
meter = new MeterRegistry().getMeter('test-prometheus');
gauge = meter.createGauge('gauge') as GaugeMetric;
gauge.bind(meter.labels({ key1: 'labelValue1' })).set(10);
});
Expand Down
8 changes: 4 additions & 4 deletions packages/opentelemetry-metrics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ npm install --save @opentelemetry/metrics
Choose this kind of metric when the value is a quantity, the sum is of primary interest, and the event count and value distribution are not of primary interest. Counters are defined as `Monotonic = true` by default, meaning that positive values are expected.

```js
const { Meter } = require('@opentelemetry/metrics');
const { MeterRegistry } = require('@opentelemetry/metrics');

// Initialize the Meter to capture measurements in various ways.
const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

const counter = meter.createCounter('metric_name', {
labelKeys: ["pid"],
Expand All @@ -40,10 +40,10 @@ boundCounter.add(10);
Gauge metrics express a pre-calculated value. Generally, this kind of metric should be used when the metric cannot be expressed as a sum or because the measurement interval is arbitrary. Use this kind of metric when the measurement is not a quantity, and the sum and event count are not of interest. Gauges are defined as `Monotonic = false` by default, meaning that new values are permitted to make positive or negative changes to the gauge. There is no restriction on the sign of the input for gauges.

```js
const { Meter } = require('@opentelemetry/metrics');
const { MeterRegistry } = require('@opentelemetry/metrics');

// Initialize the Meter to capture measurements in various ways.
const meter = new Meter();
const meter = new MeterRegistry().getMeter('your-meter-name');

const gauge = meter.createGauge('metric_name', {
labelKeys: ["pid"],
Expand Down
42 changes: 42 additions & 0 deletions packages/opentelemetry-metrics/src/MeterRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*!
* 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 { ConsoleLogger } from '@opentelemetry/core';
import * as types from '@opentelemetry/types';
import { Logger } from '@opentelemetry/types';
import { Meter } from '.';
import { DEFAULT_CONFIG, MeterConfig } from './types';

/**
* This class represents a basic meter registry which platform libraries can extend
*/
export class MeterRegistry implements types.MeterRegistry {
private readonly _meters: Map<string, Meter> = new Map();
readonly logger: Logger;

constructor(private _config: MeterConfig = DEFAULT_CONFIG) {
this.logger = _config.logger || new ConsoleLogger(_config.logLevel);
}

getMeter(name: string, version = '*', config?: MeterConfig): Meter {
const key = `${name}@${version}`;
if (!this._meters.has(key)) {
this._meters.set(key, new Meter(config || this._config));
}

return this._meters.get(key)!;
}
}
1 change: 1 addition & 0 deletions packages/opentelemetry-metrics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
export * from './BoundInstrument';
export * from './Meter';
export * from './Metric';
export * from './MeterRegistry';
export * from './export/ConsoleMetricExporter';
export * from './export/types';
5 changes: 3 additions & 2 deletions packages/opentelemetry-metrics/test/Meter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
hrTimeToMilliseconds,
} from '@opentelemetry/core';
import { NoopExporter } from './mocks/Exporter';
import { MeterRegistry } from '../src/MeterRegistry';

const performanceTimeOrigin = hrTime();

Expand All @@ -43,9 +44,9 @@ describe('Meter', () => {
const hrTime: types.HrTime = [22, 400000000];

beforeEach(() => {
meter = new Meter({
meter = new MeterRegistry({
logger: new NoopLogger(),
});
}).getMeter('test-meter');
labelSet = meter.labels(labels);
});

Expand Down
68 changes: 68 additions & 0 deletions packages/opentelemetry-metrics/test/MeterRegistry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*!
* 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 { NoopLogger } from '@opentelemetry/core';
import * as assert from 'assert';
import { MeterRegistry, Meter } from '../src';

describe('MeterRegistry', () => {
describe('constructor', () => {
it('should construct an instance without any options', () => {
const registry = new MeterRegistry();
assert.ok(registry instanceof MeterRegistry);
});

it('should construct an instance with logger', () => {
const registry = new MeterRegistry({
logger: new NoopLogger(),
});
assert.ok(registry instanceof MeterRegistry);
});
});

describe('getMeter', () => {
it('should return an instance of Meter', () => {
const meter = new MeterRegistry().getMeter('test-meter-registry');
assert.ok(meter instanceof Meter);
});

it('should return the meter with default version without version option', () => {
const registry = new MeterRegistry();
const meter1 = registry.getMeter('test');
const meter2 = registry.getMeter('test', '*');
assert.deepEqual(meter1, meter2);
});

it('should return the same Meter instance with same name & version', () => {
const registry = new MeterRegistry();
const meter1 = registry.getMeter('meter1', 'ver1');
const meter2 = registry.getMeter('meter1', 'ver1');
assert.deepEqual(meter1, meter2);
});

it('should return different Meter instance with different name or version', () => {
const registry = new MeterRegistry();

const meter1 = registry.getMeter('meter1', 'ver1');
const meter2 = registry.getMeter('meter1');
assert.notEqual(meter1, meter2);

const meter3 = registry.getMeter('meter2', 'ver2');
const meter4 = registry.getMeter('meter3', 'ver2');
assert.notEqual(meter3, meter4);
});
});
});
Loading