-
Notifications
You must be signed in to change notification settings - Fork 369
/
easy_patch.rb
150 lines (129 loc) · 5.1 KB
/
easy_patch.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require 'ddtrace/ext/net'
require 'ddtrace/ext/distributed'
require 'ddtrace/ext/integration'
require 'ddtrace/propagation/http_propagator'
require 'ddtrace/contrib/ethon/ext'
require 'ddtrace/contrib/http_annotation_helper'
module Datadog
module Contrib
module Ethon
# Ethon EasyPatch
module EasyPatch
def self.included(base)
base.send(:prepend, InstanceMethods)
end
# InstanceMethods - implementing instrumentation
# rubocop:disable Metrics/ModuleLength
module InstanceMethods
include Datadog::Contrib::HttpAnnotationHelper
def http_request(url, action_name, options = {})
load_datadog_configuration_for(url)
return super unless tracer_enabled?
# It's tricky to get HTTP method from libcurl
@datadog_method = action_name.to_s.upcase
super
end
def headers=(headers)
# Store headers to call this method again when span is ready
@datadog_original_headers = headers
super
end
def perform
load_datadog_configuration_for(url)
return super unless tracer_enabled?
datadog_before_request
super
end
def complete
return super unless tracer_enabled?
begin
response_options = mirror.options
response_code = (response_options[:response_code] || response_options[:code]).to_i
if response_code.zero?
return_code = response_options[:return_code]
message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
set_span_error_message("Request has failed: #{message}")
else
@datadog_span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response_code)
if Datadog::Ext::HTTP::ERROR_RANGE.cover?(response_code)
set_span_error_message("Request has failed with HTTP error: #{response_code}")
end
end
ensure
@datadog_span.finish
@datadog_span = nil
end
super
end
def reset
super
ensure
@datadog_span = nil
@datadog_method = nil
@datadog_original_headers = nil
@datadog_configuration = nil
end
def datadog_before_request(parent_span: nil)
load_datadog_configuration_for(url)
@datadog_span = datadog_configuration[:tracer].trace(
Ext::SPAN_REQUEST,
service: uri ? service_name(uri.host, datadog_configuration) : datadog_configuration[:service_name],
span_type: Datadog::Ext::HTTP::TYPE_OUTBOUND
)
@datadog_span.parent = parent_span unless parent_span.nil?
datadog_tag_request
if datadog_configuration[:distributed_tracing]
@datadog_original_headers ||= {}
Datadog::HTTPPropagator.inject!(@datadog_span.context, @datadog_original_headers)
self.headers = @datadog_original_headers
end
end
def datadog_span_started?
instance_variable_defined?(:@datadog_span) && !@datadog_span.nil?
end
private
attr_reader :datadog_configuration
def datadog_tag_request
span = @datadog_span
method = 'N/A'
if instance_variable_defined?(:@datadog_method) && !@datadog_method.nil?
method = @datadog_method.to_s
end
span.resource = method
# Tag as an external peer service
span.set_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE, span.service)
# Set analytics sample rate
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
return unless uri
span.set_tag(Datadog::Ext::HTTP::URL, uri.path)
span.set_tag(Datadog::Ext::HTTP::METHOD, method)
span.set_tag(Datadog::Ext::NET::TARGET_HOST, uri.host)
span.set_tag(Datadog::Ext::NET::TARGET_PORT, uri.port)
end
def set_span_error_message(message)
# Sets span error from message, in case there is no exception available
@datadog_span.status = Datadog::Ext::Errors::STATUS
@datadog_span.set_tag(Datadog::Ext::Errors::MSG, message)
end
def uri
URI.parse(url)
# rubocop:disable Lint/HandleExceptions
rescue URI::InvalidURIError
end
def load_datadog_configuration_for(host = :default)
@datadog_configuration = Datadog.configuration[:ethon, host]
end
def tracer_enabled?
datadog_configuration[:tracer].enabled
end
def analytics_enabled?
Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
end
def analytics_sample_rate
datadog_configuration[:analytics_sample_rate]
end
end
end
end
end
end