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

fix!: Rename Resource labels to attributes #367

Merged
merged 2 commits into from
Sep 9, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module Encoder # rubocop:disable Metrics/ModuleLength

def encoded_process(resource)
service_name = 'unknown'
tags = resource&.label_enumerator&.select do |key, value|
tags = resource&.attribute_enumerator&.select do |key, value|
service_name = value if key == 'service.name'
key != 'service.name'
end
Expand Down
2 changes: 1 addition & 1 deletion exporter/otlp/lib/opentelemetry/exporter/otlp/exporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def encode(span_data) # rubocop:disable Metrics/MethodLength
.map do |resource, span_datas|
Opentelemetry::Proto::Trace::V1::ResourceSpans.new(
resource: Opentelemetry::Proto::Resource::V1::Resource.new(
attributes: resource.label_enumerator.map { |key, value| as_otlp_key_value(key, value) }
attributes: resource.attribute_enumerator.map { |key, value| as_otlp_key_value(key, value) }
),
instrumentation_library_spans: span_datas
.group_by(&:instrumentation_library)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,36 @@
module OpenTelemetry
module Resource
module Detectors
# GoogleCloudPlatform contains detect class method for determining gcp environment resource labels
# GoogleCloudPlatform contains detect class method for determining gcp environment resource attributes
module GoogleCloudPlatform
extend self

def detect # rubocop:disable Metrics/AbcSize
gcp_env = Google::Cloud::Env.new
resource_labels = {}
resource_attributes = {}
resource_constants = OpenTelemetry::SDK::Resources::Constants

if gcp_env.compute_engine?
resource_labels[resource_constants::CLOUD_RESOURCE[:provider]] = 'gcp'
resource_labels[resource_constants::CLOUD_RESOURCE[:account_id]] = gcp_env.project_id
resource_labels[resource_constants::CLOUD_RESOURCE[:region]] = gcp_env.instance_attribute('cluster-location')
resource_labels[resource_constants::CLOUD_RESOURCE[:zone]] = gcp_env.instance_zone

resource_labels[resource_constants::HOST_RESOURCE[:hostname]] = hostname
resource_labels[resource_constants::HOST_RESOURCE[:id]] = gcp_env.lookup_metadata('instance', 'id')
resource_labels[resource_constants::HOST_RESOURCE[:name]] = gcp_env.lookup_metadata('instance', 'hostname')
resource_attributes[resource_constants::CLOUD_RESOURCE[:provider]] = 'gcp'
resource_attributes[resource_constants::CLOUD_RESOURCE[:account_id]] = gcp_env.project_id
resource_attributes[resource_constants::CLOUD_RESOURCE[:region]] = gcp_env.instance_attribute('cluster-location')
resource_attributes[resource_constants::CLOUD_RESOURCE[:zone]] = gcp_env.instance_zone

resource_attributes[resource_constants::HOST_RESOURCE[:hostname]] = hostname
resource_attributes[resource_constants::HOST_RESOURCE[:id]] = gcp_env.lookup_metadata('instance', 'id')
resource_attributes[resource_constants::HOST_RESOURCE[:name]] = gcp_env.lookup_metadata('instance', 'hostname')
end

if gcp_env.kubernetes_engine?
resource_labels[resource_constants::K8S_RESOURCE[:cluster_name]] = gcp_env.instance_attribute('cluster-name')
resource_labels[resource_constants::K8S_RESOURCE[:namespace_name]] = gcp_env.kubernetes_engine_namespace_id
resource_labels[resource_constants::K8S_RESOURCE[:pod_name]] = hostname
resource_attributes[resource_constants::K8S_RESOURCE[:cluster_name]] = gcp_env.instance_attribute('cluster-name')
resource_attributes[resource_constants::K8S_RESOURCE[:namespace_name]] = gcp_env.kubernetes_engine_namespace_id
resource_attributes[resource_constants::K8S_RESOURCE[:pod_name]] = hostname

resource_labels[resource_constants::CONTAINER_RESOURCE[:name]] = ENV['CONTAINER_NAME']
resource_attributes[resource_constants::CONTAINER_RESOURCE[:name]] = ENV['CONTAINER_NAME']
end

resource_labels.delete_if { |_key, value| value.nil? || value.empty? }
OpenTelemetry::SDK::Resources::Resource.create(resource_labels)
resource_attributes.delete_if { |_key, value| value.nil? || value.empty? }
OpenTelemetry::SDK::Resources::Resource.create(resource_attributes)
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
describe OpenTelemetry::Resource::Detectors::AutoDetector do
let(:auto_detector) { OpenTelemetry::Resource::Detectors::AutoDetector }
let(:detected_resource) { auto_detector.detect }
let(:detected_resource_labels) { detected_resource.label_enumerator.to_h }
let(:expected_resource_labels) { {} }
let(:detected_resource_attributes) { detected_resource.attribute_enumerator.to_h }
let(:expected_resource_attributes) { {} }

describe '.detect' do
it 'returns detected resources' do
_(detected_resource).must_be_instance_of(OpenTelemetry::SDK::Resources::Resource)
_(detected_resource_labels).must_equal(expected_resource_labels)
_(detected_resource_attributes).must_equal(expected_resource_attributes)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@

describe '.detect' do
let(:detected_resource) { detector.detect }
let(:detected_resource_labels) { detected_resource.label_enumerator.to_h }
let(:expected_resource_labels) { {} }
let(:detected_resource_attributes) { detected_resource.attribute_enumerator.to_h }
let(:expected_resource_attributes) { {} }

it 'returns an empty resource' do
_(detected_resource).must_be_instance_of(OpenTelemetry::SDK::Resources::Resource)
_(detected_resource_labels).must_equal(expected_resource_labels)
_(detected_resource_attributes).must_equal(expected_resource_attributes)
end

describe 'when in a gcp environment' do
Expand Down Expand Up @@ -45,7 +45,7 @@
end
end

let(:expected_resource_labels) do
let(:expected_resource_attributes) do
{
'cloud.provider' => 'gcp',
'cloud.account.id' => 'opentelemetry',
Expand All @@ -62,22 +62,22 @@

it 'returns a resource with gcp attributes' do
_(detected_resource).must_be_instance_of(OpenTelemetry::SDK::Resources::Resource)
_(detected_resource_labels).must_equal(expected_resource_labels)
_(detected_resource_attributes).must_equal(expected_resource_attributes)
end

describe 'and a nil resource value is detected' do
let(:project_id) { nil }

it 'returns a resource without that label' do
_(detected_resource_labels.key?('cloud.account.id')).must_equal(false)
it 'returns a resource without that attribute' do
_(detected_resource_attributes.key?('cloud.account.id')).must_equal(false)
end
end

describe 'and an empty string resource value is detected' do
let(:project_id) { '' }

it 'returns a resource without that label' do
_(detected_resource_labels.key?('cloud.account.id')).must_equal(false)
it 'returns a resource without that attribute' do
_(detected_resource_attributes.key?('cloud.account.id')).must_equal(false)
end
end
end
Expand Down
48 changes: 24 additions & 24 deletions sdk/lib/opentelemetry/sdk/resources/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,40 @@ class Resource
class << self
private :new # rubocop:disable Style/AccessModifierDeclarations

# Returns a newly created {Resource} with the specified labels
# Returns a newly created {Resource} with the specified attributes
#
# @param [Hash{String => String, Numeric, Boolean} labels Hash of key-value pairs to be used
# as labels for this resource
# @raise [ArgumentError] If label keys and values are not strings
# @param [Hash{String => String, Numeric, Boolean} attributes Hash of key-value pairs to be used
# as attributes for this resource
# @raise [ArgumentError] If attribute keys and values are not strings
# @return [Resource]
def create(labels = {})
frozen_labels = labels.each_with_object({}) do |(k, v), memo|
raise ArgumentError, 'label keys must be strings' unless k.is_a?(String)
raise ArgumentError, 'label values must be strings, integers, floats, or booleans' unless Internal.valid_value?(v)
def create(attributes = {})
frozen_attributes = attributes.each_with_object({}) do |(k, v), memo|
raise ArgumentError, 'attribute keys must be strings' unless k.is_a?(String)
raise ArgumentError, 'attribute values must be strings, integers, floats, or booleans' unless Internal.valid_value?(v)

memo[-k] = v.freeze
end.freeze

new(frozen_labels)
new(frozen_attributes)
end

def telemetry_sdk
resource_labels = {
resource_attributes = {
Constants::TELEMETRY_SDK_RESOURCE[:name] => 'opentelemetry',
Constants::TELEMETRY_SDK_RESOURCE[:language] => 'ruby',
Constants::TELEMETRY_SDK_RESOURCE[:version] => OpenTelemetry::SDK::VERSION
}

resource_pairs = ENV['OTEL_RESOURCE_ATTRIBUTES']
return create(resource_labels) unless resource_pairs.is_a?(String)
return create(resource_attributes) unless resource_pairs.is_a?(String)

resource_pairs.split(',').each do |pair|
key, value = pair.split('=')
resource_labels[key] = value
resource_attributes[key] = value
end

resource_labels.delete_if { |_key, value| value.nil? || value.empty? }
create(resource_labels)
resource_attributes.delete_if { |_key, value| value.nil? || value.empty? }
create(resource_attributes)
end
end

Expand All @@ -55,18 +55,18 @@ def telemetry_sdk
# Users should use the {create} factory method to obtain a {Resource}
# instance.
#
# @param [Hash<String, String>] frozen_labels Frozen-hash of frozen-string
# key-value pairs to be used as labels for this resource
# @param [Hash<String, String>] frozen_attributes Frozen-hash of frozen-string
# key-value pairs to be used as attributes for this resource
# @return [Resource]
def initialize(frozen_labels)
@labels = frozen_labels
def initialize(frozen_attributes)
@attributes = frozen_attributes
end

# Returns an enumerator for labels of this {Resource}
# Returns an enumerator for attributes of this {Resource}
#
# @return [Enumerator]
def label_enumerator
@label_enumerator ||= labels.to_enum
def attribute_enumerator
@attribute_enumerator ||= attributes.to_enum
end

# Returns a new, merged {Resource} by merging the current {Resource} with
Expand All @@ -79,16 +79,16 @@ def label_enumerator
def merge(other)
return self unless other.is_a?(Resource)

merged_labels = labels.merge(other.labels) do |_, old_v, new_v|
merged_attributes = attributes.merge(other.attributes) do |_, old_v, new_v|
old_v.empty? ? new_v : old_v
end

self.class.send(:new, merged_labels.freeze)
self.class.send(:new, merged_attributes.freeze)
end

protected

attr_reader :labels
attr_reader :attributes
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions sdk/test/opentelemetry/sdk/configurator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

describe '#resource=' do
let(:configurator_resource) { configurator.instance_variable_get(:@resource) }
let(:configurator_resource_labels) { configurator_resource.label_enumerator.to_h }
let(:expected_resource_labels) do
let(:configurator_resource_attributes) { configurator_resource.attribute_enumerator.to_h }
let(:expected_resource_attributes) do
{
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'ruby',
Expand All @@ -35,11 +35,11 @@

it 'merges the resource' do
configurator.resource = OpenTelemetry::SDK::Resources::Resource.create('test_key' => 'test_value')
_(configurator_resource_labels).must_equal(expected_resource_labels)
_(configurator_resource_attributes).must_equal(expected_resource_attributes)
end

describe 'when there is a resource key collision' do
let(:expected_resource_labels) do
let(:expected_resource_attributes) do
{
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'ruby',
Expand All @@ -51,7 +51,7 @@
it 'uses the user provided resources' do
with_env('OTEL_RESOURCE_ATTRIBUTES' => 'important_value=100') do
configurator.resource = OpenTelemetry::SDK::Resources::Resource.create('important_value' => '25')
_(configurator_resource_labels).must_equal(expected_resource_labels)
_(configurator_resource_attributes).must_equal(expected_resource_attributes)
end
end
end
Expand Down
46 changes: 23 additions & 23 deletions sdk/test/opentelemetry/sdk/resources/resource_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
end

describe '.create' do
it 'can be initialized with labels' do
expected_labels = { 'k1' => 'v1', 'k2' => 'v2' }
resource = Resource.create(expected_labels)
_(resource.label_enumerator.to_h).must_equal(expected_labels)
it 'can be initialized with attributes' do
expected_attributes = { 'k1' => 'v1', 'k2' => 'v2' }
resource = Resource.create(expected_attributes)
_(resource.attribute_enumerator.to_h).must_equal(expected_attributes)
end

it 'can be empty' do
resource = Resource.create
_(resource.label_enumerator.to_h).must_be_empty
_(resource.attribute_enumerator.to_h).must_be_empty
end

it 'enforces keys are strings' do
Expand All @@ -36,21 +36,21 @@
values = ['v1', 123, 456.78, false, true]
values.each do |value|
resource = Resource.create('k1' => value)
_(resource.label_enumerator.first.last).must_equal(value)
_(resource.attribute_enumerator.first.last).must_equal(value)
end
end
end

describe '.telemetry_sdk' do
it 'returns a resource for the telemetry sdk' do
resource_labels = Resource.telemetry_sdk.label_enumerator.to_h
_(resource_labels['telemetry.sdk.name']).must_equal('opentelemetry')
_(resource_labels['telemetry.sdk.language']).must_equal('ruby')
_(resource_labels['telemetry.sdk.version']).must_match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}/)
resource_attributes = Resource.telemetry_sdk.attribute_enumerator.to_h
_(resource_attributes['telemetry.sdk.name']).must_equal('opentelemetry')
_(resource_attributes['telemetry.sdk.language']).must_equal('ruby')
_(resource_attributes['telemetry.sdk.version']).must_match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}/)
end

describe 'when the environment variable is present' do
let(:expected_resource_labels) do
let(:expected_resource_attributes) do
{
'key1' => 'value1',
'key2' => 'value2',
Expand All @@ -62,8 +62,8 @@

it 'includes environment resources' do
with_env('OTEL_RESOURCE_ATTRIBUTES' => 'key1=value1,key2=value2') do
resource_labels = Resource.telemetry_sdk.label_enumerator.to_h
_(resource_labels).must_equal(expected_resource_labels)
resource_attributes = Resource.telemetry_sdk.attribute_enumerator.to_h
_(resource_attributes).must_equal(expected_resource_attributes)
end
end
end
Expand All @@ -75,30 +75,30 @@
res2 = Resource.create('k3' => 'v3', 'k4' => 'v4')
res3 = res1.merge(res2)

_(res3.label_enumerator.to_h).must_equal('k1' => 'v1', 'k2' => 'v2',
'k3' => 'v3', 'k4' => 'v4')
_(res1.label_enumerator.to_h).must_equal('k1' => 'v1', 'k2' => 'v2')
_(res2.label_enumerator.to_h).must_equal('k3' => 'v3', 'k4' => 'v4')
_(res3.attribute_enumerator.to_h).must_equal('k1' => 'v1', 'k2' => 'v2',
'k3' => 'v3', 'k4' => 'v4')
_(res1.attribute_enumerator.to_h).must_equal('k1' => 'v1', 'k2' => 'v2')
_(res2.attribute_enumerator.to_h).must_equal('k3' => 'v3', 'k4' => 'v4')
end

it 'does not overwrite receiver\'s keys when value is non-empty' do
res1 = Resource.create('k1' => 'v1', 'k2' => 'v2')
res2 = Resource.create('k2' => '2v2', 'k3' => '2v3')
res3 = res1.merge(res2)

_(res3.label_enumerator.to_h).must_equal('k1' => 'v1',
'k2' => 'v2',
'k3' => '2v3')
_(res3.attribute_enumerator.to_h).must_equal('k1' => 'v1',
'k2' => 'v2',
'k3' => '2v3')
end

it 'overwrites receiver\'s key when value is empty' do
res1 = Resource.create('k1' => 'v1', 'k2' => '')
res2 = Resource.create('k2' => '2v2', 'k3' => '2v3')
res3 = res1.merge(res2)

_(res3.label_enumerator.to_h).must_equal('k1' => 'v1',
'k2' => '2v2',
'k3' => '2v3')
_(res3.attribute_enumerator.to_h).must_equal('k1' => 'v1',
'k2' => '2v2',
'k3' => '2v3')
end
end
end