spartan_apm 0.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +55 -0
  5. data/VERSION +1 -0
  6. data/app/assets/flatpickr-4.6.9/LICENSE.md +21 -0
  7. data/app/assets/flatpickr-4.6.9/flatpickr.min.css +13 -0
  8. data/app/assets/flatpickr-4.6.9/flatpickr.min.js +2 -0
  9. data/app/assets/nice-select2-2.0.0/LICENSE +21 -0
  10. data/app/assets/nice-select2-2.0.0/nice-select2.min.css +1 -0
  11. data/app/assets/nice-select2-2.0.0/nice-select2.min.js +1 -0
  12. data/app/assets/spartan.svg +5 -0
  13. data/app/views/_help.html.erb +147 -0
  14. data/app/views/index.html.erb +231 -0
  15. data/app/views/scripts.js +911 -0
  16. data/app/views/styles.css +332 -0
  17. data/config.ru +36 -0
  18. data/lib/spartan_apm/engine.rb +45 -0
  19. data/lib/spartan_apm/error_info.rb +17 -0
  20. data/lib/spartan_apm/instrumentation/active_record.rb +13 -0
  21. data/lib/spartan_apm/instrumentation/base.rb +36 -0
  22. data/lib/spartan_apm/instrumentation/bunny.rb +24 -0
  23. data/lib/spartan_apm/instrumentation/cassandra.rb +13 -0
  24. data/lib/spartan_apm/instrumentation/curb.rb +13 -0
  25. data/lib/spartan_apm/instrumentation/dalli.rb +13 -0
  26. data/lib/spartan_apm/instrumentation/elasticsearch.rb +18 -0
  27. data/lib/spartan_apm/instrumentation/excon.rb +13 -0
  28. data/lib/spartan_apm/instrumentation/http.rb +13 -0
  29. data/lib/spartan_apm/instrumentation/httpclient.rb +13 -0
  30. data/lib/spartan_apm/instrumentation/net_http.rb +13 -0
  31. data/lib/spartan_apm/instrumentation/redis.rb +13 -0
  32. data/lib/spartan_apm/instrumentation/typhoeus.rb +13 -0
  33. data/lib/spartan_apm/instrumentation.rb +71 -0
  34. data/lib/spartan_apm/measure.rb +172 -0
  35. data/lib/spartan_apm/metric.rb +26 -0
  36. data/lib/spartan_apm/middleware/rack/end_middleware.rb +29 -0
  37. data/lib/spartan_apm/middleware/rack/start_middleware.rb +57 -0
  38. data/lib/spartan_apm/middleware/sidekiq/end_middleware.rb +25 -0
  39. data/lib/spartan_apm/middleware/sidekiq/start_middleware.rb +34 -0
  40. data/lib/spartan_apm/middleware.rb +16 -0
  41. data/lib/spartan_apm/persistence.rb +648 -0
  42. data/lib/spartan_apm/report.rb +436 -0
  43. data/lib/spartan_apm/string_cache.rb +27 -0
  44. data/lib/spartan_apm/web/api_request.rb +133 -0
  45. data/lib/spartan_apm/web/helpers.rb +88 -0
  46. data/lib/spartan_apm/web/router.rb +90 -0
  47. data/lib/spartan_apm/web.rb +10 -0
  48. data/lib/spartan_apm.rb +399 -0
  49. data/spartan_apm.gemspec +39 -0
  50. metadata +161 -0
@@ -0,0 +1,332 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ body {
6
+ font-family: sans-serif;
7
+ font-size: 14px;
8
+ line-height: 36px ;
9
+ text-align: left;
10
+ color: #212529;
11
+ background-color: #ffffff;
12
+ margin: 0 0 1rem 0;
13
+ padding: 0;
14
+ }
15
+
16
+ header {
17
+ background-color: #666;
18
+ color: white;
19
+ padding: 1rem;
20
+ margin-bottom: 1rem;
21
+ }
22
+
23
+ header h1 {
24
+ font-weight: bold;
25
+ font-size: 1.2rem;
26
+ margin: 0;
27
+ }
28
+
29
+ header .dates {
30
+ float: right;
31
+ max-width: 50%;
32
+ margin-left: 1rem;
33
+ }
34
+
35
+ header .help-btn {
36
+ float: right;
37
+ margin-right: 1rem;
38
+ }
39
+
40
+ header .help-btn a {
41
+ color: white;
42
+ text-decoration: none;
43
+ }
44
+ header .help-btn a:visited {
45
+ color: white;
46
+ }
47
+ header .help-btn a:hover {
48
+ color: #CCC;
49
+ }
50
+ header .help-btn a:active {
51
+ color: #CCC;
52
+ }
53
+
54
+ h2 {
55
+ font-weight: normal;
56
+ font-size: 1.2rem;
57
+ margin: 1rem 0;
58
+ }
59
+
60
+ .text-center {
61
+ text-align: center;
62
+ }
63
+
64
+ .text-right {
65
+ text-align: right;
66
+ }
67
+
68
+ .text-normal {
69
+ font-weight: normal;
70
+ }
71
+
72
+ .container {
73
+ padding-left: 1rem;
74
+ padding-right: 1rem;
75
+ margin-left: auto;
76
+ margin-right: auto;
77
+ }
78
+
79
+ .push-up {
80
+ margin-top: 1rem;
81
+ }
82
+
83
+ .nowrap {
84
+ white-space: nowrap;
85
+ }
86
+
87
+ .flex-container {
88
+ display: flex;
89
+ gap: 2rem;
90
+ align-items: flex-start;
91
+ align-content: space-between;
92
+ }
93
+
94
+ .flex-item {
95
+ width: 50%;
96
+ flex-grow: 1;
97
+ }
98
+
99
+ .show-xs {
100
+ display: none;
101
+ }
102
+
103
+ @media only screen and (max-width: 800px) {
104
+ .flex-container {
105
+ display: block;
106
+ }
107
+
108
+ .flex-item {
109
+ width: 100%;
110
+ }
111
+
112
+ .hide-xs {
113
+ display: none;
114
+ }
115
+
116
+ .show-xs {
117
+ display: inherit;
118
+ }
119
+
120
+ #start-time {
121
+ display: block;
122
+ margin-top: -1rem;
123
+ }
124
+
125
+ #end-time {
126
+ display: block;
127
+ margin-top: -0.5rem;
128
+ margin-bottom: 1rem;
129
+ }
130
+ }
131
+
132
+ .btn {
133
+ height: 2.4rem;
134
+ box-shadow: inset 0px 1px 0px 0px #ffffff;
135
+ background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
136
+ background-color: #f9f9f9;
137
+ border-radius: 6px;
138
+ border: 1px solid #dcdcdc;
139
+ display: inline-block;
140
+ color: #666666;
141
+ font-family: Arial;
142
+ font-size: 1rem;
143
+ font-weight: 200;
144
+ padding: 0.47rem 1rem;
145
+ text-decoration: none;
146
+ text-shadow: 0px 1px 0px #ffffff;
147
+ vertical-align: middle;
148
+ }
149
+ .btn:hover {
150
+ background:linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%);
151
+ background-color:#e9e9e9;
152
+ }
153
+ .btn:active {
154
+ position:relative;
155
+ top:1px;
156
+ }
157
+ .btn:disabled {
158
+ background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
159
+ background-color:#f9f9f9;
160
+ opacity: 0.65;
161
+ box-shadow: none;
162
+ }
163
+
164
+ .btn svg {
165
+ height: 1.2em;
166
+ }
167
+
168
+ .table {
169
+ width: 100%;
170
+ max-width: 100%;
171
+ margin-bottom: 1rem;
172
+ border-collapse: collapse;
173
+ }
174
+
175
+ .table thead th {
176
+ vertical-align: bottom;
177
+ border-bottom: 2px solid #dee2e6;
178
+ }
179
+
180
+ .table td, .table th {
181
+ padding: 0.75rem;
182
+ vertical-align: top;
183
+ border-top: 1px solid #dee2e6;
184
+ }
185
+
186
+ .table-striped tbody tr:nth-of-type(odd) {
187
+ background-color: rgba(0, 0, 0, .05);
188
+ }
189
+
190
+ .nice-select {
191
+ float: none;
192
+ display: inline-block;
193
+ border: 1px solid #ccc;
194
+ margin: 0 0 0.5rem 0;
195
+ }
196
+
197
+ .nice-select .nice-select-search {
198
+ border: 1px solid #ccc;
199
+ }
200
+
201
+ .form-control {
202
+ margin: 0 0 0.5rem 0;
203
+ padding: .375rem .5rem;
204
+ color: #495057;
205
+ background-color: #fff;
206
+ background-clip: padding-box;
207
+ border: 1px solid #ccc;
208
+ border-radius: 5px;
209
+ transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
210
+ max-width: 100%;
211
+ line-height: 36px;
212
+ height: 38px;
213
+ font-size: 14px;
214
+ display: inline-block;
215
+ outline: none;
216
+ }
217
+
218
+ .form-control:disabled {
219
+ color: #999;
220
+ }
221
+
222
+ .form-control:focus, .nice-select:focus, .nice-select:active, .nice-select.open {
223
+ border-color: #333;
224
+ }
225
+
226
+ select {
227
+ display: none;
228
+ }
229
+
230
+ .hidden {
231
+ display: none;
232
+ }
233
+
234
+ .spinner {
235
+ width: 100%;
236
+ height: 64px;
237
+ background-repeat: no-repeat;
238
+ background-position: center;
239
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64px' height='64px' viewBox='0 0 128 128'%3E%3Cg%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%23000000'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(45, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(90, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(135, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(180, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(225, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(270, 64, 64)'/%3E%3Cpath d='M116.3 60.18a52.28 52.28 0 0 0-12.64-30.45l8.06-8.06a63.6 63.6 0 0 1 15.97 38.5h-11.4z' fill='%239c9c9c' transform='rotate(315, 64, 64)'/%3E%3CanimateTransform attributeName='transform' type='rotate' values='0 64 64;45 64 64;90 64 64;135 64 64;180 64 64;225 64 64;270 64 64;315 64 64' calcMode='discrete' dur='720ms' repeatCount='indefinite'%3E%3C/animateTransform%3E%3C/g%3E%3C/svg%3E");
240
+ }
241
+
242
+ .download-btn {
243
+ cursor: pointer;
244
+ width: 1.3rem;
245
+ }
246
+
247
+ .error-class-name {
248
+ font-size: 0.9rem;
249
+ overflow-wrap: break-word;
250
+ }
251
+
252
+ .error-count {
253
+ font-size: 0.9rem;
254
+ }
255
+
256
+ .error-backtrace {
257
+ font-family: monospace;
258
+ font-size: 0.9rem;
259
+ }
260
+
261
+ .backtrace-line {
262
+ text-indent: -2rem;
263
+ margin-left: 2rem;
264
+ line-height: 1.1rem;
265
+ margin-bottom: 0.2rem;
266
+ overflow-wrap: break-word;
267
+ }
268
+
269
+ #alert {
270
+ display: none;
271
+ text-align: center;
272
+ margin: 0 auto;
273
+ color: red;
274
+ }
275
+
276
+ #modal {
277
+ z-index: 1000000000000;
278
+ display: none;
279
+ padding-top: 5rem;
280
+ position: fixed;
281
+ left: 0;
282
+ top: 0;
283
+ width: 100%;
284
+ height: 100%;
285
+ overflow: auto;
286
+ background-color: rgba(0,0,0,0.4);
287
+ }
288
+
289
+ .modal-dialog {
290
+ margin: auto;
291
+ background-color: #fff;
292
+ position: relative;
293
+ outline: 0;
294
+ padding: 2em;
295
+ box-shadow: 3px 3px 7px 3px rgba(0, 0, 0, 0.6);
296
+ border-radius: 4px;
297
+ width: 80%;
298
+ height: 80%;
299
+ }
300
+
301
+ .modal-content {
302
+ height: 100%;
303
+ overflow: auto;
304
+ line-height: 1rem;
305
+ }
306
+
307
+ .modal-content p {
308
+ margin-top: 0;
309
+ margin-bottom: 0.75rem;
310
+ }
311
+
312
+ .modal-close {
313
+ display: block;
314
+ position: absolute;
315
+ top: 0;
316
+ right: 0;
317
+ border: 0;
318
+ padding: 1ex;
319
+ background-color: inherit;
320
+ font-size: 1.5rem;
321
+ font-weight: 500;
322
+ }
323
+
324
+ dd {
325
+ margin-inline-start: 0;
326
+ margin: 0 0 0.5rem 0;
327
+ font-weight: bold;
328
+ }
329
+
330
+ dt {
331
+ margin: 0 0 1rem 0;
332
+ }
data/config.ru ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+
5
+ require_relative "lib/spartan_apm"
6
+
7
+ if SpartanAPM.apps.empty?
8
+ raise ArgumentError.new("Apps must be specified in comma delimited list in the SPARTAN_APM environment variable")
9
+ else
10
+ puts "Using apps #{SpartanAPM.apps.join(', ')} in environments #{SpartanAPM.environments.join(', ')}"
11
+ end
12
+
13
+ # Make sure we don't log access tokens.
14
+ class SecureLogger
15
+ ACCESS_TOKEN_PATTERN = /([?&]access_token=)[^&\s]+/
16
+
17
+ def write(message)
18
+ $stdout.write(message.gsub(ACCESS_TOKEN_PATTERN, '\1******'))
19
+ end
20
+ end
21
+
22
+ use Rack::CommonLogger, SecureLogger.new
23
+
24
+ basic_auth_user = ENV.fetch("BASIC_AUTH_USER", "")
25
+ basic_auth_password = ENV.fetch("BASIC_AUTH_PASSWORD", "")
26
+ unless basic_auth_user.empty?
27
+ use Rack::Auth::Basic do |user, password|
28
+ user == basic_auth_user && password.to_s == basic_auth_password
29
+ end
30
+ end
31
+
32
+ if File.exist?(File.join(__dir__, "public", "plotly.js"))
33
+ use Rack::Static, urls: ["/plotly.js"], root: "public"
34
+ end
35
+
36
+ run SpartanAPM::Web::Router.new
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ # Rails engine that will automatically instrument a Rails application
5
+ # for web requests. If Sidekiq is installed, it will be instrumented
6
+ # as well.
7
+ class Engine < Rails::Engine
8
+ initializer "spartan_apm" do |app|
9
+ ActiveSupport.on_load(:action_controller) do
10
+ ActionController::Base.prepend_around_action do |controller, action|
11
+ # rubocop:disable Lint/RescueException
12
+ begin
13
+ action.call
14
+ rescue Exception => e
15
+ SpartanAPM.capture_error(e)
16
+ raise
17
+ end
18
+ # rubocop:enable Lint/RescueException
19
+ end
20
+
21
+ if defined?(Sidekiq) && Sidekiq.server?
22
+ Sidekiq.configure_server do |config|
23
+ config.server_middleware do |chain|
24
+ chain.prepend SpartanAPM::Middleware::Sidekiq::StartMiddleware
25
+ chain.add SpartanAPM::Middleware::Sidekiq::EndMiddleware
26
+ end
27
+ end
28
+ end
29
+
30
+ app.config.middleware.insert(0, SpartanAPM::Middleware::Rack::StartMiddleware)
31
+ app.config.middleware.use(SpartanAPM::Middleware::Rack::EndMiddleware)
32
+ end
33
+ end
34
+
35
+ config.after_initialize do
36
+ SpartanAPM.configure do |config|
37
+ config.env = Rails.env.to_s unless config.env_set?
38
+ config.logger ||= Rails.logger
39
+ apps = ["web"]
40
+ apps << "sidekiq" if defined?(Sidekiq)
41
+ config.apps = apps if config.apps.empty?
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ # Data structure for capturing information about errors.
5
+ class ErrorInfo
6
+ attr_reader :time, :class_name, :message, :backtrace
7
+ attr_accessor :count
8
+
9
+ def initialize(time, class_name, message, backtrace, count)
10
+ @time = time
11
+ @class_name = class_name
12
+ @message = message
13
+ @backtrace = backtrace
14
+ @count = count.to_i
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class ActiveRecord < Base
6
+ def initialize
7
+ @klass = ::ActiveRecord::Base.connection.class if defined?(::ActiveRecord::Base)
8
+ @name = :database
9
+ @methods = [:exec_query]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ # Base class for describing how to inject instrumentation code into another class.
6
+ # This class should be extended and the subclass should set the klass, name, and methods
7
+ # attributes in the constructor.
8
+ class Base
9
+ # The class that should be instrumented.
10
+ attr_accessor :klass
11
+
12
+ # The component name that metrics should be recorded as.
13
+ attr_accessor :name
14
+
15
+ # Flag indicating if metrics should be captured exclusively.
16
+ attr_accessor :exclusive
17
+
18
+ # List of instance methods to instrument.
19
+ attr_accessor :methods
20
+
21
+ # Inject instrumentation code into the specified class' methods.
22
+ def instrument!
23
+ raise ArgumentError.new("klass not specified") unless klass
24
+ raise ArgumentError.new("name not specified") unless name
25
+ Instrumentation.instrument!(klass, name, methods, exclusive: exclusive, module_name: "#{self.class.name.split("::").last}Instrumentation")
26
+ end
27
+
28
+ # Determine if the instrumentation definition is valid.
29
+ def valid?
30
+ return false if klass.nil? || name.nil?
31
+ all_methods = klass.public_instance_methods + klass.protected_instance_methods + klass.private_instance_methods
32
+ Array(methods).all? { |m| all_methods.include?(m) }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Bunny < Base
6
+ def initialize
7
+ @klass = ::Bunny::Channel if defined?(::Bunny::Channel)
8
+ @name = :rabbitmq
9
+ @methods = [
10
+ :basic_get,
11
+ :basic_publish,
12
+ :basic_ack,
13
+ :basic_nack,
14
+ :basic_consume,
15
+ :basic_consume_with,
16
+ :basic_recover,
17
+ :basic_cancel,
18
+ :basic_qos,
19
+ :basic_reject
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Cassandra < Base
6
+ def initialize
7
+ @klass = ::Cassandra::Session if defined?(::Cassandra::Session)
8
+ @name = :cassandra
9
+ @methods = [:execute, :prepare]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Curb < Base
6
+ def initialize
7
+ @klass = ::Curl::Multi if defined?(::Curl::Multi)
8
+ @name = :http
9
+ @methods = [:perform]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Dalli < Base
6
+ def initialize
7
+ @klass = ::Dalli::Client if defined?(::Dalli::Client)
8
+ @name = :memcache
9
+ @methods = [:perform]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Elasticsearch < Base
6
+ def initialize
7
+ if defined?(::Elastic::Transport::Client)
8
+ @klass = ::Elastic::Transport::Client
9
+ elsif defined?(::Elasticsearch::Transport::Client)
10
+ @klass = ::Elasticsearch::Transport::Client
11
+ end
12
+ @name = :elasticsearch
13
+ @methods = [:perform_request]
14
+ @exclusive = true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Excon < Base
6
+ def initialize
7
+ @klass = ::Excon::Connection if defined?(::Excon::Connection)
8
+ @name = :http
9
+ @methods = [:request]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class HTTP < Base
6
+ def initialize
7
+ @klass = ::HTTP::Client if defined?(::HTTP::Client)
8
+ @name = :http
9
+ @methods = [:perform]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class HTTPClient < Base
6
+ def initialize
7
+ @klass = ::HTTPClient if defined?(::HTTPClient)
8
+ @name = :http
9
+ @methods = [:do_get_block]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class NetHTTP < Base
6
+ def initialize
7
+ @klass = ::Net::HTTP if defined?(::Net::HTTP)
8
+ @name = :http
9
+ @methods = [:request]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Redis < Base
6
+ def initialize
7
+ @klass = ::Redis::Client if defined?(::Redis::Client)
8
+ @name = :redis
9
+ @methods = [:process]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpartanAPM
4
+ module Instrumentation
5
+ class Typhoeus < Base
6
+ def initialize
7
+ @klass = ::Typhoeus::Hydra if defined?(::Typhoeus::Hydra)
8
+ @name = :http
9
+ @methods = [:run]
10
+ end
11
+ end
12
+ end
13
+ end