-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #211 from walterking/excon_instrumentation
Add Excon instrumentation
- Loading branch information
Showing
9 changed files
with
496 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
require 'excon' | ||
require 'ddtrace/ext/http' | ||
require 'ddtrace/ext/net' | ||
require 'ddtrace/ext/distributed' | ||
require 'ddtrace/propagation/http_propagator' | ||
|
||
module Datadog | ||
module Contrib | ||
module Excon | ||
# Middleware implements an excon-middleware for ddtrace instrumentation | ||
class Middleware < ::Excon::Middleware::Base | ||
SPAN_NAME = 'excon.request'.freeze | ||
DEFAULT_ERROR_HANDLER = lambda do |response| | ||
Ext::HTTP::ERROR_RANGE.cover?(response[:status]) | ||
end | ||
|
||
def initialize(stack, options = {}) | ||
super(stack) | ||
@options = Datadog.configuration[:excon].merge(options) | ||
end | ||
|
||
def request_call(datum) | ||
begin | ||
unless datum.key?(:datadog_span) | ||
tracer.trace(SPAN_NAME).tap do |span| | ||
datum[:datadog_span] = span | ||
annotate!(span, datum) | ||
propagate!(span, datum) if distributed_tracing? | ||
end | ||
end | ||
rescue StandardError => e | ||
Datadog::Tracer.log.debug(e.message) | ||
end | ||
|
||
@stack.request_call(datum) | ||
end | ||
|
||
def response_call(datum) | ||
@stack.response_call(datum).tap do |d| | ||
handle_response(d) | ||
end | ||
end | ||
|
||
def error_call(datum) | ||
@stack.error_call(datum).tap do |d| | ||
handle_response(d) | ||
end | ||
end | ||
|
||
# Returns a child class of this trace middleware | ||
# With options given as defaults. | ||
def self.with(options = {}) | ||
Class.new(self) do | ||
@options = options | ||
|
||
# rubocop:disable Style/TrivialAccessors | ||
def self.options | ||
@options | ||
end | ||
|
||
def initialize(stack) | ||
super(stack, self.class.options) | ||
end | ||
end | ||
end | ||
|
||
# Returns a copy of the default stack with the trace middleware injected | ||
def self.around_default_stack | ||
::Excon.defaults[:middlewares].dup.tap do |default_stack| | ||
# If the default stack contains a version of the trace middleware already... | ||
existing_trace_middleware = default_stack.find { |m| m <= Middleware } | ||
default_stack.delete(existing_trace_middleware) if existing_trace_middleware | ||
|
||
# Inject after the ResponseParser middleware | ||
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i | ||
default_stack.insert(response_middleware_index + 1, self) | ||
end | ||
end | ||
|
||
private | ||
|
||
def tracer | ||
@options[:tracer] | ||
end | ||
|
||
def distributed_tracing? | ||
@options[:distributed_tracing] == true && tracer.enabled | ||
end | ||
|
||
def error_handler | ||
@options[:error_handler] || DEFAULT_ERROR_HANDLER | ||
end | ||
|
||
def split_by_domain? | ||
@options[:split_by_domain] == true | ||
end | ||
|
||
def annotate!(span, datum) | ||
span.resource = datum[:method].to_s.upcase | ||
span.service = service_name(datum) | ||
span.span_type = Ext::HTTP::TYPE | ||
span.set_tag(Ext::HTTP::URL, datum[:path]) | ||
span.set_tag(Ext::HTTP::METHOD, datum[:method].to_s.upcase) | ||
span.set_tag(Ext::NET::TARGET_HOST, datum[:host]) | ||
span.set_tag(Ext::NET::TARGET_PORT, datum[:port].to_s) | ||
end | ||
|
||
def handle_response(datum) | ||
if datum.key?(:datadog_span) | ||
datum[:datadog_span].tap do |span| | ||
return span if span.finished? | ||
|
||
if datum.key?(:response) | ||
response = datum[:response] | ||
if error_handler.call(response) | ||
span.set_error(["Error #{response[:status]}", response[:body]]) | ||
end | ||
span.set_tag(Ext::HTTP::STATUS_CODE, response[:status]) | ||
end | ||
span.set_error(datum[:error]) if datum.key?(:error) | ||
span.finish | ||
datum.delete(:datadog_span) | ||
end | ||
end | ||
rescue StandardError => e | ||
Datadog::Tracer.log.debug(e.message) | ||
end | ||
|
||
def propagate!(span, datum) | ||
Datadog::HTTPPropagator.inject!(span.context, datum[:headers]) | ||
end | ||
|
||
def service_name(datum) | ||
# TODO: Change this to implement more sensible multiplexing | ||
split_by_domain? ? datum[:host] : @options[:service_name] | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
require 'ddtrace/ext/app_types' | ||
|
||
module Datadog | ||
module Contrib | ||
module Excon | ||
# Responsible for hooking the instrumentation into Excon | ||
module Patcher | ||
include Base | ||
|
||
DEFAULT_SERVICE = 'excon'.freeze | ||
|
||
register_as :excon | ||
option :tracer, default: Datadog.tracer | ||
option :service_name, default: DEFAULT_SERVICE | ||
option :distributed_tracing, default: false | ||
option :split_by_domain, default: false | ||
option :error_handler, default: nil | ||
|
||
@patched = false | ||
|
||
module_function | ||
|
||
def patch | ||
return @patched if patched? || !compatible? | ||
|
||
require 'ddtrace/contrib/excon/middleware' | ||
|
||
add_middleware | ||
|
||
@patched = true | ||
rescue => e | ||
Tracer.log.error("Unable to apply Excon integration: #{e}") | ||
@patched | ||
end | ||
|
||
def patched? | ||
@patched | ||
end | ||
|
||
def compatible? | ||
defined?(::Excon) | ||
end | ||
|
||
def add_middleware | ||
::Excon.defaults[:middlewares] = Middleware.around_default_stack | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.