TL;DR

  • resource用于描述“产生otel数据的实体”的一些属性
  • 可以通过OTEL_RESOURCE_ATTRIBUTES配置额外的resource属性
  • 也可以在配置sdk时,通过c.resource = OpenTelemetry::SDK::Resources::Resource.create({})添加属性
  • 还有c.service_name=c.service_version=
  • OpenTelemetry::SDK.configure所配置的resource,会用来创建TracerProvider,然后TracerProvider产生span时,会使用这个resource
什么是resource

环境变量OTELRESOURCEATTRIBUTES

搜索OTEL_RESOURCE_ATTRIBUTES,可见位于 opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/resources/resource.rb

打印其调用栈

 def telemetry_sdk
+  pp caller
   resource_attributes = {
     # ...
   }

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

   # ...
   create(resource_attributes)
 end


[".../opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/resources/resource.rb:34:in `default'",
 ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin/transformer.rb:37:in `'",
 ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin/transformer.rb:12:in `'",
 ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin/transformer.rb:10:in `'",
 ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin/transformer.rb:9:in `'",
 ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin/transformer.rb:8:in `
'", # ... ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry/exporter/zipkin.rb:25:in `
'", # ... ".../opentelemetry-exporter-zipkin-0.21.0/lib/opentelemetry-exporter-zipkin.rb:7:in `
'", # ... ".../bundler.rb:114:in `require'", ".../config/application.rb:16:in `
'", # ... "bin/rails:4:in `
'"]

回到代码

# opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/resources/resource.rb
def default
  @default ||= create(SemanticConventions::Resource::SERVICE_NAME => 'unknown_service').merge(process).merge(telemetry_sdk).merge(service_name_from_env)
end

def process
  resource_attributes = {
    SemanticConventions::Resource::PROCESS_PID => Process.pid,
    # ...
  }

  create(resource_attributes)
end

def telemetry_sdk
  resource_attributes = {
    # ...
  }

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

  # ...
  create(resource_attributes)
end

def service_name_from_env
  service_name = ENV['OTEL_SERVICE_NAME']
  create(SemanticConventions::Resource::SERVICE_NAME => service_name) unless service_name.nil?
end

可见resource在创建时会收集进程ID、环境变量(如OTEL_RESOURCE_ATTRIBUTES

添加属性

除了用OTEL_RESOURCE_ATTRIBUTES配置属性,还可以在配置sdk时,手动merge。例如:

OpenTelemetry::SDK.configure do |c|
  c.add_span_processor(
    # ...
  )
  c.resource = OpenTelemetry::SDK::Resources::Resource.create({
    OpenTelemetry::SemanticConventions::Resource::SERVICE_NAMESPACE => 'tracing',
    # ...
  })
end

源码如下,虽然是=,但其实是merge

# opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/configurator.rb
module OpenTelemetry
  module SDK
    class Configurator
      def initialize
        # ...
        @resource = Resources::Resource.default
      end

      def resource=(new_resource)
        @resource = @resource.merge(new_resource)
      end
    end
  end
end

其他修改方式

观察configurator的代码,发现还有service_name=service_version=

# opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/configurator.rb
def service_name=(service_name)
  self.resource = OpenTelemetry::SDK::Resources::Resource.create(
    OpenTelemetry::SemanticConventions::Resource::SERVICE_NAME => service_name
  )
end

def service_version=(service_version)
  self.resource = OpenTelemetry::SDK::Resources::Resource.create(
    OpenTelemetry::SemanticConventions::Resource::SERVICE_VERSION => service_version
  )
end

resource的使用

configurator执行时,会用resource创建TracerProvider

# opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/configurator.rb
def configure
  # ...
  OpenTelemetry.tracer_provider = tracer_provider
  install_instrumentation
end

private

def tracer_provider
  @tracer_provider ||= Trace::TracerProvider.new(resource: @resource)
end

然后TracerProvider产生span时,会使用这个resource

# opentelemetry-sdk-1.2.0/lib/opentelemetry/sdk/trace/tracer_provider.rb
def internal_start_span(name, kind, attributes, links, start_timestamp, parent_context, instrumentation_scope) # rubocop:disable Metrics/MethodLength
  # ...
  if result.recording? && !@stopped
    # ...
    Span.new(
      # ...
      @resource,
      instrumentation_scope
    )
  else
    OpenTelemetry::Trace.non_recording_span(OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id, tracestate: result.tracestate))
  end
end