-
Notifications
You must be signed in to change notification settings - Fork 375
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
Refactor:Move distributed propagation to Contrib #2352
Changes from 55 commits
76dfe37
135e58e
b621972
243050e
0166025
af7c159
a5c5513
7f9e59e
6d2d00f
c918273
fe38b24
72bc3a6
f8ecf3a
f05e27c
6eecfbc
13ef267
cedfe2b
5650505
8f86955
2830b3a
e261e8e
62fcea8
17bfa34
c81fd81
e877d99
998ffb3
70dd590
1374774
076a784
7c394e0
6462cf8
b4c8239
52da1c1
bb60a3a
df12297
98bf97f
998f35b
61c3b9a
bb08ca8
5efac8a
35dddbc
b39ce1c
658f497
1bbeb5e
bf39755
6c69871
0975630
23f75b5
11d3103
ebf82b8
51ea9f4
8af6f31
2150c88
129d823
9df6d9d
573eaf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
# typed: true | ||
|
||
require_relative '../../../distributed/fetcher' | ||
|
||
module Datadog | ||
module Tracing | ||
module Contrib | ||
module GRPC | ||
module Distributed | ||
# Retrieves values from the gRPC metadata. | ||
# One metadata key can be associated with multiple values. | ||
# | ||
# @see https://github.com/grpc/grpc-go/blob/56ac86fa0f3940cb79946ce2c6e56f7ee7ecae84/Documentation/grpc-metadata.md#constructing-metadata | ||
class Fetcher < Tracing::Distributed::Fetcher | ||
def [](key) | ||
# Metadata values are normally integrals but can also be | ||
# arrays when multiple values are associated with the same key. | ||
value = super(key) | ||
value.is_a?(::Array) ? value[0] : value | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# frozen_string_literal: true | ||
# typed: true | ||
|
||
require_relative 'fetcher' | ||
require_relative '../../../distributed/b3' | ||
require_relative '../../../distributed/b3_single' | ||
require_relative '../../../distributed/datadog' | ||
require_relative '../../../distributed/propagation' | ||
|
||
module Datadog | ||
module Tracing | ||
module Contrib | ||
module GRPC | ||
module Distributed | ||
# Extracts and injects propagation through gRPC metadata. | ||
# @see https://github.com/grpc/grpc-go/blob/v1.50.1/Documentation/grpc-metadata.md | ||
class Propagation < Tracing::Distributed::Propagation | ||
def initialize | ||
super( | ||
propagation_styles: { | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 => | ||
Tracing::Distributed::B3.new(fetcher: Fetcher), | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER => | ||
Tracing::Distributed::B3Single.new(fetcher: Fetcher), | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG => | ||
Tracing::Distributed::Datadog.new(fetcher: Fetcher) | ||
}) | ||
end | ||
|
||
# DEV: Singleton kept until a larger refactor is performed. | ||
# DEV: See {Datadog::Tracing::Distributed::Propagation#initialize} for more information. | ||
INSTANCE = Propagation.new | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,8 +19,6 @@ def target_version | |
end | ||
|
||
def patch | ||
require_relative '../../propagation/grpc' | ||
require_relative 'datadog_interceptor' | ||
Comment on lines
-22
to
-23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were just unnecessary and actually the responsibility of |
||
require_relative 'intercept_with_datadog' | ||
|
||
prepend_interceptor | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# frozen_string_literal: false | ||
# typed: false | ||
|
||
require_relative '../../../distributed/fetcher' | ||
|
||
module Datadog | ||
module Tracing | ||
module Contrib | ||
module HTTP | ||
module Distributed | ||
# Retrieves Rack formatted headers from HTTP headers. | ||
class Fetcher < Tracing::Distributed::Fetcher | ||
# TODO: Don't assume Rack format. | ||
# Make distributed tracing headers apathetic. | ||
# DEV: Should we try to parse both verbatim an Rack-formatted headers, | ||
# DEV: given Rack-formatted is the most common format in Ruby? | ||
def [](name) | ||
rack_header = "HTTP-#{name}" | ||
rack_header.upcase! | ||
rack_header.tr!('-'.freeze, '_'.freeze) | ||
|
||
hdr = super(rack_header) | ||
|
||
# Only return the value if it is not an empty string | ||
hdr if hdr != '' | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# frozen_string_literal: true | ||
# typed: true | ||
|
||
require_relative 'fetcher' | ||
require_relative '../../../distributed/propagation' | ||
require_relative '../../../distributed/b3' | ||
require_relative '../../../distributed/b3_single' | ||
require_relative '../../../distributed/datadog' | ||
|
||
module Datadog | ||
module Tracing | ||
module Contrib | ||
module HTTP | ||
module Distributed | ||
# Extracts and injects propagation through HTTP headers. | ||
class Propagation < Tracing::Distributed::Propagation | ||
def initialize | ||
Comment on lines
+10
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this new class is a detour and not the desired outcome from where we are right now. Specifically, in BUT here, we're breaking the old (existing) API and creating a new API, but this new API still doesn't do the "correct thing" for configuration. This suggests to me that to do the "correct thing", we're going to need to break the API a third time. So I'm left wondering -- is this detour worth it? Would it be worth considering not creating this class (and the grpc variant) until we're ready to create it with an API that receives the configuration as input as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't have time to do the whole thing, which involves touching The changes that are needed in the future, to perform that correct dependency injection, will work directly with these classes in this PR: they are now classes, not singletons, and are in their correct namespace. It will be much less messy with these changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll admit that I'm not convinced these "midway points" are useful, but I'll trust you this one :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I had to break down the work somehow, given I already put more time that I budgeted for for this refactor, so I chose a stopping point that allowed me move forward with adding new propagators without pulling hairs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mega fair! Hope you didn't take the above as criticism of you or this change, it's more of a "I suspect this detour may need to be slightly redone and so I would prefer omitting it, but I don't have any data/proof to match my suspicion and this is reasonable as well so since we need to make a decision, I trust yours." |
||
super( | ||
propagation_styles: { | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 => | ||
Tracing::Distributed::B3.new(fetcher: Fetcher), | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER => | ||
Tracing::Distributed::B3Single.new(fetcher: Fetcher), | ||
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG => | ||
Tracing::Distributed::Datadog.new(fetcher: Fetcher) | ||
}) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# frozen_string_literal: true | ||
# typed: true | ||
|
||
require_relative 'helpers' | ||
require_relative '../trace_digest' | ||
|
||
module Datadog | ||
module Tracing | ||
module Distributed | ||
# B3-style trace propagation. | ||
# @see https://github.com/openzipkin/b3-propagation#multiple-headers | ||
class B3 | ||
B3_TRACE_ID_KEY = 'x-b3-traceid' | ||
B3_SPAN_ID_KEY = 'x-b3-spanid' | ||
B3_SAMPLED_KEY = 'x-b3-sampled' | ||
|
||
def initialize( | ||
marcotc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fetcher:, | ||
trace_id_key: B3_TRACE_ID_KEY, | ||
span_id_key: B3_SPAN_ID_KEY, | ||
sampled_key: B3_SAMPLED_KEY | ||
) | ||
@trace_id_key = trace_id_key | ||
@span_id_key = span_id_key | ||
@sampled_key = sampled_key | ||
@fetcher = fetcher | ||
end | ||
|
||
def inject!(digest, data = {}) | ||
return if digest.nil? | ||
|
||
# DEV: We need these to be hex encoded | ||
data[@trace_id_key] = digest.trace_id.to_s(16) | ||
data[@span_id_key] = digest.span_id.to_s(16) | ||
|
||
if digest.trace_sampling_priority | ||
sampling_priority = Helpers.clamp_sampling_priority( | ||
digest.trace_sampling_priority | ||
) | ||
data[@sampled_key] = sampling_priority.to_s | ||
end | ||
|
||
data | ||
end | ||
|
||
def extract(data) | ||
# DEV: B3 doesn't have "origin" | ||
fetcher = @fetcher.new(data) | ||
trace_id = fetcher.id(@trace_id_key, base: 16) | ||
span_id = fetcher.id(@span_id_key, base: 16) | ||
# We don't need to try and convert sampled since B3 supports 0/1 (AUTO_REJECT/AUTO_KEEP) | ||
sampling_priority = fetcher.number(@sampled_key) | ||
|
||
# Return early if this propagation is not valid | ||
return unless trace_id && span_id | ||
|
||
TraceDigest.new( | ||
trace_id: trace_id, | ||
span_id: span_id, | ||
trace_sampling_priority: sampling_priority | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I slightly wonder if we should take the next step and also kill the
GRPC::Distributed::Propagation
subclass, since it's only a shortcut for callingTracing::Distributed::Propagation
with the defaults :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is complex enough that it should be encapsulated:
It's the one place where we wire the protocol-specific logic.
I'd like to request permission to leave it as it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need mine! 😅
These design decisions are trade-offs, so definitely I wouldn't claim there's a right and a wrong. So I think it's very fair if you don't think it's worth the change or prefer the approach you've already done :)