Skip to content
This repository has been archived by the owner on Sep 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #8 from DataDog/add_otel_resource_handling
Browse files Browse the repository at this point in the history
Add otel resource label and `service.name` handling
  • Loading branch information
ericmustin authored Dec 4, 2020
2 parents 9ff3c2b + 72eb0ef commit 56b6503
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 107 deletions.
12 changes: 6 additions & 6 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ AllCops:
Lint/UnusedMethodArgument:
Enabled: false
Metrics/AbcSize:
Max: 35
Max: 36
Metrics/BlockLength:
Max: 38
Max: 40
Metrics/ClassLength:
Max: 161
Max: 189
Metrics/LineLength:
Enabled: false
Metrics/MethodLength:
Max: 43
Max: 45
Metrics/PerceivedComplexity:
Max: 16
Max: 20
Metrics/CyclomaticComplexity:
Max: 15
Max: 19
Metrics/ParameterLists:
Enabled: false
Naming/FileName:
Expand Down
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ gemspec

# Use the opentelemetry-api gem from source
gem 'ddtrace', '~> 0.37'
gem 'opentelemetry-api', '~> 0.5'
gem 'opentelemetry-sdk', '~> 0.5'
gem 'opentelemetry-api', '~> 0.10.0'
gem 'opentelemetry-sdk', '~> 0.10.0'
5 changes: 0 additions & 5 deletions lib/opentelemetry/exporters/datadog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2020 Datadog, Inc.

# require_relative './datadog/exporter.rb'
# require_relative './datadog/version.rb'
# require_relative './datadog/datadog_span_processor.rb'
# require_relative './datadog/propagator.rb'
# require_relative './datadog_probability_sampler'
require 'opentelemetry/exporters/datadog/exporter'
require 'opentelemetry/exporters/datadog/version'
require 'opentelemetry/exporters/datadog/datadog_span_processor'
Expand Down
35 changes: 18 additions & 17 deletions lib/opentelemetry/exporters/datadog/datadog_probability_sampler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,37 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2020 Datadog, Inc.

require 'opentelemetry/sdk/trace/samplers/probability_sampler'
require 'opentelemetry/sdk/trace/samplers/trace_id_ratio_based'
require 'opentelemetry/sdk/trace/samplers/decision'
require 'opentelemetry/sdk/trace/samplers/result'

module OpenTelemetry
module Exporters
module Datadog
# Implements sampling based on a probability but records all spans regardless.
class DatadogProbabilitySampler < OpenTelemetry::SDK::Trace::Samplers::ProbabilitySampler
RECORD_AND_SAMPLED = OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLED)
RECORD = OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD)
class DatadogProbabilitySampler
attr_reader :description

private_constant(:RECORD_AND_SAMPLED, :RECORD)
def initialize(probability)
@probability = probability
@id_upper_bound = (probability * (2**64 - 1)).ceil
@description = format('TraceIdRatioBased{%.6f}', probability)
end

def sample?(trace_id)
@probability == 1.0 || trace_id[8, 8].unpack1('Q>') < @id_upper_bound
end

# @api private
#
# See {Samplers}.
def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:)
# Ignored for sampling decision: links, name, kind, attributes.

if sample?(trace_id, parent_context)
RECORD_AND_SAMPLED
tracestate = OpenTelemetry::Trace.current_span(parent_context).context.tracestate
if sample?(trace_id)
OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_AND_SAMPLE, tracestate: tracestate)
else
RECORD
OpenTelemetry::SDK::Trace::Samplers::Result.new(decision: OpenTelemetry::SDK::Trace::Samplers::Decision::RECORD_ONLY, tracestate: tracestate)
end
end

Expand All @@ -40,16 +47,10 @@ def should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:
def self.default_with_probability(probability = 1.0)
raise ArgumentError, 'probability must be in range [0.0, 1.0]' unless (0.0..1.0).include?(probability)

new(probability,
ignore_parent: false,
apply_to_remote_parent: :root_spans_and_remote_parent,
apply_to_all_spans: :root_spans_and_remote_parent)
new(probability)
end

DEFAULT = new(1.0,
ignore_parent: false,
apply_to_remote_parent: :root_spans_and_remote_parent,
apply_to_all_spans: :root_spans_and_remote_parent)
DEFAULT = new(1.0)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/opentelemetry/exporters/datadog/datadog_span_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def initialize(exporter:,

# datadog trace-agent endpoint requires a complete trace to be sent
# threadsafe may block on lock
def on_start(span)
def on_start(span, _parent_context)
context = span.context
trace_id = context.trace_id

Expand Down Expand Up @@ -135,7 +135,7 @@ def force_flush

# shuts the consumer thread down and flushes the current accumulated buffer
# will block until the thread is finished
def shutdown
def shutdown(timeout: nil)
lock do
@keep_running = false
@condition.signal
Expand Down
17 changes: 4 additions & 13 deletions lib/opentelemetry/exporters/datadog/exporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

require 'uri'
require 'ddtrace'
require 'opentelemetry/sdk'
require 'opentelemetry'
require 'opentelemetry/exporters/datadog/exporter/span_encoder'
# require_relative './exporter/span_encoder.rb'

module OpenTelemetry
module Exporters
Expand All @@ -22,16 +21,8 @@ module Datadog
class Exporter
DEFAULT_AGENT_URL = 'http://localhost:8126'
DEFAULT_SERVICE_NAME = 'my_service'
SUCCESS = begin
OpenTelemetry::SDK::Trace::Export::SUCCESS
rescue NameError
0
end
FAILURE = begin
OpenTelemetry::SDK::Trace::Export::FAILURE
rescue NameError
1
end
SUCCESS = 0
FAILURE = 1
private_constant(:SUCCESS, :FAILURE)

def initialize(service_name: nil, agent_url: nil, env: nil, version: nil, tags: nil)
Expand Down Expand Up @@ -68,7 +59,7 @@ def export(spans)

# Called when {TracerProvider#shutdown} is called, if this exporter is
# registered to a {TracerProvider} object.
def shutdown
def shutdown(timeout: nil)
@shutdown = true
end

Expand Down
49 changes: 41 additions & 8 deletions lib/opentelemetry/exporters/datadog/exporter/span_encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class SpanEncoder
ORIGIN_REGEX = /#{DD_ORIGIN}\=(.*?)($|,)/.freeze
PROBABILITY_REGEX = /\d[.]\d{1,6}/.freeze
TRUNCATION_HELPER = ::Datadog::DistributedTracing::Headers::Headers.new({})
RESOURCE_SERVICE_TAG = 'service.name'
RESOURCE_VERSION_TAG = 'service.version'
RESOURCE_ENVIRONMENT_TAG = 'deployment.environment'

INSTRUMENTATION_SPAN_TYPES = {
'OpenTelemetry::Instrumentation::Ethon' => ::Datadog::Ext::HTTP::TYPE_OUTBOUND,
Expand All @@ -56,20 +59,23 @@ def translate_to_datadog(otel_spans, service, env = nil, version = nil, tags = n
span_type = get_span_type(span)
span_name = get_span_name(span)

# this excludes service.name, which we get seperately
span_resource_tags, resource_service_name, resource_environment_name, resource_version_name = get_resource_tags_and_service(span)

default_tags_including_resource = default_tags.merge(span_resource_tags)
datadog_span = ::Datadog::Span.new(nil, span_name,
service: service,
service: resource_service_name || service,
trace_id: trace_id,
parent_id: parent_id,
resource: get_resource(span),
span_type: span_type)

# span_id is autogenerated so have to override
datadog_span.span_id = span_id
datadog_span.start_time = span.start_timestamp
datadog_span.end_time = span.end_timestamp

# set span.error, span tag error.msg/error.type
if span.status && span.status.canonical_code != OpenTelemetry::Trace::Status::OK
if span.status && !span.status.ok?
datadog_span.status = 1

exception_type, exception_msg, exception_stack = get_exception_info(span)
Expand All @@ -82,14 +88,14 @@ def translate_to_datadog(otel_spans, service, env = nil, version = nil, tags = n
end

# set default tags
default_tags&.keys&.each do |attribute|
datadog_span.set_tag(attribute, span.attributes[attribute])
default_tags_including_resource&.keys&.each do |attribute|
datadog_span.set_tag(attribute, default_tags_including_resource[attribute])
end

origin = get_origin_string(span)
datadog_span.set_tag(DD_ORIGIN, origin) if origin && parent_id.zero?
datadog_span.set_tag(VERSION_KEY, version) if version && parent_id.zero?
datadog_span.set_tag(ENV_KEY, env) if env
datadog_span.set_tag(VERSION_KEY, resource_version_name || version) if (resource_version_name || version) && parent_id.zero?
datadog_span.set_tag(ENV_KEY, resource_environment_name || env) if resource_version_name || env

# set tags - takes precedence over env vars
span.attributes&.keys&.each do |attribute|
Expand All @@ -103,7 +109,6 @@ def translate_to_datadog(otel_spans, service, env = nil, version = nil, tags = n
elsif sampling_rate
datadog_span.set_metric(SAMPLE_RATE_METRIC_KEY, sampling_rate)
end

datadog_spans << datadog_span
end

Expand Down Expand Up @@ -183,6 +188,34 @@ def get_span_name(span)
span.name
end

def get_resource_tags_and_service(span)
resource_tags = {}
service_name = nil
environment_name = nil
version_name = nil
# this is open to change in new versions so being extra defensive here
return resource_tags unless (resource_attributes = begin
span.resource.attribute_enumerator.to_h
rescue StandardError
nil
end)

# grab service name seperately since it has significance
resource_attributes.each do |rattribute_key, rattribute_value|
if rattribute_key == RESOURCE_SERVICE_TAG
service_name = rattribute_value
elsif rattribute_key == RESOURCE_ENVIRONMENT_TAG
environment_name = rattribute_value
elsif rattribute_key == RESOURCE_VERSION_TAG
version_name = rattribute_value
else
resource_tags[rattribute_key] = rattribute_value
end
end

[resource_tags, service_name, environment_name, version_name]
end

def get_origin_string(span)
tracestate = begin
span.tracestate
Expand Down
14 changes: 7 additions & 7 deletions lib/opentelemetry/exporters/datadog/propagator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
# SPDX-License-Identifier: Apache-2.0

require 'opentelemetry/sdk'
require 'opentelemetry'
require 'opentelemetry/context/propagation'
require 'ddtrace/distributed_tracing/headers/headers'
require 'ddtrace/distributed_tracing/headers/helpers'
Expand All @@ -24,13 +24,13 @@ class Propagator
DD_ORIGIN = '_dd_origin'
ORIGIN_REGEX = /#{DD_ORIGIN}\=(.*?)($|,)/.freeze
DEFAULT_INJECTORS = [
OpenTelemetry::Trace::Propagation::TraceContext.text_injector,
OpenTelemetry::CorrelationContext::Propagation.text_injector
OpenTelemetry::Trace::Propagation::TraceContext.text_map_injector,
OpenTelemetry::Baggage::Propagation.text_map_injector
].freeze

DEFAULT_EXTRACTORS = [
OpenTelemetry::Trace::Propagation::TraceContext.rack_extractor,
OpenTelemetry::CorrelationContext::Propagation.rack_extractor
OpenTelemetry::Baggage::Propagation.rack_extractor
].freeze

# Returns a new Propagator
Expand Down Expand Up @@ -92,7 +92,8 @@ def extract(carrier, context, &getter)
tracestate: tracestate,
remote: true)

context.set_value(Trace::Propagation::ContextKeys.extracted_span_context_key, span_context)
span = Trace::Span.new(span_context: span_context)
Trace.context_with_span(span, parent_context: context)
rescue StandardError => e
OpenTelemetry.logger.debug("error extracting datadog propagation, #{e.message}")
context
Expand All @@ -116,8 +117,7 @@ def rack_helper(header)
end

def span_context_from(context)
context[Trace::Propagation::ContextKeys.current_span_key]&.context ||
context[Trace::Propagation::ContextKeys.extracted_span_context_key]
OpenTelemetry::Trace.current_span(context).context
end

def get_origin_string(tracestate)
Expand Down
4 changes: 2 additions & 2 deletions opentelemetry-exporters-datadog.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 2.5.0'

spec.add_dependency 'ddtrace', '~> 0.37'
spec.add_dependency 'opentelemetry-api', '~> 0.5'
spec.add_dependency 'opentelemetry-sdk', '~> 0.5'
spec.add_dependency 'opentelemetry-api', '~> 0.10.0'
spec.add_dependency 'opentelemetry-sdk', '~> 0.10.0'

spec.add_development_dependency 'bundler', '>= 1.17'
spec.add_development_dependency 'faraday', '~> 0.13'
Expand Down
Loading

0 comments on commit 56b6503

Please sign in to comment.