http_instrumentation 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/VERSION +1 -1
- data/lib/http_instrumentation/instrumentation/curb_hook.rb +9 -3
- data/lib/http_instrumentation/instrumentation/ethon_hook.rb +32 -12
- data/lib/http_instrumentation/instrumentation/excon_hook.rb +9 -3
- data/lib/http_instrumentation/instrumentation/http_hook.rb +9 -3
- data/lib/http_instrumentation/instrumentation/httpclient_hook.rb +9 -3
- data/lib/http_instrumentation/instrumentation/httpx_hook.rb +8 -2
- data/lib/http_instrumentation/instrumentation/net_http_hook.rb +16 -4
- data/lib/http_instrumentation/instrumentation/patron_hook.rb +9 -3
- data/lib/http_instrumentation/instrumentation/typhoeus_hook.rb +22 -6
- data/lib/http_instrumentation/instrumentation.rb +47 -3
- data/lib/http_instrumentation.rb +13 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1457b4d97046d8c0a41e99aa0825386e3540eb67ac5603fb0ecc80e2fca77e92
|
4
|
+
data.tar.gz: 78b242f2f2821f22d8abddd754e641a271232da63e8218b2492ecd0907e43eca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aab6fde374e4f00c40509e32950fc8d3ab3b18666a8c5be593f1fc2d58a1907ab19ea1ba2a309d1728a6c3611aaeae54f8873a2e25b7450a55dbe9952358811
|
7
|
+
data.tar.gz: a22576c8eb6253c18c3705211c09764df2c1221c65797fcb944c8f3a62f31c7b7f5f6aec1abe607393c98ebd9bc90792662e609673a1f4bdea86f3b33030e132
|
data/CHANGELOG.md
CHANGED
@@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
-
## 1.0.
|
7
|
+
## 1.0.1
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
- Added detection for other gems that may be instrumenting these same libraries and ensuring that the method of injecting the instrumentation call is compatible. This fixes issues caused by the fundamental incompatibility in Ruby between `alias_method` and `prepend` on the same method. Aliasing is now the default method for injection since this is the most compatible. However if another library has already prepended behavior on a method, then `prepend` will be used instead.
|
11
|
+
- `HTTPInstrumentation.client` properly returns the block return value if it was called with a block.
|
12
|
+
|
13
|
+
## 1.0.0
|
8
14
|
|
9
15
|
### Added
|
10
16
|
- Initial release.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.1
|
@@ -11,17 +11,23 @@ module HTTPInstrumentation
|
|
11
11
|
module CurbHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Curl::Easy, self) if defined?(::Curl::Easy)
|
14
|
+
Instrumentation.instrument!(::Curl::Easy, self, :http) if defined?(::Curl::Easy)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::Curl::Easy) && ::Curl::Easy.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
|
-
def http(method, *)
|
24
|
+
def http(method, *args)
|
23
25
|
HTTPInstrumentation.instrument("curb") do |payload|
|
24
|
-
retval =
|
26
|
+
retval = if HTTPInstrumentation::Instrumentation::CurbHook.aliased
|
27
|
+
http_without_http_instrumentation(method, *args)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
25
31
|
|
26
32
|
payload[:http_method] = method
|
27
33
|
begin
|
@@ -11,8 +11,8 @@ module HTTPInstrumentation
|
|
11
11
|
module EthonHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Ethon::Easy, Easy) if defined?(::Ethon::Easy)
|
15
|
-
Instrumentation.instrument!(::Ethon::Multi, Multi) if defined?(::Ethon::Multi)
|
14
|
+
Instrumentation.instrument!(::Ethon::Easy, Easy, [:http_request, :perform]) if defined?(::Ethon::Easy)
|
15
|
+
Instrumentation.instrument!(::Ethon::Multi, Multi, :perform) if defined?(::Ethon::Multi)
|
16
16
|
end
|
17
17
|
|
18
18
|
def installed?
|
@@ -24,31 +24,51 @@ module HTTPInstrumentation
|
|
24
24
|
end
|
25
25
|
|
26
26
|
module Multi
|
27
|
-
|
27
|
+
class << self
|
28
|
+
attr_accessor :aliased
|
29
|
+
end
|
30
|
+
|
31
|
+
def perform(*args)
|
28
32
|
HTTPInstrumentation.instrument("ethon") do |payload|
|
29
33
|
begin
|
30
34
|
payload[:count] = easy_handles.size
|
31
35
|
rescue
|
32
36
|
end
|
33
37
|
|
34
|
-
|
38
|
+
if HTTPInstrumentation::Instrumentation::EthonHook::Multi.aliased
|
39
|
+
perform_without_http_instrumentation(*args)
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
35
43
|
end
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
39
47
|
module Easy
|
40
|
-
|
41
|
-
|
42
|
-
@http_url = url
|
43
|
-
super
|
48
|
+
class << self
|
49
|
+
attr_accessor :aliased
|
44
50
|
end
|
45
51
|
|
46
|
-
def
|
52
|
+
def http_request(url, action_name, *args)
|
53
|
+
@http_instrumentation_method = action_name
|
54
|
+
@http_instrumentation_url = url
|
55
|
+
if HTTPInstrumentation::Instrumentation::EthonHook::Easy.aliased
|
56
|
+
http_request_without_http_instrumentation(url, action_name, *args)
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def perform(*args)
|
47
63
|
HTTPInstrumentation.instrument("ethon") do |payload|
|
48
|
-
retval =
|
64
|
+
retval = if HTTPInstrumentation::Instrumentation::EthonHook::Easy.aliased
|
65
|
+
perform_without_http_instrumentation(*args)
|
66
|
+
else
|
67
|
+
super
|
68
|
+
end
|
49
69
|
|
50
|
-
payload[:http_method] = @
|
51
|
-
payload[:url] = @
|
70
|
+
payload[:http_method] = @http_instrumentation_method
|
71
|
+
payload[:url] = @http_instrumentation_url
|
52
72
|
begin
|
53
73
|
payload[:status_code] = response_code
|
54
74
|
rescue
|
@@ -11,17 +11,23 @@ module HTTPInstrumentation
|
|
11
11
|
module ExconHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Excon::Connection, self) if defined?(::Excon::Connection)
|
14
|
+
Instrumentation.instrument!(::Excon::Connection, self, :request) if defined?(::Excon::Connection)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::Excon::Connection) && ::Excon::Connection.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
|
-
def request(params = {}
|
24
|
+
def request(params = {})
|
23
25
|
HTTPInstrumentation.instrument("excon") do |payload|
|
24
|
-
response =
|
26
|
+
response = if HTTPInstrumentation::Instrumentation::ExconHook.aliased
|
27
|
+
request_without_http_instrumentation(params)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
25
31
|
|
26
32
|
begin
|
27
33
|
info = params
|
@@ -11,17 +11,23 @@ module HTTPInstrumentation
|
|
11
11
|
module HTTPHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::HTTP::Client, self) if defined?(::HTTP::Client)
|
14
|
+
Instrumentation.instrument!(::HTTP::Client, self, :perform) if defined?(::HTTP::Client)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::HTTP::Client) && ::HTTP::Client.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
|
-
def perform(request, *)
|
24
|
+
def perform(request, *args)
|
23
25
|
HTTPInstrumentation.instrument("http") do |payload|
|
24
|
-
response =
|
26
|
+
response = if HTTPInstrumentation::Instrumentation::HTTPHook.aliased
|
27
|
+
perform_without_http_instrumentation(request, *args)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
25
31
|
|
26
32
|
begin
|
27
33
|
payload[:http_method] = request.verb
|
@@ -11,17 +11,23 @@ module HTTPInstrumentation
|
|
11
11
|
# This module is responsible for instrumenting the httpclient gem.
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::HTTPClient, self) if defined?(::HTTPClient)
|
14
|
+
Instrumentation.instrument!(::HTTPClient, self, :do_get_block) if defined?(::HTTPClient)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::HTTPClient) && ::HTTPClient.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
|
-
def do_get_block(request, *)
|
24
|
+
def do_get_block(request, *args)
|
23
25
|
HTTPInstrumentation.instrument("httpclient") do |payload|
|
24
|
-
response =
|
26
|
+
response = if HTTPInstrumentation::Instrumentation::HTTPClientHook.aliased
|
27
|
+
do_get_block_without_http_instrumentation(request, *args)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
25
31
|
|
26
32
|
begin
|
27
33
|
payload[:http_method] = request.header.request_method
|
@@ -11,19 +11,25 @@ module HTTPInstrumentation
|
|
11
11
|
module HTTPXHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::HTTPX::Session, self) if defined?(::HTTPX::Session)
|
14
|
+
Instrumentation.instrument!(::HTTPX::Session, self, :send_requests) if defined?(::HTTPX::Session)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::HTTPX::Session) && ::HTTPX::Session.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
23
25
|
|
24
26
|
def send_requests(*requests)
|
25
27
|
HTTPInstrumentation.instrument("httpx") do |payload|
|
26
|
-
responses =
|
28
|
+
responses = if HTTPInstrumentation::Instrumentation::HTTPXHook.aliased
|
29
|
+
send_requests_without_http_instrumentation(*requests)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
27
33
|
|
28
34
|
if requests.size == 1
|
29
35
|
begin
|
@@ -11,19 +11,31 @@ module HTTPInstrumentation
|
|
11
11
|
module NetHTTPHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Net::HTTP, self) if defined?(::Net::HTTP)
|
14
|
+
Instrumentation.instrument!(::Net::HTTP, self, :request) if defined?(::Net::HTTP)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::Net::HTTP) && ::Net::HTTP.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
|
-
def request(req, *)
|
23
|
-
|
24
|
+
def request(req, *args, &block)
|
25
|
+
unless started?
|
26
|
+
if HTTPInstrumentation::Instrumentation::NetHTTPHook.aliased
|
27
|
+
return request_without_http_instrumentation(req, *args, &block)
|
28
|
+
else
|
29
|
+
return super
|
30
|
+
end
|
31
|
+
end
|
24
32
|
|
25
33
|
HTTPInstrumentation.instrument("net/http") do |payload|
|
26
|
-
response =
|
34
|
+
response = if HTTPInstrumentation::Instrumentation::NetHTTPHook.aliased
|
35
|
+
request_without_http_instrumentation(req, *args, &block)
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
27
39
|
|
28
40
|
default_port = (use_ssl? ? 443 : 80)
|
29
41
|
scheme = (use_ssl? ? "https" : "http")
|
@@ -11,19 +11,25 @@ module HTTPInstrumentation
|
|
11
11
|
module PatronHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Patron::Session, self) if defined?(::Patron::Session)
|
14
|
+
Instrumentation.instrument!(::Patron::Session, self, :request) if defined?(::Patron::Session)
|
15
15
|
end
|
16
16
|
|
17
17
|
def installed?
|
18
18
|
!!(defined?(::Patron::Session) && ::Patron::Session.include?(self))
|
19
19
|
end
|
20
|
+
|
21
|
+
attr_accessor :aliased
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
23
25
|
|
24
|
-
def request(action, url, *)
|
26
|
+
def request(action, url, *args)
|
25
27
|
HTTPInstrumentation.instrument("patron") do |payload|
|
26
|
-
response =
|
28
|
+
response = if HTTPInstrumentation::Instrumentation::PatronHook.aliased
|
29
|
+
request_without_http_instrumentation(action, url, *args)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
27
33
|
|
28
34
|
payload[:http_method] = action
|
29
35
|
payload[:url] = url
|
@@ -11,8 +11,8 @@ module HTTPInstrumentation
|
|
11
11
|
module TyphoeusHook
|
12
12
|
class << self
|
13
13
|
def instrument!
|
14
|
-
Instrumentation.instrument!(::Typhoeus::Request, Easy) if defined?(::Typhoeus::Request)
|
15
|
-
Instrumentation.instrument!(::Typhoeus::Hydra, Multi) if defined?(::Typhoeus::Hydra)
|
14
|
+
Instrumentation.instrument!(::Typhoeus::Request, Easy, :run) if defined?(::Typhoeus::Request)
|
15
|
+
Instrumentation.instrument!(::Typhoeus::Hydra, Multi, :run) if defined?(::Typhoeus::Hydra)
|
16
16
|
end
|
17
17
|
|
18
18
|
def installed?
|
@@ -24,22 +24,38 @@ module HTTPInstrumentation
|
|
24
24
|
end
|
25
25
|
|
26
26
|
module Multi
|
27
|
-
|
27
|
+
class << self
|
28
|
+
attr_accessor :aliased
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(*args)
|
28
32
|
HTTPInstrumentation.instrument("typhoeus") do |payload|
|
29
33
|
begin
|
30
34
|
payload[:count] = queued_requests.size
|
31
35
|
rescue
|
32
36
|
end
|
33
37
|
|
34
|
-
|
38
|
+
if HTTPInstrumentation::Instrumentation::TyphoeusHook::Multi.aliased
|
39
|
+
run_without_http_instrumentation(*args)
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
35
43
|
end
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
39
47
|
module Easy
|
40
|
-
|
48
|
+
class << self
|
49
|
+
attr_accessor :aliased
|
50
|
+
end
|
51
|
+
|
52
|
+
def run(*args)
|
41
53
|
HTTPInstrumentation.instrument("typhoeus") do |payload|
|
42
|
-
retval =
|
54
|
+
retval = if HTTPInstrumentation::Instrumentation::TyphoeusHook::Easy.aliased
|
55
|
+
run_without_http_instrumentation(*args)
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
43
59
|
|
44
60
|
begin
|
45
61
|
payload[:http_method] = options[:method]
|
@@ -13,9 +13,53 @@ require_relative "instrumentation/typhoeus_hook"
|
|
13
13
|
module HTTPInstrumentation
|
14
14
|
module Instrumentation
|
15
15
|
class << self
|
16
|
-
# Helper method to
|
17
|
-
|
18
|
-
|
16
|
+
# Helper method to add an instrumentation module to methods on a class. The
|
17
|
+
# methods must be defined in the instrumentation module.
|
18
|
+
#
|
19
|
+
# If the methods have already been prepended on the class, then module will
|
20
|
+
# be prepended to the class. Otherwise, the methods will be aliased and the
|
21
|
+
# module will be included in the class. This is because prepending and aliasing
|
22
|
+
# methods are not compatible with each other and other instrumentation libraries
|
23
|
+
# may have already prepended the methods. Aliasing is the default strategy because
|
24
|
+
# prepending after aliasing will work, but aliasing after prepending will not.
|
25
|
+
def instrument!(klass, instrumentation_module, methods)
|
26
|
+
return if klass.include?(instrumentation_module)
|
27
|
+
|
28
|
+
methods = Array(methods).collect(&:to_sym)
|
29
|
+
|
30
|
+
if HTTPInstrumentation.force_prepend? || methods_prepended?(klass, methods)
|
31
|
+
klass.prepend(instrumentation_module)
|
32
|
+
instrumentation_module.aliased = false
|
33
|
+
else
|
34
|
+
Array(methods).each do |method|
|
35
|
+
instrumentation_module.alias_method("#{method}_with_http_instrumentation", method)
|
36
|
+
end
|
37
|
+
|
38
|
+
klass.include(instrumentation_module)
|
39
|
+
|
40
|
+
Array(methods).each do |method|
|
41
|
+
klass.alias_method("#{method}_without_http_instrumentation", method)
|
42
|
+
klass.alias_method(method, "#{method}_with_http_instrumentation")
|
43
|
+
end
|
44
|
+
|
45
|
+
instrumentation_module.aliased = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def methods_prepended?(klass, methods)
|
52
|
+
prepended = false
|
53
|
+
|
54
|
+
klass.ancestors.each do |mod|
|
55
|
+
next unless mod.is_a?(Module) && !mod.is_a?(Class)
|
56
|
+
|
57
|
+
module_methods = mod.instance_methods(false) + mod.private_instance_methods(false)
|
58
|
+
prepended = (module_methods & methods).any?
|
59
|
+
break if prepended
|
60
|
+
end
|
61
|
+
|
62
|
+
prepended
|
19
63
|
end
|
20
64
|
end
|
21
65
|
end
|
data/lib/http_instrumentation.rb
CHANGED
@@ -60,18 +60,20 @@ module HTTPInstrumentation
|
|
60
60
|
# block. If no block is given, then return the current HTTP client name.
|
61
61
|
#
|
62
62
|
# @param name [String, Symbol, nil] The name of the client to set
|
63
|
-
# @return [String, Symbol, nil]
|
63
|
+
# @return [String, Symbol, nil] If a block is given, then the return value of the block. Otherwise
|
64
|
+
# the current client name.
|
64
65
|
def client(name = nil)
|
65
66
|
save_val = Thread.current[:http_instrumentation_client]
|
66
67
|
if block_given?
|
67
68
|
begin
|
68
|
-
Thread.current[:http_instrumentation_client] = name
|
69
|
+
Thread.current[:http_instrumentation_client] = name&.to_s
|
69
70
|
yield
|
70
71
|
ensure
|
71
72
|
Thread.current[:http_instrumentation_client] = save_val
|
72
73
|
end
|
74
|
+
else
|
75
|
+
save_val
|
73
76
|
end
|
74
|
-
save_val
|
75
77
|
end
|
76
78
|
|
77
79
|
# Returns true if instrumentation is currently silenced.
|
@@ -121,6 +123,14 @@ module HTTPInstrumentation
|
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
126
|
+
# Returns true if instrumentation should always use module prepend rather than method aliasing.
|
127
|
+
# The default is to use method aliasing since that is more compatible with other libraries.
|
128
|
+
# Prepending can be forced by setting the HTTP_INSTRUMENTATION_FORCE_PREPEND environment variable
|
129
|
+
# to "true".
|
130
|
+
def force_prepend?
|
131
|
+
ENV.fetch("HTTP_INSTRUMENTATION_FORCE_PREPEND", nil) == "true"
|
132
|
+
end
|
133
|
+
|
124
134
|
private
|
125
135
|
|
126
136
|
# Turn the given value into a lowercase symbol.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_instrumentation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '0'
|
82
82
|
requirements: []
|
83
|
-
rubygems_version: 3.
|
83
|
+
rubygems_version: 3.2.22
|
84
84
|
signing_key:
|
85
85
|
specification_version: 4
|
86
86
|
summary: ActiveSupoprt instrumentation for a variety of Ruby HTTP client libraries.
|