stackify-ruby-apm 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +38 -0
- data/.ruby-version +1 -0
- data/Gemfile +17 -11
- data/Gemfile.lock +98 -95
- data/Rakefile +7 -5
- data/docker/stackify-ruby +8 -0
- data/docker/stackify-ruby-rvm +10 -0
- data/docker/stackify-ruby-test +28 -0
- data/lib/{stackify → stackify_apm}/agent.rb +42 -33
- data/lib/{stackify → stackify_apm}/config.rb +56 -39
- data/lib/{stackify → stackify_apm}/context.rb +5 -6
- data/lib/{stackify → stackify_apm}/context/request.rb +0 -0
- data/lib/{stackify → stackify_apm}/context/request/socket.rb +0 -0
- data/lib/{stackify → stackify_apm}/context/request/url.rb +2 -6
- data/lib/stackify_apm/context/response.rb +33 -0
- data/lib/{stackify → stackify_apm}/context_builder.rb +2 -5
- data/lib/{stackify → stackify_apm}/error.rb +7 -6
- data/lib/stackify_apm/error/exception.rb +37 -0
- data/lib/stackify_apm/error/log.rb +24 -0
- data/lib/stackify_apm/error_builder.rb +61 -0
- data/lib/stackify_apm/helper/database_helper.rb +27 -0
- data/lib/{stackify → stackify_apm}/instrumenter.rb +12 -19
- data/lib/{stackify → stackify_apm}/internal_error.rb +0 -0
- data/lib/{stackify → stackify_apm}/log.rb +0 -0
- data/lib/{stackify → stackify_apm}/logger/log_device.rb +22 -11
- data/lib/{stackify → stackify_apm}/logger/logger_high_version.rb +1 -6
- data/lib/{stackify → stackify_apm}/logger/logger_lower_version.rb +2 -1
- data/lib/stackify_apm/middleware.rb +70 -0
- data/lib/{stackify → stackify_apm}/naively_hashable.rb +1 -3
- data/lib/{stackify → stackify_apm}/normalizers.rb +3 -2
- data/lib/{stackify → stackify_apm}/normalizers/action_controller.rb +0 -0
- data/lib/{stackify → stackify_apm}/normalizers/action_mailer.rb +0 -0
- data/lib/{stackify → stackify_apm}/normalizers/action_view.rb +0 -0
- data/lib/{stackify → stackify_apm}/normalizers/active_record.rb +3 -25
- data/lib/{stackify → stackify_apm}/railtie.rb +5 -7
- data/lib/{stackify → stackify_apm}/root_info.rb +2 -6
- data/lib/{stackify → stackify_apm}/serializers.rb +3 -2
- data/lib/{stackify → stackify_apm}/serializers/errors.rb +7 -10
- data/lib/{stackify → stackify_apm}/serializers/transactions.rb +11 -18
- data/lib/{stackify → stackify_apm}/span.rb +8 -9
- data/lib/{stackify → stackify_apm}/span/context.rb +3 -1
- data/lib/{stackify → stackify_apm}/spies.rb +3 -2
- data/lib/{stackify → stackify_apm}/spies/action_dispatch.rb +3 -4
- data/lib/stackify_apm/spies/curb.rb +49 -0
- data/lib/stackify_apm/spies/curb/easy.rb +157 -0
- data/lib/stackify_apm/spies/curb/multi.rb +43 -0
- data/lib/{stackify → stackify_apm}/spies/httpclient.rb +10 -8
- data/lib/{stackify → stackify_apm}/spies/httprb.rb +7 -9
- data/lib/{stackify → stackify_apm}/spies/mongo.rb +5 -3
- data/lib/{stackify → stackify_apm}/spies/net_http.rb +4 -5
- data/lib/{stackify → stackify_apm}/spies/redis.rb +19 -18
- data/lib/stackify_apm/spies/sequel.rb +65 -0
- data/lib/{stackify → stackify_apm}/spies/sinatra.rb +7 -10
- data/lib/stackify_apm/spies/sinatra_activerecord/mysql_adapter.rb +201 -0
- data/lib/stackify_apm/spies/sinatra_activerecord/postgresql_adapter.rb +94 -0
- data/lib/stackify_apm/spies/sinatra_activerecord/sqlite_adapter.rb +46 -0
- data/lib/stackify_apm/spies/stackify_logger.rb +60 -0
- data/lib/{stackify → stackify_apm}/spies/tilt.rb +3 -3
- data/lib/stackify_apm/stacktrace.rb +18 -0
- data/lib/stackify_apm/stacktrace/frame.rb +47 -0
- data/lib/{stackify → stackify_apm}/stacktrace_builder.rb +10 -11
- data/lib/{stackify → stackify_apm}/subscriber.rb +20 -14
- data/lib/{stackify → stackify_apm}/trace_logger.rb +10 -16
- data/lib/stackify_apm/transaction.rb +127 -0
- data/lib/{stackify → stackify_apm}/util.rb +3 -1
- data/lib/{stackify → stackify_apm}/util/dig.rb +1 -1
- data/lib/{stackify → stackify_apm}/util/inflector.rb +0 -0
- data/lib/{stackify → stackify_apm}/util/inspector.rb +1 -3
- data/lib/stackify_apm/util/lru_cache.rb +49 -0
- data/lib/stackify_apm/util/trace_log_watcher.rb +37 -0
- data/lib/stackify_apm/version.rb +6 -0
- data/lib/{stackify → stackify_apm}/worker.rb +8 -7
- data/lib/stackify_ruby_apm.rb +18 -15
- data/run-test-docker.sh +50 -0
- data/run-test.sh +1 -3
- data/stackify-ruby-apm.gemspec +14 -11
- metadata +86 -59
- data/lib/stackify/context/response.rb +0 -37
- data/lib/stackify/error/exception.rb +0 -36
- data/lib/stackify/error/log.rb +0 -25
- data/lib/stackify/error_builder.rb +0 -65
- data/lib/stackify/middleware.rb +0 -74
- data/lib/stackify/spies/sinatra_activerecord/mysql_adapter.rb +0 -177
- data/lib/stackify/spies/sinatra_activerecord/postgresql_adapter.rb +0 -96
- data/lib/stackify/spies/sinatra_activerecord/sqlite_adapter.rb +0 -48
- data/lib/stackify/stacktrace.rb +0 -19
- data/lib/stackify/stacktrace/frame.rb +0 -50
- data/lib/stackify/transaction.rb +0 -132
- data/lib/stackify/util/lru_cache.rb +0 -49
- data/lib/stackify/version.rb +0 -4
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Monkey patch for the CurbSpy class for sending & receiving Curb responses.
|
|
4
|
+
#
|
|
5
|
+
module StackifyRubyAPM
|
|
6
|
+
# @api private
|
|
7
|
+
module Spies
|
|
8
|
+
# @api private
|
|
9
|
+
class CurbEasySpy
|
|
10
|
+
attr_accessor :_apm_http_verb
|
|
11
|
+
def install
|
|
12
|
+
Curl::Easy.class_eval do
|
|
13
|
+
singleton_class.send(:alias_method, :perform_without_apm, :perform)
|
|
14
|
+
singleton_class.send(:alias_method, :http_head_without_apm, :http_head)
|
|
15
|
+
singleton_class.send(:alias_method, :http_post_without_apm, :http_post)
|
|
16
|
+
singleton_class.send(:alias_method, :http_put_without_apm, :http_put)
|
|
17
|
+
singleton_class.send(:alias_method, :http_get_without_apm, :http_get)
|
|
18
|
+
singleton_class.send(:alias_method, :http_delete_without_apm, :http_delete)
|
|
19
|
+
def self.perform(*args)
|
|
20
|
+
req = nil
|
|
21
|
+
return perform_without_apm(*args) unless StackifyRubyAPM.current_transaction
|
|
22
|
+
# Data configuration
|
|
23
|
+
@_apm_http_verb ||= :GET
|
|
24
|
+
method = @_apm_http_verb
|
|
25
|
+
uri = args[0].strip
|
|
26
|
+
name = "#{method} #{uri}"
|
|
27
|
+
type = "ext.Curb.Easy.#{method}"
|
|
28
|
+
# Submits HTTP request
|
|
29
|
+
#
|
|
30
|
+
req = perform_without_apm(*args)
|
|
31
|
+
# Builds span context
|
|
32
|
+
#
|
|
33
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
|
34
|
+
ctx = Span::Context.new(
|
|
35
|
+
CATEGORY: 'Web External',
|
|
36
|
+
SUBCATEGORY: 'Execute',
|
|
37
|
+
URL: uri,
|
|
38
|
+
STATUS: status_code,
|
|
39
|
+
METHOD: method
|
|
40
|
+
)
|
|
41
|
+
# Creates new span from HTTP result
|
|
42
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
43
|
+
req
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.http_post(*args)
|
|
48
|
+
req = nil
|
|
49
|
+
return http_post_without_apm(*args) unless StackifyRubyAPM.current_transaction
|
|
50
|
+
# Data configuration
|
|
51
|
+
#
|
|
52
|
+
@_apm_http_verb = :POST
|
|
53
|
+
method = @_apm_http_verb
|
|
54
|
+
uri = args[0].strip
|
|
55
|
+
name = "#{method} #{uri}"
|
|
56
|
+
type = "ext.Curb.Easy.#{method}"
|
|
57
|
+
req = http_post_without_apm(*args)
|
|
58
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
|
59
|
+
|
|
60
|
+
ctx = Span::Context.new(
|
|
61
|
+
CATEGORY: 'Web External',
|
|
62
|
+
SUBCATEGORY: 'Execute',
|
|
63
|
+
URL: uri,
|
|
64
|
+
STATUS: status_code,
|
|
65
|
+
METHOD: method
|
|
66
|
+
)
|
|
67
|
+
# Creates new span from HTTP result
|
|
68
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
69
|
+
req
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.http_put(url, data)
|
|
74
|
+
req = nil
|
|
75
|
+
return http_put_without_apm(url, data) unless StackifyRubyAPM.current_transaction
|
|
76
|
+
# Data configuration
|
|
77
|
+
#
|
|
78
|
+
@_apm_http_verb = :PUT
|
|
79
|
+
method = @_apm_http_verb
|
|
80
|
+
uri = url.strip
|
|
81
|
+
name = "#{method} #{uri}"
|
|
82
|
+
type = "ext.Curb.Easy.#{method}"
|
|
83
|
+
req = http_put_without_apm(url, data)
|
|
84
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
|
85
|
+
|
|
86
|
+
ctx = Span::Context.new(
|
|
87
|
+
CATEGORY: 'Web External',
|
|
88
|
+
SUBCATEGORY: 'Execute',
|
|
89
|
+
URL: uri,
|
|
90
|
+
STATUS: status_code,
|
|
91
|
+
METHOD: method
|
|
92
|
+
)
|
|
93
|
+
# Creates new span from HTTP result
|
|
94
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
95
|
+
req
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.http_get(*args)
|
|
100
|
+
req = nil
|
|
101
|
+
return http_get_without_apm(*args) unless StackifyRubyAPM.current_transaction
|
|
102
|
+
# Data configuration
|
|
103
|
+
#
|
|
104
|
+
@_apm_http_verb = :GET
|
|
105
|
+
method = @_apm_http_verb
|
|
106
|
+
uri = args[0].strip
|
|
107
|
+
name = "#{method} #{uri}"
|
|
108
|
+
type = "ext.Curb.Easy.#{method}"
|
|
109
|
+
req = http_get_without_apm(*args)
|
|
110
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
|
111
|
+
|
|
112
|
+
ctx = Span::Context.new(
|
|
113
|
+
CATEGORY: 'Web External',
|
|
114
|
+
SUBCATEGORY: 'Execute',
|
|
115
|
+
URL: uri,
|
|
116
|
+
STATUS: status_code,
|
|
117
|
+
METHOD: method
|
|
118
|
+
)
|
|
119
|
+
# Creates new span from HTTP result
|
|
120
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
121
|
+
req
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.http_delete(*args)
|
|
126
|
+
req = nil
|
|
127
|
+
return http_delete_without_apm(*args) unless StackifyRubyAPM.current_transaction
|
|
128
|
+
# Data configuration
|
|
129
|
+
#
|
|
130
|
+
@_apm_http_verb = :DELETE
|
|
131
|
+
method = @_apm_http_verb
|
|
132
|
+
uri = args[0].strip
|
|
133
|
+
name = "#{method} #{uri}"
|
|
134
|
+
type = "ext.Curb.Easy.#{method}"
|
|
135
|
+
req = http_delete_without_apm(*args)
|
|
136
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
|
137
|
+
|
|
138
|
+
ctx = Span::Context.new(
|
|
139
|
+
CATEGORY: 'Web External',
|
|
140
|
+
SUBCATEGORY: 'Execute',
|
|
141
|
+
URL: uri,
|
|
142
|
+
STATUS: status_code,
|
|
143
|
+
METHOD: method
|
|
144
|
+
)
|
|
145
|
+
# Creates new span from HTTP result
|
|
146
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
147
|
+
req
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
# Registers CurbSpy spy, go to: /stackify/spies.rb
|
|
154
|
+
#
|
|
155
|
+
register 'Curl::Easy', 'curl/easy', CurbEasySpy.new
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Monkey patch for the CurbSpy class for sending & receiving Curb responses.
|
|
4
|
+
#
|
|
5
|
+
module StackifyRubyAPM
|
|
6
|
+
# @api private
|
|
7
|
+
module Spies
|
|
8
|
+
# @api private
|
|
9
|
+
class CurbMultiSpy
|
|
10
|
+
def install
|
|
11
|
+
Curl::Multi.class_eval do
|
|
12
|
+
singleton_class.send(:alias_method, :http_without_apm, :http)
|
|
13
|
+
|
|
14
|
+
def self.http(urls_with_config, _multi_options = {}, &blk)
|
|
15
|
+
return http_without_apm(urls_with_config, _multi_options = {}, &blk) unless StackifyRubyAPM.current_transaction
|
|
16
|
+
http_without_apm(urls_with_config, _multi_options = {}) do |c, code, method|
|
|
17
|
+
status_code = code.zero? ? 404 : code
|
|
18
|
+
method = method.upcase
|
|
19
|
+
uri = c.url.to_s.strip
|
|
20
|
+
name = "#{method} #{uri}"
|
|
21
|
+
type = "ext.Curb.Multi.#{method}"
|
|
22
|
+
|
|
23
|
+
ctx = Span::Context.new(
|
|
24
|
+
CATEGORY: 'Web External',
|
|
25
|
+
SUBCATEGORY: 'Execute',
|
|
26
|
+
URL: uri,
|
|
27
|
+
STATUS: status_code,
|
|
28
|
+
METHOD: method
|
|
29
|
+
)
|
|
30
|
+
# Creates new span from HTTP result
|
|
31
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
|
32
|
+
blk.call(c, code, method)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
# Registers CurbSpy spy, go to: /stackify/spies.rb
|
|
40
|
+
#
|
|
41
|
+
register 'Curl::Multi', 'curl/multi', CurbMultiSpy.new
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Monkey patch for the HTTPClient class for sending & receiving HTTP responses.
|
|
2
4
|
#
|
|
3
5
|
|
|
@@ -8,13 +10,15 @@ module StackifyRubyAPM
|
|
|
8
10
|
class HTTPClientSpy
|
|
9
11
|
def install
|
|
10
12
|
HTTPClient.class_eval do
|
|
11
|
-
|
|
13
|
+
alias_method 'request_without_apm', 'request'
|
|
12
14
|
|
|
13
15
|
def request(method, uri, *args, &block)
|
|
14
16
|
req = nil
|
|
15
|
-
unless StackifyRubyAPM.current_transaction
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
return request_without_apm(method, uri, *args, &block) unless StackifyRubyAPM.current_transaction
|
|
18
|
+
|
|
19
|
+
# unless StackifyRubyAPM.current_transaction
|
|
20
|
+
# return request_without_apm(method, uri, *args, &block)
|
|
21
|
+
# end
|
|
18
22
|
|
|
19
23
|
# Data configuration
|
|
20
24
|
#
|
|
@@ -42,15 +46,13 @@ module StackifyRubyAPM
|
|
|
42
46
|
StackifyRubyAPM.span name, type, context: ctx do
|
|
43
47
|
req
|
|
44
48
|
end
|
|
45
|
-
|
|
46
49
|
end
|
|
47
50
|
end
|
|
48
51
|
end
|
|
49
|
-
# rubocop:enable Metrics/MethodLength
|
|
50
52
|
end
|
|
51
53
|
|
|
52
|
-
# Registers HTTPClient spy, go to: /
|
|
54
|
+
# Registers HTTPClient spy, go to: /stackify_apm/spies.rb
|
|
53
55
|
#
|
|
54
56
|
register 'HTTPClient', 'httpclient', HTTPClientSpy.new
|
|
55
57
|
end
|
|
56
|
-
end
|
|
58
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# This class monkey patch the http.rb gem with the request method.
|
|
3
5
|
#
|
|
@@ -6,23 +8,20 @@ module StackifyRubyAPM
|
|
|
6
8
|
module Spies
|
|
7
9
|
# @api private
|
|
8
10
|
class HTTPRbSpy
|
|
9
|
-
|
|
10
11
|
def install
|
|
11
12
|
HTTP::Client.class_eval do
|
|
12
|
-
|
|
13
|
+
alias_method 'request_without_apm', 'request'
|
|
13
14
|
|
|
14
15
|
# Make HTTP request
|
|
15
|
-
def request(verb, uri,
|
|
16
|
-
unless StackifyRubyAPM.current_transaction
|
|
17
|
-
return request_without_apm(verb, uri, opts = {})
|
|
18
|
-
end
|
|
16
|
+
def request(verb, uri, _opts = {})
|
|
17
|
+
return request_without_apm(verb, uri, _opts = {}) unless StackifyRubyAPM.current_transaction
|
|
19
18
|
|
|
20
19
|
method = verb.upcase
|
|
21
20
|
uri = uri.strip
|
|
22
21
|
name = "#{method} #{uri}"
|
|
23
22
|
type = "ext.httprb.#{method}"
|
|
24
23
|
|
|
25
|
-
req = request_without_apm(verb, uri,
|
|
24
|
+
req = request_without_apm(verb, uri, _opts = {})
|
|
26
25
|
ctx = Span::Context.new(
|
|
27
26
|
CATEGORY: 'Web External',
|
|
28
27
|
SUBCATEGORY: 'Execute',
|
|
@@ -37,9 +36,8 @@ module StackifyRubyAPM
|
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
|
-
# rubocop:enable Metrics/MethodLength
|
|
41
39
|
end
|
|
42
40
|
|
|
43
41
|
register 'HTTP::Client', 'http/client', HTTPRbSpy.new
|
|
44
42
|
end
|
|
45
|
-
end
|
|
43
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Monkey patch for the Mongo::Monitoring::Global module in mongoDB(http://api.mongodb.com/ruby/current/Mongo/Monitoring/Global.html)
|
|
2
4
|
# -> Allows subscribing to events for all Mongo clients.
|
|
3
5
|
#
|
|
@@ -45,7 +47,7 @@ module StackifyRubyAPM
|
|
|
45
47
|
col = nil
|
|
46
48
|
if document
|
|
47
49
|
document.each_with_index do |val, idx|
|
|
48
|
-
col = val[1] if idx
|
|
50
|
+
col = val[1] if idx.zero?
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
|
|
@@ -53,7 +55,7 @@ module StackifyRubyAPM
|
|
|
53
55
|
#
|
|
54
56
|
ctx = Span::Context.new(
|
|
55
57
|
CATEGORY: 'MongoDB',
|
|
56
|
-
MONGODB_COLLECTION: col
|
|
58
|
+
MONGODB_COLLECTION: col
|
|
57
59
|
)
|
|
58
60
|
|
|
59
61
|
# Creates new span from Mongo event
|
|
@@ -71,7 +73,7 @@ module StackifyRubyAPM
|
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
|
|
74
|
-
# Registers Mongo spy, go to: /
|
|
76
|
+
# Registers Mongo spy, go to: /stackify_apm/spies.rb
|
|
75
77
|
#
|
|
76
78
|
register 'Mongo', 'mongo', MongoSpy.new
|
|
77
79
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# Monkey patch for the Net::HTTP class for sending & receiving HTTP responses.
|
|
2
|
-
#
|
|
3
2
|
|
|
4
3
|
module StackifyRubyAPM
|
|
5
4
|
# @api private
|
|
@@ -8,7 +7,7 @@ module StackifyRubyAPM
|
|
|
8
7
|
class NetHTTPSpy
|
|
9
8
|
def install
|
|
10
9
|
Net::HTTP.class_eval do
|
|
11
|
-
|
|
10
|
+
alias_method 'request_without_apm', 'request'
|
|
12
11
|
|
|
13
12
|
def request(req, body = nil, &block)
|
|
14
13
|
result = nil
|
|
@@ -50,9 +49,9 @@ module StackifyRubyAPM
|
|
|
50
49
|
end
|
|
51
50
|
# rubocop:enable Metrics/MethodLength
|
|
52
51
|
end
|
|
53
|
-
|
|
54
|
-
# Registers Net::HTTP spy, go to: /
|
|
52
|
+
|
|
53
|
+
# Registers Net::HTTP spy, go to: /stackify_apm/spies.rb
|
|
55
54
|
#
|
|
56
55
|
register 'Net::HTTP', 'net/http', NetHTTPSpy.new
|
|
57
56
|
end
|
|
58
|
-
end
|
|
57
|
+
end
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Monkey patch for Redis.
|
|
2
4
|
#
|
|
3
|
-
|
|
4
5
|
module StackifyRubyAPM
|
|
5
6
|
# @api private
|
|
6
7
|
module Spies
|
|
7
8
|
# @api private
|
|
8
9
|
class RedisSpy
|
|
9
|
-
|
|
10
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
11
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
10
12
|
def install
|
|
11
13
|
::Redis::Client.class_eval do
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
alias_method 'call_without_apm', 'call'
|
|
15
|
+
|
|
14
16
|
def call(command, &block)
|
|
15
17
|
name = command[0].upcase.to_s
|
|
16
18
|
type = 'db.redis'
|
|
17
|
-
redis_details = command[1].is_a?(String) ? command[1].split(
|
|
18
|
-
redis_nspace = !redis_details.blank? ? redis_details[0] :
|
|
19
|
-
redis_key =
|
|
20
|
-
|
|
19
|
+
redis_details = command[1].is_a?(String) ? command[1].split(':') : []
|
|
20
|
+
redis_nspace = !redis_details.blank? ? redis_details[0] : ''
|
|
21
|
+
redis_key = ''
|
|
22
|
+
|
|
21
23
|
# Checks CACHEKEY value
|
|
22
24
|
if !redis_details.blank? && redis_details[1]
|
|
23
25
|
# Initially sets the CACHEKEY value
|
|
24
|
-
args = redis_details[1].split(
|
|
26
|
+
args = redis_details[1].split('/')
|
|
25
27
|
redis_key = args[0]
|
|
26
28
|
|
|
27
29
|
# If command has passed __method__, it will be included in the CACHEKEY value
|
|
28
30
|
# Possible formats:
|
|
29
|
-
# `<namespace:key/method_name/expires_in=300/ttl=60/>`
|
|
31
|
+
# `<namespace:key/method_name/expires_in=300/ttl=60/>`
|
|
30
32
|
# `<namespace:key/expires_in=300/ttl=60/>`
|
|
31
|
-
if args.length > 1 && !args[1].include?(
|
|
32
|
-
redis_key = args[0..1].join("/")
|
|
33
|
-
end
|
|
33
|
+
redis_key = args[0..1].join('/') if args.length > 1 && !args[1].include?('=')
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
return call_without_apm(command, &block) if command[0] == :auth
|
|
@@ -43,24 +43,25 @@ module StackifyRubyAPM
|
|
|
43
43
|
COMPONENT_DETAIL: 'Execute',
|
|
44
44
|
THREAD_ID: Thread.current.object_id,
|
|
45
45
|
OPERATION: name
|
|
46
|
-
}.tap do |hash|
|
|
46
|
+
}.tap do |hash|
|
|
47
47
|
hash[:CACHEKEY] = redis_key unless redis_key.empty?
|
|
48
48
|
hash[:CACHENAME] = redis_nspace unless redis_nspace.empty?
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
ctx = Span::Context.new(context)
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
StackifyRubyAPM.span name, type, context: ctx do
|
|
54
54
|
call_without_apm(command, &block)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
60
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
60
61
|
end
|
|
61
62
|
|
|
62
|
-
# Registers Redis spy, go to: /
|
|
63
|
+
# Registers Redis spy, go to: /stackify_apm/spies.rb
|
|
63
64
|
#
|
|
64
65
|
register 'Redis', 'redis', RedisSpy.new
|
|
65
66
|
end
|
|
66
|
-
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This class monkey patch the sequel.rb gem with the request method.
|
|
5
|
+
#
|
|
6
|
+
module StackifyRubyAPM
|
|
7
|
+
# @api private
|
|
8
|
+
module Spies
|
|
9
|
+
# @api private
|
|
10
|
+
class SequelSpy
|
|
11
|
+
DEFAULT = 'SQL'.freeze
|
|
12
|
+
TYPE = 'db.sequel.sql'.freeze
|
|
13
|
+
TABLE_REGEX = %{["'`]?([A-Za-z0-9]+)}.freeze
|
|
14
|
+
REGEXES = {
|
|
15
|
+
/^BEGIN/i => 'BEGIN',
|
|
16
|
+
/^COMMIT/i => 'COMMIT',
|
|
17
|
+
/^SELECT .* FROM #{TABLE_REGEX}/i => 'SELECT FROM ',
|
|
18
|
+
/^INSERT INTO #{TABLE_REGEX}/i => 'INSERT INTO ',
|
|
19
|
+
/^UPDATE #{TABLE_REGEX}/i => 'UPDATE ',
|
|
20
|
+
/^DELETE FROM #{TABLE_REGEX}/i => 'DELETE FROM '
|
|
21
|
+
}.freeze
|
|
22
|
+
FORMAT = '%s%s'.freeze
|
|
23
|
+
|
|
24
|
+
def install
|
|
25
|
+
require 'sequel/database/logging'
|
|
26
|
+
|
|
27
|
+
::Sequel::Database.class_eval do
|
|
28
|
+
alias_method 'log_connection_yield_without_apm', 'log_connection_yield'
|
|
29
|
+
|
|
30
|
+
def log_connection_yield(sql, *args, &block)
|
|
31
|
+
return log_connection_yield_without_apm(sql, *args, &block) unless StackifyRubyAPM.current_transaction
|
|
32
|
+
|
|
33
|
+
name = summarize sql
|
|
34
|
+
db_adapter = ''
|
|
35
|
+
db_adapter = args[0].class.to_s.gsub('::Database', '').downcase if args[0]
|
|
36
|
+
|
|
37
|
+
context = Span::Context.new(
|
|
38
|
+
CATEGORY: 'Database',
|
|
39
|
+
SUBCATEGORY: 'Execute',
|
|
40
|
+
COMPONENT_CATEGORY: 'DB Query',
|
|
41
|
+
COMPONENT_DETAIL: 'Execute SQL Query',
|
|
42
|
+
SQL: sql,
|
|
43
|
+
PROVIDER: get_profiler(db_adapter)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
StackifyRubyAPM.span(name, TYPE, context: context, &block)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# rubocop:disable Lint/UselessAssignment
|
|
50
|
+
def summarize(sql)
|
|
51
|
+
current_sql ||=
|
|
52
|
+
REGEXES.find do |regex, sig|
|
|
53
|
+
if (match = sql.match(regex))
|
|
54
|
+
break format(FORMAT, sig, match[1] && match[1].gsub(/["']/, ''))
|
|
55
|
+
end
|
|
56
|
+
end || DEFAULT
|
|
57
|
+
end
|
|
58
|
+
require 'stackify_apm/helper/database_helper'
|
|
59
|
+
end
|
|
60
|
+
# rubocop:enable Lint/UselessAssignment
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
register 'Sequel', 'sequel', SequelSpy.new
|
|
64
|
+
end
|
|
65
|
+
end
|