Skip to content
Open
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
41 changes: 24 additions & 17 deletions sdk/lib/opentelemetry/sdk/internal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,34 @@ def numeric?(value)
end

def valid_simple_value?(value)
value.instance_of?(String) || boolean?(value) || numeric?(value)
value.instance_of?(String) || boolean?(value) || numeric?(value) || value.nil?
end

def valid_array_value?(value)
return false unless value.is_a?(Array)
return true if value.empty?
def valid_value?(value)
to_check = [value]
seen = Set.new
until to_check.empty?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating this to comply latest spec.
Have you considered using a recursive approach instead?

def valid_value?(value, depth = 0)
  # ...
  case value
  when String, TrueClass, FalseClass, Integer, Float, NilClass
    true
  when Array
    value.all? { |v| valid_value?(v, depth + 1) }
  when Hash
    value.all? { |k, v| valid_key?(k) && valid_value?(v, depth + 1) }
  else
    false
  end
  # ...
end

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I originally used the recursive approach, but I was a bit concerned about larger more complex JSON style attributes, since there isn't a natural limit on nesting.

current = to_check.pop
next if valid_simple_value?(current)

case value.first
when String
value.all? { |v| v.instance_of?(String) }
when TrueClass, FalseClass
value.all? { |v| boolean?(v) }
when Numeric
value.all? { |v| numeric?(v) }
else
false
end
end
return false if seen.include?(current.object_id)

def valid_value?(value)
valid_simple_value?(value) || valid_array_value?(value)
seen << current.object_id

case current
when Array
current.each { |v| to_check << v }
when Hash
current.each do |k, v|
return false unless valid_key?(k)

to_check << v
end
else
return false
end
end
true
end

def valid_attributes?(owner, kind, attrs)
Expand Down
12 changes: 6 additions & 6 deletions sdk/test/opentelemetry/sdk/trace/span_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@
end
end

it 'reports an error for a NilClass value, which is invalid' do
it 'does not report an error for a NilClass value, as empty values are valid' do
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
span.set_attribute('foo', nil)
span.finish
_(log_stream.string).must_match(/invalid span attribute value type NilClass for key 'foo' on span 'name'/)
_(log_stream.string.length).must_equal(0)
end
end

Expand Down Expand Up @@ -223,12 +223,12 @@
_(events.first.attributes).must_equal(attrs)
end

it 'does not keep nil-valued attributes' do
it 'keeps nil-valued attributes' do
attrs = { 'foo' => nil }
span.add_event('added', attributes: attrs)
events = span.events
_(events.size).must_equal(1)
_(events.first.attributes).must_equal({})
_(events.first.attributes).must_equal({ 'foo' => nil })
end

it 'accepts array-valued attributes' do
Expand All @@ -247,12 +247,12 @@
_(events.first.attributes).must_equal({})
end

it 'does not accept array-valued attributes if the elements are different types' do
it 'accepts array-valued attributes even if the elements are different types' do
attrs = { 'foo' => [1, 2, 'bar'] }
span.add_event('added', attributes: attrs)
events = span.events
_(events.size).must_equal(1)
_(events.first.attributes).must_equal({})
_(events.first.attributes).must_equal({ 'foo' => [1, 2, 'bar'] })
end

it 'accepts array-valued attributes if the elements are true and false' do
Expand Down
Loading