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

O11Y-2256 : Resource can be passed into MeterProvider #90

Merged
merged 7 commits into from
Dec 3, 2022
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: 0 additions & 1 deletion lib/src/api/metrics/noop/noop_meter_provider.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:opentelemetry/api.dart';
import 'package:opentelemetry/src/api/metrics/noop/noop_meter.dart';
import 'package:opentelemetry/src/experimental_api.dart';

/// A noop registry for creating named [Meter]s.
Expand Down
6 changes: 6 additions & 0 deletions lib/src/experimental_api.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@experimental
library experimental_api;

import 'package:meta/meta.dart';

export 'api/metrics/counter.dart' show Counter;
export 'api/metrics/meter_provider.dart' show MeterProvider;
export 'api/metrics/meter.dart' show Meter;
export 'api/metrics/noop/noop_meter.dart' show NoopMeter;
6 changes: 6 additions & 0 deletions lib/src/experimental_sdk.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@experimental
library experimental_sdk;

import 'package:meta/meta.dart';

export 'sdk/metrics/counter.dart' show Counter;
export 'sdk/metrics/meter_provider.dart' show MeterProvider;
export 'sdk/metrics/meter.dart' show Meter;
export 'sdk/resource/resource.dart' show Resource;
27 changes: 27 additions & 0 deletions lib/src/sdk/common/instrumentation_scope.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:opentelemetry/api.dart' as api;

class InstrumentationScope {
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved
final String _name;
final String _version;
final String _schemaUrl;
final List<api.Attribute> _attributes;

InstrumentationScope(
this._name, this._version, this._schemaUrl, this._attributes);

String get name {
return _name;
}

String get version {
return _version;
}

String get schemaUrl {
return _schemaUrl;
}

List<api.Attribute> get attributes {
return _attributes;
}
}
7 changes: 7 additions & 0 deletions lib/src/sdk/metrics/meter.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import 'package:opentelemetry/src/experimental_sdk.dart' as sdk;
import 'package:opentelemetry/src/experimental_api.dart' as api;

import 'state/meter_shared_state.dart';

class Meter implements api.Meter {
// ignore: unused_field
final MeterSharedState _state;

Meter(this._state);

@override
api.Counter<T> createCounter<T extends num>(String name,
{String description, String unit}) {
Expand Down
27 changes: 19 additions & 8 deletions lib/src/sdk/metrics/meter_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,39 @@ import 'package:opentelemetry/api.dart' as api;
import 'package:opentelemetry/src/experimental_api.dart' as api;
import 'package:opentelemetry/src/experimental_sdk.dart' as sdk;
import 'package:logging/logging.dart';
import 'package:opentelemetry/src/api/metrics/meter_key.dart';
import 'package:opentelemetry/src/sdk/common/instrumentation_scope.dart';
import 'package:opentelemetry/src/sdk/metrics/state/meter_provider_shared_state.dart';

const invalidMeterNameMessage = 'Invalid Meter Name';

class MeterProvider implements api.MeterProvider {
final _meters = <MeterKey, api.Meter>{};
final _logger = Logger('opentelemetry.sdk.metrics.meterprovider');
final _shutdown = false;
final MeterProviderSharedState _sharedState;

sdk.Resource get resource => _sharedState.resource;
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved

MeterProvider({sdk.Resource resource})
: _sharedState = MeterProviderSharedState(resource);

@override
sdk.Meter get(String name,
api.Meter get(String name,
{String version = '',
String schemaUrl = '',
List<api.Attribute> attributes = const []}) {
if (name == null || name == '') {
name = '';
_logger.warning(invalidMeterNameMessage, '', StackTrace.current);
}
version ??= '';
schemaUrl ??= '';
attributes ??= const [];
final key = MeterKey(name, version, schemaUrl, attributes);

return _meters.putIfAbsent(key, () => sdk.Meter());
if (_shutdown) {
_logger.warning('A shutdown MeterProvider cannot provide a Meter', '',
StackTrace.current);
return api.NoopMeter();
}
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved

return _sharedState
.getMeterSharedState(InstrumentationScope(name, version, schemaUrl, attributes))
.meter;
}
}
27 changes: 27 additions & 0 deletions lib/src/sdk/metrics/state/meter_provider_shared_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:opentelemetry/sdk.dart';
import 'package:opentelemetry/src/sdk/common/instrumentation_scope.dart';
import 'package:opentelemetry/src/sdk/metrics/state/meter_shared_state.dart';
import 'package:quiver/core.dart';

int instrumentationScopeId(InstrumentationScope instrumentationScope) {
return hash3(instrumentationScope.name, instrumentationScope.version,
instrumentationScope.schemaUrl);
}

class MeterProviderSharedState {
Resource resource;
final Map<int, MeterSharedState> _meterSharedStates = {};

MeterProviderSharedState(this.resource);

MeterSharedState getMeterSharedState(
InstrumentationScope instrumentationScope) {
final id = instrumentationScopeId(instrumentationScope);
var meterSharedState = _meterSharedStates[id];
if (meterSharedState == null) {
meterSharedState = MeterSharedState(this, instrumentationScope);
_meterSharedStates[id] = meterSharedState;
}
return meterSharedState;
}
}
17 changes: 17 additions & 0 deletions lib/src/sdk/metrics/state/meter_shared_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:opentelemetry/src/sdk/common/instrumentation_scope.dart';

import 'package:opentelemetry/src/experimental_sdk.dart' as sdk;

import 'meter_provider_shared_state.dart';

class MeterSharedState {
// ignore: unused_field
final MeterProviderSharedState _meterProviderSharedState;
// ignore: unused_field
final InstrumentationScope _instrumentationScope;
sdk.Meter meter;

MeterSharedState(this._meterProviderSharedState, this._instrumentationScope) {
meter = sdk.Meter(this);
}
}
10 changes: 8 additions & 2 deletions test/unit/sdk/metrics/meter_provider_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void main() {

test(
'getting by same name, same version, same schema_url and different '
'attributes will return different meter instances', () {
'attributes will return the same meter instance', () {
const meterName = 'meterA';
const version = 'v2';
const url = 'http:schemas.com';
Expand All @@ -154,7 +154,13 @@ void main() {
final meterB = meterProvider.get(meterName,
version: version, schemaUrl: url, attributes: attributesB);

expect(identical(meterA, meterB), false);
expect(identical(meterA, meterB), true);
});

test('resource can be set', () {
final resource = sdk.Resource([api.Attribute.fromString('foo', 'bar')]);
final provider = sdk.MeterProvider(resource: resource);
expect(identical(resource, provider.resource), true);
});

// todo: implement test that verifies that changes to attributes apply to
Expand Down
42 changes: 42 additions & 0 deletions test/unit/sdk/metrics/state/instrumentation_scope_id_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@TestOn('vm')

import 'package:logging/logging.dart';
import 'package:opentelemetry/api.dart';
import 'package:opentelemetry/src/sdk/common/instrumentation_scope.dart';
import 'package:opentelemetry/src/sdk/metrics/state/meter_provider_shared_state.dart';
import 'package:test/test.dart';

void main() {
group('instrumentationScopeId:', () {
setUp(() {
Logger.root.level = Level.ALL; // defaults to Level.INFO
Logger.root.onRecord.listen((record) {
printOnFailure(
'${record.level.name}: ${record.time}: ${record.message}');
});
});

test('instrumentationScopeId with same parameters returns same id', () {
//int instrumentationScopeId(InstrumentationScope instrumentationScope) {
const nameOne = 'testName';
const versionOne = '';
const schemaUrlOne = '';
const attributesOne = <Attribute>[];

const nameTwo = 'testName';
const versionTwo = '';
const schemaUrlTwo = '';
const attributesTwo = <Attribute>[];

final scopeOne = InstrumentationScope(
nameOne, versionOne, schemaUrlOne, attributesOne);
final idOne = instrumentationScopeId(scopeOne);

final scopeTwo = InstrumentationScope(
nameTwo, versionTwo, schemaUrlTwo, attributesTwo);
final idTwo = instrumentationScopeId(scopeTwo);

expect(idOne, equals(idTwo));
});
});
}