From d06c0e2290c13e618f47adfc3326bb42f9d2fd30 Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Fri, 1 Apr 2022 11:28:58 -0400 Subject: [PATCH] Remove access of span.attributes --- lib/src/api/common/attribute.dart | 38 ++++--- lib/src/api/common/attribute_util.dart | 18 ---- lib/src/api/common/attributes.dart | 28 +---- lib/src/api/trace/nonrecording_span.dart | 3 +- lib/src/api/trace/span.dart | 5 +- lib/src/sdk/internal/utils.dart | 2 +- .../trace/exporters/collector_exporter.dart | 3 +- lib/src/sdk/trace/span.dart | 101 +++++++++++------- lib/src/sdk/trace/span_limits.dart | 26 ++--- lib/src/sdk/trace/tracer.dart | 5 +- test/unit/api/attribute_test.dart | 58 ++++++++++ test/unit/sdk/span_limits_test.dart | 83 +++++++------- 12 files changed, 215 insertions(+), 155 deletions(-) delete mode 100644 lib/src/api/common/attribute_util.dart create mode 100644 test/unit/api/attribute_test.dart diff --git a/lib/src/api/common/attribute.dart b/lib/src/api/common/attribute.dart index f2a1fafe..9304180d 100644 --- a/lib/src/api/common/attribute.dart +++ b/lib/src/api/common/attribute.dart @@ -1,34 +1,48 @@ +import 'package:opentelemetry/src/sdk/internal/utils.dart'; + /// A representation of a single piece of metadata attached to trace span. class Attribute { final String key; final Object value; /// Create an Attribute from a String value. - Attribute.fromString(this.key, String this.value); + Attribute.fromString(this.key, String this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a boolean value. // ignore: avoid_positional_boolean_parameters - Attribute.fromBoolean(this.key, bool this.value); + Attribute.fromBoolean(this.key, bool this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a double-precision floating-point value. - Attribute.fromDouble(this.key, double this.value); + Attribute.fromDouble(this.key, double this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from an integer value. - Attribute.fromInt(this.key, int this.value); + Attribute.fromInt(this.key, int this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a list of String values. - Attribute.fromStringList(this.key, List this.value); + Attribute.fromStringList(this.key, List this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a list of boolean values. - Attribute.fromBooleanList(this.key, List this.value); + Attribute.fromBooleanList(this.key, List this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a list of double-precision floating-point values. - Attribute.fromDoubleList(this.key, List this.value); + Attribute.fromDoubleList(this.key, List this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } /// Create an Attribute from a list of integer values. - Attribute.fromIntList(this.key, List this.value); - - ///Create an Attribute from an object. - ///Do we need to do a type check of value? - Attribute.fromObject(this.key, this.value); + Attribute.fromIntList(this.key, List this.value) { + Utils.checkArgument(key != null, "key can't be null"); + } } diff --git a/lib/src/api/common/attribute_util.dart b/lib/src/api/common/attribute_util.dart deleted file mode 100644 index 0027a4d3..00000000 --- a/lib/src/api/common/attribute_util.dart +++ /dev/null @@ -1,18 +0,0 @@ -class AttributeUtil { - //Truncate just strings which length is longer than configuration. - //Reference: https://github.com/open-telemetry/opentelemetry-java/blob/14ffacd1cdd22f5aa556eeda4a569c7f144eadf2/sdk/common/src/main/java/io/opentelemetry/sdk/internal/AttributeUtil.java#L80 - static Object applyAttributeLengthLimit(Object value, int lengthLimit) { - if (value is String) { - return value.length > lengthLimit - ? value.substring(0, lengthLimit) - : value; - } else if (value is List) { - for (var i = 0; i < value.length; i++) { - value[i] = value[i].length > lengthLimit - ? value[i].substring(0, lengthLimit) - : value[i]; - } - } - return value; - } -} diff --git a/lib/src/api/common/attributes.dart b/lib/src/api/common/attributes.dart index b7bd22e4..4e5a87e3 100644 --- a/lib/src/api/common/attributes.dart +++ b/lib/src/api/common/attributes.dart @@ -1,45 +1,27 @@ import 'attribute.dart'; -import 'attribute_util.dart'; /// A representation of a collection of metadata attached to a trace span. -/// From OpenTelemetry Specification about attributes, -/// https://opentelemetry.io/docs/reference/specification/common/common/#exempt-entities -/// Some attributes are exempt from limits, in this case, it is set as -1. -/// If it is 0, it is considered as not accepting attributes. class Attributes { Map _attributes = {}; - int _maxNumAttributes; - int _maxNumAttributesLength; /// Instantiate an empty Attributes. - Attributes.empty([int maxNumAttributes, int maxNumAttributesLength]) { + Attributes.empty() { _attributes = {}; - _maxNumAttributes = maxNumAttributes ?? -1; // no restrain limits - _maxNumAttributesLength = maxNumAttributesLength ?? -1; } /// Retrieve the value associated with the Attribute with key [key]. Object get(String key) => _attributes[key]; + /// + int get length => _attributes.length; + /// Retrieve the keys of all Attributes in this collection. Iterable get keys => _attributes.keys; - ///Retrieve the number of attributes contained in this. - int get size => _attributes.length; - /// Add an Attribute [attribute]. /// If an Attribute with the same key already exists, it will be overwritten. - /// If the number of attributes is too many, it will drop it silently. - /// If the attribute value length is too long, it will be truncated. void add(Attribute attribute) { - if (_maxNumAttributes == -1) { - _attributes[attribute.key] = attribute.value; - return; - } - if (_attributes.length >= _maxNumAttributes && - !_attributes.containsKey(attribute.key)) return; - _attributes[attribute.key] = AttributeUtil.applyAttributeLengthLimit( - attribute.value, _maxNumAttributesLength); + _attributes[attribute.key] = attribute.value; } /// Add all Attributes in List [attributes]. diff --git a/lib/src/api/trace/nonrecording_span.dart b/lib/src/api/trace/nonrecording_span.dart index 50a0303f..526b3524 100644 --- a/lib/src/api/trace/nonrecording_span.dart +++ b/lib/src/api/trace/nonrecording_span.dart @@ -16,11 +16,10 @@ class NonRecordingSpan implements api.Span { NonRecordingSpan(this._spanContext); - @override api.Attributes get attributes => _attributes; @override - set attributes(api.Attributes attributes) { + void setAttributes(api.Attributes attributes) { return; } diff --git a/lib/src/api/trace/span.dart b/lib/src/api/trace/span.dart index d92ee4c7..946bd3f1 100644 --- a/lib/src/api/trace/span.dart +++ b/lib/src/api/trace/span.dart @@ -45,10 +45,7 @@ abstract class Span { api.SpanStatus get status; /// Set metadata to be included on this span. - set attributes(api.Attributes attributes); - - /// Retrieve metadata included on this span. - api.Attributes get attributes; + void setAttributes(api.Attributes attributes); /// Retrieve the resource on this span. api.Resource get resource; diff --git a/lib/src/sdk/internal/utils.dart b/lib/src/sdk/internal/utils.dart index 66a9bffe..b3d77efd 100644 --- a/lib/src/sdk/internal/utils.dart +++ b/lib/src/sdk/internal/utils.dart @@ -2,6 +2,6 @@ class Utils { ///Check argument // ignore: avoid_positional_boolean_parameters static void checkArgument(bool isValid, String errorMessage) { - if (!isValid) throw Exception(errorMessage); + if (!isValid) throw ArgumentError(errorMessage); } } diff --git a/lib/src/sdk/trace/exporters/collector_exporter.dart b/lib/src/sdk/trace/exporters/collector_exporter.dart index f7338b7f..3e0fec3f 100644 --- a/lib/src/sdk/trace/exporters/collector_exporter.dart +++ b/lib/src/sdk/trace/exporters/collector_exporter.dart @@ -6,6 +6,7 @@ import 'opentelemetry/proto/collector/trace/v1/trace_service.pb.dart' import 'opentelemetry/proto/trace/v1/trace.pb.dart' as pb_trace; import 'opentelemetry/proto/resource/v1/resource.pb.dart' as pb_resource; import 'opentelemetry/proto/common/v1/common.pb.dart' as pb_common; +import '../span.dart' as spansdk; class CollectorExporter implements api.SpanExporter { Uri uri; @@ -74,7 +75,7 @@ class CollectorExporter implements api.SpanExporter { return rss; } - pb_trace.Span _spanToProtobuf(api.Span span) { + pb_trace.Span _spanToProtobuf(spansdk.Span span) { pb_trace.Status_StatusCode statusCode; switch (span.status.code) { case api.StatusCode.unset: diff --git a/lib/src/sdk/trace/span.dart b/lib/src/sdk/trace/span.dart index 700dc7da..0ba7665e 100644 --- a/lib/src/sdk/trace/span.dart +++ b/lib/src/sdk/trace/span.dart @@ -2,6 +2,7 @@ import 'package:fixnum/fixnum.dart'; import 'package:opentelemetry/src/sdk/trace/span_limits.dart'; import '../../../api.dart' as api; +import '../../../api.dart'; /// A representation of a single operation within a trace. class Span implements api.Span { @@ -25,14 +26,13 @@ class Span implements api.Span { /// Construct a [Span]. Span(this.name, this._spanContext, this._parentSpanId, this._processors, this._resource, this._instrumentationLibrary, - {api.Attributes attributes, SpanLimits limits}) { + {api.Attributes attributes, SpanLimits spanlimits}) { _startTime = Int64(DateTime.now().toUtc().microsecondsSinceEpoch); - if (limits != null) _spanLimits = limits; - _attributes = api.Attributes.empty( - _spanLimits.maxNumAttributes, _spanLimits.maxNumAttributeLength); + if (spanlimits != null) _spanLimits = spanlimits; + _attributes = Attributes.empty(); if (attributes != null) { - _setAttributes(attributes); + setAttributes(attributes); } for (var i = 0; i < _processors.length; i++) { @@ -86,59 +86,82 @@ class Span implements api.Span { api.InstrumentationLibrary get instrumentationLibrary => _instrumentationLibrary; - @override + /// Retrieve metadata included on this span. api.Attributes get attributes => _attributes; - ///not sure about this part, if span.attributes = attributes, then we need to - ///discard all previous added attributes,create a new one? @override - set attributes(api.Attributes attributes) { - _setAttributes(attributes); - } + void setAttributes(api.Attributes attributes) { + if (_spanLimits.maxNumAttributes == 0) return; - void _setAttributes(api.Attributes attributes) { for (final key in attributes.keys) { - final val = attributes.get(key); - - //final reBuild = _reBuildAttribute(key, val); - //we also could do this if we add an API in attribute.dart - final reBuild = api.Attribute.fromObject(key, val); + final obj = _attributes.get(key); + //If current attributes.length is equal or greater than maxNumAttributes and + //key is not in current map, drop it. + if (_attributes.length >= _spanLimits.maxNumAttributes && obj == null) { + continue; + } + + //otherwise rebuild this attribute, truncate it and put it in + final reBuild = _reBuildAttribute(key, attributes.get(key)); _attributes.add(reBuild); } } /// reBuild an attribute, this way it is tightly coupled with the type we supported, /// if later we added more types, then we need to change this method. - // api.Attribute _reBuildAttribute(String key, dynamic value) { - // if (value is bool) { - // return api.Attribute.fromBoolean(key, value); - // } else if (value is List) { - // return api.Attribute.fromBooleanList(key, value); - // } else if (value is int) { - // return api.Attribute.fromInt(key, value); - // } else if (value is List) { - // return api.Attribute.fromIntList(key, value); - // } else if (value is double) { - // return api.Attribute.fromDouble(key, value); - // } else if (value is List) { - // return api.Attribute.fromDoubleList(key, value); - // } else if (value is String) { - // return api.Attribute.fromString(key, value); - // } else if (value is List) { - // return api.Attribute.fromStringList(key, value); - // } else { - // throw Exception("No responding type with this attribute's value"); - // } - // } + api.Attribute _reBuildAttribute(String key, dynamic value) { + if (value is bool) { + return api.Attribute.fromBoolean(key, value); + } else if (value is List) { + return api.Attribute.fromBooleanList(key, value); + } else if (value is int) { + return api.Attribute.fromInt(key, value); + } else if (value is List) { + return api.Attribute.fromIntList(key, value); + } else if (value is double) { + return api.Attribute.fromDouble(key, value); + } else if (value is List) { + return api.Attribute.fromDoubleList(key, value); + } else if (value is String) { + return api.Attribute.fromString(key, + _applyAttributeLengthLimit(value, _spanLimits.maxNumAttributeLength)); + } else if (value is List) { + for (var i = 0; i < value.length; i++) { + value[i] = _applyAttributeLengthLimit( + value[i], _spanLimits.maxNumAttributeLength); + } + return api.Attribute.fromStringList(key, value); + } else { + throw Exception("No responding type with this attribute's value"); + } + } @override void recordException(dynamic exception, {StackTrace stackTrace}) { + // ignore: todo // TODO: O11Y-1531: Consider integration of Events here. setStatus(api.StatusCode.error, description: exception.toString()); - attributes.addAll([ + _attributes.addAll([ api.Attribute.fromBoolean('error', true), api.Attribute.fromString('exception', exception.toString()), api.Attribute.fromString('stacktrace', stackTrace.toString()), ]); } + + //Truncate just strings which length is longer than configuration. + //Reference: https://github.com/open-telemetry/opentelemetry-java/blob/14ffacd1cdd22f5aa556eeda4a569c7f144eadf2/sdk/common/src/main/java/io/opentelemetry/sdk/internal/AttributeUtil.java#L80 + static Object _applyAttributeLengthLimit(Object value, int lengthLimit) { + if (value is String) { + return value.length > lengthLimit + ? value.substring(0, lengthLimit) + : value; + } else if (value is List) { + for (var i = 0; i < value.length; i++) { + value[i] = value[i].length > lengthLimit + ? value[i].substring(0, lengthLimit) + : value[i]; + } + } + return value; + } } diff --git a/lib/src/sdk/trace/span_limits.dart b/lib/src/sdk/trace/span_limits.dart index eadd681b..808f099f 100644 --- a/lib/src/sdk/trace/span_limits.dart +++ b/lib/src/sdk/trace/span_limits.dart @@ -1,12 +1,12 @@ import '../internal/utils.dart'; class SpanLimits { - final DEFAULT_MAXNUM_ATTRIBUTES = 200; - final DEFAULT_MAXNUM_EVENTS = 128; - final DEFAULT_MAXNUM_LINKS = 128; - final DEFAULT_MAXNUM_ATTRIBUTE_PER_EVENT = 128; - final DEFAULT_MAXNUM_ATTRIBUTES_PER_LINK = 128; - final DEFAULT_MAXNUM_ATTRIBUTES_LENGTH = 1000; + final _DEFAULT_MAXNUM_ATTRIBUTES = 200; + final _DEFAULT_MAXNUM_EVENTS = 128; + final _DEFAULT_MAXNUM_LINKS = 128; + final _DEFAULT_MAXNUM_ATTRIBUTE_PER_EVENT = 128; + final _DEFAULT_MAXNUM_ATTRIBUTES_PER_LINK = 128; + final _DEFAULT_MAXNUM_ATTRIBUTES_LENGTH = 1000; int _maxNumAttributes; int _maxNumEvents; @@ -15,7 +15,7 @@ class SpanLimits { int _maxNumAttributesPerLink; int _maxNumAttributeLength; - /// + ///setters set maxNumAttributes(int maxNumberOfAttributes) { Utils.checkArgument(maxNumberOfAttributes >= 0, 'maxNumberOfAttributes must be greater or equal to zero'); @@ -70,14 +70,14 @@ class SpanLimits { int maxNumAttributesPerEvent, int maxNumAttributesPerLink, int maxNumAttributeLength}) { - _maxNumAttributes = maxNumAttributes ?? DEFAULT_MAXNUM_ATTRIBUTES; - _maxNumEvents = maxNumEvents ?? DEFAULT_MAXNUM_EVENTS; - _maxNumLink = maxNumLink ?? DEFAULT_MAXNUM_LINKS; + _maxNumAttributes = maxNumAttributes ?? _DEFAULT_MAXNUM_ATTRIBUTES; + _maxNumEvents = maxNumEvents ?? _DEFAULT_MAXNUM_EVENTS; + _maxNumLink = maxNumLink ?? _DEFAULT_MAXNUM_LINKS; _maxNumAttributesPerEvent = - maxNumAttributesPerEvent ?? DEFAULT_MAXNUM_ATTRIBUTE_PER_EVENT; + maxNumAttributesPerEvent ?? _DEFAULT_MAXNUM_ATTRIBUTE_PER_EVENT; _maxNumAttributesPerLink = - maxNumAttributesPerLink ?? DEFAULT_MAXNUM_ATTRIBUTES_PER_LINK; + maxNumAttributesPerLink ?? _DEFAULT_MAXNUM_ATTRIBUTES_PER_LINK; _maxNumAttributeLength = - maxNumAttributeLength ?? DEFAULT_MAXNUM_ATTRIBUTES_LENGTH; + maxNumAttributeLength ?? _DEFAULT_MAXNUM_ATTRIBUTES_LENGTH; } } diff --git a/lib/src/sdk/trace/tracer.dart b/lib/src/sdk/trace/tracer.dart index 7918f3d8..563c4399 100644 --- a/lib/src/sdk/trace/tracer.dart +++ b/lib/src/sdk/trace/tracer.dart @@ -23,8 +23,7 @@ class Tracer implements api.Tracer { api.Span startSpan(String name, {api.Context context, api.Attributes attributes}) { context ??= api.Context.current; - attributes ??= api.Attributes.empty( - _spanLimits.maxNumAttributes, _spanLimits.maxNumAttributeLength); + attributes ??= api.Attributes.empty(); // If a valid, active Span is present in the context, use it as this Span's // parent. If the Context does not contain an active parent Span, create @@ -56,7 +55,7 @@ class Tracer implements api.Tracer { return sdk.Span(name, spanContext, parentSpanId, _processors, _resource, _instrumentationLibrary, - attributes: attributes, limits: _spanLimits); + attributes: attributes, spanlimits: _spanLimits); } /// Records a span of the given [name] for the given function diff --git a/test/unit/api/attribute_test.dart b/test/unit/api/attribute_test.dart new file mode 100644 index 00000000..7e73dcbc --- /dev/null +++ b/test/unit/api/attribute_test.dart @@ -0,0 +1,58 @@ +import 'package:opentelemetry/api.dart'; +import 'package:test/test.dart'; + +void main() { + test("test bool key can't be null", () { + expect( + () => Attribute.fromBoolean(null, true), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + + test("test int key can't be null", () { + expect( + () => Attribute.fromInt(null, 2), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + + test("test String key can't be null", () { + expect( + () => Attribute.fromString(null, 'abc'), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + + test("test double key can't be null", () { + expect( + () => Attribute.fromDouble(null, 0.1), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + test("test BoolList key can't be null", () { + expect( + () => Attribute.fromBooleanList(null, [true, false]), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + + test("test IntList key can't be null", () { + expect( + () => Attribute.fromIntList(null, [2, 3]), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + test("test StringList key can't be null", () { + expect( + () => Attribute.fromStringList(null, ['1', '2']), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); + + test("test DoubleList key can't be null", () { + expect( + () => Attribute.fromDoubleList(null, [0.2, 0.1]), + throwsA(isA() + .having((error) => error.message, 'message', "key can't be null"))); + }); +} diff --git a/test/unit/sdk/span_limits_test.dart b/test/unit/sdk/span_limits_test.dart index d7511c5a..82ee390a 100644 --- a/test/unit/sdk/span_limits_test.dart +++ b/test/unit/sdk/span_limits_test.dart @@ -1,14 +1,13 @@ +import 'package:opentelemetry/api.dart'; import 'package:opentelemetry/src/api/common/attribute.dart'; import 'package:opentelemetry/src/api/common/attributes.dart'; -import 'package:opentelemetry/src/api/trace/tracer.dart'; import 'package:opentelemetry/src/sdk/trace/span_limits.dart'; -import 'package:opentelemetry/src/sdk/trace/tracer_provider.dart'; import 'package:test/test.dart'; +import 'package:opentelemetry/src/sdk/trace/span.dart' as sdkspan; void main() { const maxAttributes = 3; const maxAttributeLength = 5; - Tracer tracer; final attrShort = Attribute.fromString('shortkey', '55555'); final dupShort = Attribute.fromString('shortkey', '66666'); final attrLong = Attribute.fromString('longkey', '5555555'); @@ -18,21 +17,18 @@ void main() { final attrDoubleArray = Attribute.fromDoubleList('doubleList', [0.1, 0.2]); final attrStringArray = Attribute.fromStringList('stringList', ['1111', '1111111']); - final attrNull = Attribute.fromInt(null, 2); final limits = SpanLimits( maxNumAttributes: maxAttributes, maxNumAttributeLength: maxAttributeLength); - setUp(() { - final tracerProvider = TracerProvider(limits: limits); - tracer = tracerProvider.getTracer('test_tracer'); - }); + setUp(() {}); test('test spanlimits normal', () { final attrs = Attributes.empty() ..addAll([attrShort, attrDoubleArray, attrStringArray]); - final span = tracer.startSpan('spanlimits', attributes: attrs); - expect(span.attributes.size, equals(3)); + final span = sdkspan.Span('foo', null, SpanId([4, 5, 6]), [], null, null, + attributes: attrs, spanlimits: limits); + expect(span.attributes.length, equals(3)); expect(span.attributes.get('shortkey'), equals('55555')); expect(span.attributes.get('doubleList'), equals([0.1, 0.2])); expect(span.attributes.get('stringList'), equals(['1111', '11111'])); @@ -41,88 +37,97 @@ void main() { test('test spanlimits maxNumAttributes', () { final attrs = Attributes.empty() ..addAll([attrShort, attrLong, attrInt, attrBool]); - final span = tracer.startSpan('spanlimits', attributes: attrs); - expect(span.attributes.size, equals(maxAttributes)); + final span = sdkspan.Span('foo', null, SpanId([4, 5, 6]), [], null, null, + attributes: attrs, spanlimits: limits); + expect(span.attributes.length, equals(maxAttributes)); expect(span.attributes.get('boolean'), equals(null)); }); test('test spanlimits maxNumAttributeLength', () { final attrs = Attributes.empty()..addAll([attrShort, attrLong]); - final span = tracer.startSpan('spanlimits', attributes: attrs); + final span = sdkspan.Span('foo', null, SpanId([4, 5, 6]), [], null, null, + attributes: attrs, spanlimits: limits); expect(span.attributes.get('shortkey'), equals('55555')); expect(span.attributes.get('longkey'), equals('55555')); }); test('test spanlimits normal from span', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty() ..addAll([attrShort, attrInt, attrDoubleArray]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - expect(span.attributes.size, equals(3)); + span.setAttributes(attrs); + expect(span.attributes.length, equals(3)); expect(span.attributes.get('shortkey'), equals('55555')); expect(span.attributes.get('intKey'), equals(12)); expect(span.attributes.get('doubleList'), equals([0.1, 0.2])); }); test('test spanlimits maxNumAttributes from span', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty() ..addAll([attrShort, attrLong, attrInt, attrBool]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - expect(span.attributes.size, equals(maxAttributes)); + span.setAttributes(attrs); + expect(span.attributes.length, equals(maxAttributes)); expect(span.attributes.get('boolean'), equals(null)); }); - test('test spanlimits maxNumAttributeLength', () { + test('test spanlimits maxNumAttributeLength with setAttributes', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty()..addAll([attrShort, attrLong]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; + span.setAttributes(attrs); expect(span.attributes.get('shortkey'), equals('55555')); expect(span.attributes.get('longkey'), equals('55555')); }); test('test spanlimits from span, then add more', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty()..addAll([attrShort, attrLong]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; + span.setAttributes(attrs); expect(span.attributes.get('shortkey'), equals('55555')); expect(span.attributes.get('longkey'), equals('55555')); - span.attributes.add(attrBool); - expect(span.attributes.size, equals(3)); + span.setAttributes(Attributes.empty()..add(attrBool)); + expect(span.attributes.length, equals(maxAttributes)); expect(span.attributes.get('boolKey'), equals(true)); - span.attributes.add(attrDoubleArray); - expect(span.attributes.size, equals(3)); + span.setAttributes(Attributes.empty()..add(attrDoubleArray)); + expect(span.attributes.length, equals(maxAttributes)); expect(span.attributes.get('doubleList'), equals(null)); }); test('test add same key twice', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty()..addAll([attrShort, dupShort]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - expect(span.attributes.size, 1); + span.setAttributes(attrs); + expect(span.attributes.length, 1); expect(span.attributes.get('shortkey'), equals('66666')); - span.attributes.addAll([attrLong, dupLong]); - expect(span.attributes.size, 2); + span.setAttributes(Attributes.empty()..addAll([attrLong, dupLong])); + expect(span.attributes.length, 2); expect(span.attributes.get('longkey'), equals('66666')); }); test('test add same key twice', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty() ..addAll([attrShort, dupShort, attrLong, dupLong]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - expect(span.attributes.size, 2); + span.setAttributes(attrs); + expect(span.attributes.length, 2); expect(span.attributes.get('shortkey'), equals('66666')); expect(span.attributes.get('longkey'), equals('66666')); }); test('test add oversized string list', () { + final span = + sdkspan.Span('test', null, null, [], null, null, spanlimits: limits); final attrs = Attributes.empty() ..addAll([attrShort, dupShort, attrLong, dupLong]); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - expect(span.attributes.size, 2); + span.setAttributes(attrs); + expect(span.attributes.length, 2); expect(span.attributes.get('shortkey'), equals('66666')); expect(span.attributes.get('longkey'), equals('66666')); }); - - test('test add null as key', () { - final attrs = Attributes.empty()..add(attrNull); - final span = tracer.startSpan('spanlimits')..attributes = attrs; - span.attributes.add(Attribute.fromBoolean(null, false)); - expect(span.attributes.get(null), equals(false)); - }); }