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 3 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
1 change: 1 addition & 0 deletions lib/src/experimental_api.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
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;
4 changes: 4 additions & 0 deletions lib/src/experimental_sdk.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export 'sdk/metrics/counter.dart' show Counter;
export 'sdk/metrics/meter_provider.dart' show MeterProvider;
export 'sdk/metrics/meter.dart' show Meter;
export 'sdk/metrics/state/meter_shared_state.dart' show MeterSharedState;
export 'sdk/metrics/state/meter_provider_shared_state.dart'
show MeterProviderSharedState;
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved
export 'sdk/resource/resource.dart' show Resource;
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}
5 changes: 5 additions & 0 deletions lib/src/sdk/metrics/meter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import 'package:opentelemetry/src/experimental_sdk.dart' as sdk;
import 'package:opentelemetry/src/experimental_api.dart' as api;

class Meter implements api.Meter {
// ignore: unused_field
final sdk.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;
}
}
32 changes: 32 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,32 @@
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 hash4(
instrumentationScope.name,
instrumentationScope.version,
instrumentationScope.schemaUrl,
instrumentationScope.attributes.isEmpty
? const []
: instrumentationScope.attributes);
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved
}

class MeterProviderSharedState {
Resource resource;
Map<int, MeterSharedState> meterSharedStates = {};
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved

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;
}
}
15 changes: 15 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,15 @@
import 'package:opentelemetry/src/sdk/common/instrumentation_scope.dart';

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

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

MeterSharedState(this._meterProviderSharedState, this._instrumentationScope) {
meter = sdk.Meter(this);
}
}
dustinlessard-wf marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions test/unit/sdk/metrics/meter_provider_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ void main() {
expect(identical(meterA, meterB), false);
});

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
// previously created meters
// https://github.com/Workiva/opentelemetry-dart/issues/74
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));
});
});
}