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

Add otel resource label and service.name handling #8

Merged
merged 23 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e7a6feb
[feature]: add otel span resource labels as dd span tags, wip on serv…
ericmustin Sep 2, 2020
dd5024f
[feature]: add tests for resource tags and service name
ericmustin Sep 3, 2020
f954243
[feature]: update attributes to handle resource naming conventions
ericmustin Sep 18, 2020
66e544d
[fix]: bring up to date with 0.8 and add unified service tagging
ericmustin Nov 29, 2020
453161e
[fix]: update to 0.9 compatability
ericmustin Nov 29, 2020
9c6bbfa
[fix]: dont use common as dependancy
ericmustin Nov 29, 2020
431185f
[fix]: dependancies
ericmustin Nov 29, 2020
c19dcd8
try to get common to load
ericmustin Nov 29, 2020
b74370a
moving up common above gemspec
ericmustin Nov 29, 2020
4781eb6
change dependancy syntax
ericmustin Nov 29, 2020
80da3da
remove gemfile details
ericmustin Nov 29, 2020
0517451
remove versioning details
ericmustin Nov 29, 2020
fcdf229
[fix] try updating gemfile again
ericmustin Nov 29, 2020
c682b0a
[fix] more gemfile updates
ericmustin Nov 29, 2020
052776c
[fix]: remove sdk dependancy
ericmustin Nov 29, 2020
3311c97
try to use common in dev
ericmustin Nov 29, 2020
8c666fa
test adding test gemfile group
ericmustin Nov 29, 2020
a570251
[fix]: try adding common to regular dependancies
ericmustin Nov 30, 2020
c6759ea
[fix]: modify rake task in ci
ericmustin Nov 30, 2020
9b87711
rubocop
ericmustin Nov 30, 2020
3c5fed1
dont include opentelemetry-common explicitly
ericmustin Nov 30, 2020
63c111a
use sdk for sampling
ericmustin Dec 4, 2020
72eb0ef
dont run full index builds on ci
ericmustin Dec 4, 2020
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
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