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
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
# This class builds the context of the Transaction/Span
|
|
4
4
|
# Context represents the HTTP request information such as headers, cookies, body.
|
|
5
|
-
#
|
|
6
5
|
|
|
7
6
|
module StackifyRubyAPM
|
|
8
7
|
# @api private
|
|
@@ -19,8 +18,6 @@ module StackifyRubyAPM
|
|
|
19
18
|
|
|
20
19
|
private
|
|
21
20
|
|
|
22
|
-
# rubocop:disable Metrics/AbcSize
|
|
23
|
-
#
|
|
24
21
|
# Request format and values are assigned to context
|
|
25
22
|
#
|
|
26
23
|
def apply_to_request(context, rack_env)
|
|
@@ -36,7 +33,6 @@ module StackifyRubyAPM
|
|
|
36
33
|
|
|
37
34
|
context
|
|
38
35
|
end
|
|
39
|
-
# rubocop:enable Metrics/AbcSize
|
|
40
36
|
|
|
41
37
|
def get_body(req)
|
|
42
38
|
return req.POST if req.form_data?
|
|
@@ -73,6 +69,7 @@ module StackifyRubyAPM
|
|
|
73
69
|
|
|
74
70
|
def build_http_version(rack_env)
|
|
75
71
|
return unless (http_version = rack_env['HTTP_VERSION'])
|
|
72
|
+
|
|
76
73
|
http_version.gsub(%r{HTTP/}, '')
|
|
77
74
|
end
|
|
78
75
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
5
|
-
require '
|
|
6
|
-
require '
|
|
3
|
+
require 'stackify_apm/stacktrace'
|
|
4
|
+
require 'stackify_apm/context'
|
|
5
|
+
require 'stackify_apm/error/exception'
|
|
6
|
+
require 'stackify_apm/error/log'
|
|
7
7
|
|
|
8
8
|
module StackifyRubyAPM
|
|
9
9
|
# @api private
|
|
@@ -11,8 +11,9 @@ module StackifyRubyAPM
|
|
|
11
11
|
def initialize(culprit: nil)
|
|
12
12
|
@id = SecureRandom.uuid
|
|
13
13
|
@culprit = culprit
|
|
14
|
+
time_now = Time.now
|
|
14
15
|
|
|
15
|
-
@timestamp =
|
|
16
|
+
@timestamp = time_now.to_f * 1000
|
|
16
17
|
@context = Context.new
|
|
17
18
|
|
|
18
19
|
@transaction_id = nil
|
|
@@ -21,4 +22,4 @@ module StackifyRubyAPM
|
|
|
21
22
|
attr_accessor :id, :culprit, :exception, :log, :transaction_id, :context
|
|
22
23
|
attr_reader :timestamp
|
|
23
24
|
end
|
|
24
|
-
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StackifyRubyAPM
|
|
4
|
+
class Error
|
|
5
|
+
# @api private
|
|
6
|
+
class Exception
|
|
7
|
+
MOD_SPLIT = '::'.freeze
|
|
8
|
+
|
|
9
|
+
def initialize(exception, **attrs)
|
|
10
|
+
@message =
|
|
11
|
+
"#{exception.class}: #{exception.message}"
|
|
12
|
+
@type = exception.class.to_s
|
|
13
|
+
@module = format_module exception
|
|
14
|
+
|
|
15
|
+
attrs.each do |key, val|
|
|
16
|
+
send(:"#{key}=", val)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_accessor(
|
|
21
|
+
:attributes,
|
|
22
|
+
:code,
|
|
23
|
+
:handled,
|
|
24
|
+
:message,
|
|
25
|
+
:module,
|
|
26
|
+
:stacktrace,
|
|
27
|
+
:type
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def format_module(exception)
|
|
33
|
+
exception.class.to_s.split(MOD_SPLIT)[0...-1].join(MOD_SPLIT)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StackifyRubyAPM
|
|
4
|
+
class Error
|
|
5
|
+
# @api private
|
|
6
|
+
class Log
|
|
7
|
+
def initialize(message, attrs = {})
|
|
8
|
+
@message = message
|
|
9
|
+
|
|
10
|
+
attrs.each do |key, val|
|
|
11
|
+
send(:"#{key}=", val)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_accessor(
|
|
16
|
+
:level,
|
|
17
|
+
:logger_name,
|
|
18
|
+
:message,
|
|
19
|
+
:param_message,
|
|
20
|
+
:stacktrace
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This module build errors/exceptions and the Frames/stacktraces affected/related to the error
|
|
4
|
+
|
|
5
|
+
module StackifyRubyAPM
|
|
6
|
+
# @api private
|
|
7
|
+
class ErrorBuilder
|
|
8
|
+
def initialize(agent)
|
|
9
|
+
@agent = agent
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def build_exception(exception, handled: true)
|
|
13
|
+
error = Error.new
|
|
14
|
+
error.exception = Error::Exception.new(exception, handled: handled)
|
|
15
|
+
|
|
16
|
+
if exception.backtrace
|
|
17
|
+
add_stacktrace error, :exception, exception.backtrace
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
add_transaction_id error
|
|
21
|
+
|
|
22
|
+
if (transaction = StackifyRubyAPM.current_transaction)
|
|
23
|
+
error.context = transaction.context.dup
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
error
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def build_log(message, backtrace: nil, **attrs)
|
|
30
|
+
error = Error.new
|
|
31
|
+
error.log = Error::Log.new(message, **attrs)
|
|
32
|
+
|
|
33
|
+
add_stacktrace error, :log, backtrace if backtrace
|
|
34
|
+
add_transaction_id error
|
|
35
|
+
|
|
36
|
+
error
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def add_stacktrace(error, kind, backtrace)
|
|
42
|
+
stacktrace =
|
|
43
|
+
@agent.stacktrace_builder.build(backtrace, :error)
|
|
44
|
+
return unless stacktrace
|
|
45
|
+
|
|
46
|
+
case kind
|
|
47
|
+
when :exception
|
|
48
|
+
error.exception.stacktrace = stacktrace
|
|
49
|
+
when :log
|
|
50
|
+
error.log.stacktrace = stacktrace
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
error.culprit = stacktrace.frames.first.function
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_transaction_id(error)
|
|
57
|
+
return unless (transaction = StackifyRubyAPM.current_transaction)
|
|
58
|
+
error.transaction_id = transaction.id
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# get_profiler - It will return the database driver of the Object.
|
|
4
|
+
#
|
|
5
|
+
module DatabaseHelper
|
|
6
|
+
# return back valid PROVIDER based on driver name passed in
|
|
7
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
8
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
9
|
+
def get_profiler(driver)
|
|
10
|
+
if driver.to_s.empty?
|
|
11
|
+
'generic'
|
|
12
|
+
elsif driver.include? 'mysql'
|
|
13
|
+
'mysql'
|
|
14
|
+
elsif driver.include? 'postgres'
|
|
15
|
+
'postgresql'
|
|
16
|
+
elsif driver.include? 'oci8'
|
|
17
|
+
'oracle'
|
|
18
|
+
elsif driver.include? 'db2'
|
|
19
|
+
'db2'
|
|
20
|
+
elsif driver.include? 'sqlite'
|
|
21
|
+
'generic'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
25
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
26
|
+
end
|
|
27
|
+
include DatabaseHelper
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'stackify_apm/span'
|
|
4
|
+
require 'stackify_apm/transaction'
|
|
1
5
|
#
|
|
2
6
|
# The Instrumenter will build/process the transactions and spans.
|
|
3
7
|
#
|
|
4
|
-
|
|
5
|
-
require 'stackify/span'
|
|
6
|
-
require 'stackify/transaction'
|
|
7
|
-
|
|
8
8
|
module StackifyRubyAPM
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
# @api private
|
|
10
|
+
class Instrumenter
|
|
11
11
|
include Log
|
|
12
12
|
|
|
13
13
|
KEY = :_stackify_transaction_key
|
|
14
|
-
|
|
14
|
+
# Transaction Info class
|
|
15
15
|
class TransactionInfo
|
|
16
16
|
def initialize
|
|
17
17
|
self.current = nil
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def current
|
|
21
|
-
# puts '[Instrumenter] [lib/instrumenter.rb] TransactionInfo.current()'
|
|
22
21
|
Thread.current[KEY]
|
|
23
22
|
end
|
|
24
23
|
|
|
@@ -48,20 +47,17 @@ module StackifyRubyAPM
|
|
|
48
47
|
end
|
|
49
48
|
|
|
50
49
|
def current_transaction
|
|
51
|
-
|
|
50
|
+
@transaction_info.current
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
def current_transaction=(transaction)
|
|
55
54
|
@transaction_info.current = transaction
|
|
56
55
|
end
|
|
57
56
|
|
|
58
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
59
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
60
|
-
#
|
|
61
57
|
# Creates a new transaction or return the currently running
|
|
62
58
|
#
|
|
63
59
|
def transaction(*args)
|
|
64
|
-
debug
|
|
60
|
+
debug '[Instrumenter] transaction(*args)'
|
|
65
61
|
unless config.instrument
|
|
66
62
|
yield if block_given?
|
|
67
63
|
return
|
|
@@ -83,17 +79,14 @@ module StackifyRubyAPM
|
|
|
83
79
|
self.current_transaction = nil
|
|
84
80
|
transaction.done
|
|
85
81
|
end
|
|
86
|
-
|
|
87
|
-
#puts transaction.inspect
|
|
88
82
|
|
|
89
83
|
transaction
|
|
90
84
|
end
|
|
91
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
92
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
93
85
|
|
|
94
86
|
def span(*args, &block)
|
|
95
87
|
unless current_transaction
|
|
96
88
|
return yield if block_given?
|
|
89
|
+
|
|
97
90
|
return
|
|
98
91
|
end
|
|
99
92
|
|
|
@@ -114,5 +107,5 @@ module StackifyRubyAPM
|
|
|
114
107
|
"current_transaction=#{current_transaction.inspect}" \
|
|
115
108
|
'>'
|
|
116
109
|
end
|
|
117
|
-
|
|
118
|
-
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
module StackifyRubyAPM
|
|
9
9
|
# @api private
|
|
10
10
|
class LogDevice < Logger::LogDevice
|
|
11
|
+
alias_method 'write_without_apm', 'write'
|
|
12
|
+
def write(message)
|
|
13
|
+
if @filename
|
|
14
|
+
if FileTest.exist?(@filename)
|
|
15
|
+
else
|
|
16
|
+
@dev = create_logfile(@filename)
|
|
17
|
+
File.chmod(0o777, @filename)
|
|
18
|
+
|
|
19
|
+
return @dev
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
write_without_apm(message)
|
|
23
|
+
end
|
|
24
|
+
|
|
11
25
|
def add_log_header(file)
|
|
12
26
|
# Make it only empty.
|
|
13
27
|
end
|
|
@@ -21,10 +35,7 @@ module StackifyRubyAPM
|
|
|
21
35
|
# set a temporary filename that doesn't have the increment prefix and .log format.
|
|
22
36
|
temp_filename = @filename.gsub(/\-(d*\.?\d*).log/, '')
|
|
23
37
|
# set a temporary file increment while stripping the current filename and retain the number
|
|
24
|
-
txttemp_fileincrement = @filename.gsub(temp_filename,'')
|
|
25
|
-
txttemp_fileincrement = txttemp_fileincrement.gsub('-','')
|
|
26
|
-
txttemp_fileincrement = txttemp_fileincrement.gsub('.log','')
|
|
27
|
-
|
|
38
|
+
txttemp_fileincrement = @filename.gsub(temp_filename, '').delete('^0-9')
|
|
28
39
|
# convert the string value to integer
|
|
29
40
|
current_fileprefix = txttemp_fileincrement.to_i
|
|
30
41
|
# assign as filename counter
|
|
@@ -33,12 +44,12 @@ module StackifyRubyAPM
|
|
|
33
44
|
filename_counter = current_fileprefix + 1
|
|
34
45
|
else
|
|
35
46
|
ctr_flagger = 0
|
|
36
|
-
# a loop that check if the number of filenames if exists or not
|
|
37
|
-
|
|
47
|
+
# a loop that check if the number of filenames if exists or not
|
|
48
|
+
1.upto(current_fileprefix) do |i|
|
|
38
49
|
temp_oldfile = "#{temp_filename}-#{i}.log"
|
|
39
|
-
ctr_flagger
|
|
50
|
+
ctr_flagger += 1 if FileTest.exist?(temp_oldfile)
|
|
40
51
|
end
|
|
41
|
-
# if the counter is 0 then set the filename counter to 1
|
|
52
|
+
# if the counter is 0 then set the filename counter to 1
|
|
42
53
|
filename_counter = 1 if ctr_flagger < 0
|
|
43
54
|
end
|
|
44
55
|
|
|
@@ -47,14 +58,13 @@ module StackifyRubyAPM
|
|
|
47
58
|
temp_newfilename = "#{temp_filename}-#{filename_counter}.log"
|
|
48
59
|
@filename = temp_newfilename
|
|
49
60
|
@dev = create_logfile(@filename)
|
|
61
|
+
File.chmod(0o777, @filename)
|
|
50
62
|
|
|
51
63
|
true
|
|
52
64
|
end
|
|
53
65
|
|
|
54
66
|
# This is the monkeypatch of core Logger method where reformats the file name when creating the file log.
|
|
55
67
|
def shift_log_period(period_end)
|
|
56
|
-
puts "shift_log_period(period_end) mao ni"
|
|
57
|
-
|
|
58
68
|
suffix = period_end.strftime(@shift_period_suffix)
|
|
59
69
|
age_file = "#{@filename}.#{suffix}"
|
|
60
70
|
if FileTest.exist?(age_file)
|
|
@@ -70,10 +80,11 @@ module StackifyRubyAPM
|
|
|
70
80
|
@dev.close rescue nil
|
|
71
81
|
File.rename(@filename.to_s, age_file)
|
|
72
82
|
@dev = create_logfile(@filename)
|
|
83
|
+
File.chmod(0o777, @filename)
|
|
73
84
|
|
|
74
85
|
true
|
|
75
86
|
end
|
|
76
87
|
# rubocop:enable Style/RescueModifier
|
|
77
88
|
# rubocop:enable Lint/RescueWithoutErrorClass
|
|
78
89
|
end
|
|
79
|
-
end
|
|
90
|
+
end
|
|
@@ -28,12 +28,7 @@ module StackifyRubyAPM
|
|
|
28
28
|
shift_period_suffix: shift_period_suffix)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
|
-
require 'stackify/logger/log_device'
|
|
32
|
-
# rubocop:enable Style/NumericLiterals
|
|
33
|
-
# rubocop:enable Style/GuardClause
|
|
34
|
-
# rubocop:enable Metrics/ParameterLists
|
|
35
|
-
# rubocop:enable Lint/UnusedMethodArgument
|
|
36
|
-
|
|
37
31
|
|
|
32
|
+
require 'stackify_apm/logger/log_device'
|
|
38
33
|
end
|
|
39
34
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This class monkey patches the Rack Middleware method: e.g., call(env)
|
|
5
|
+
# It also handles the submission of transactions to Agent.
|
|
6
|
+
#
|
|
7
|
+
# If Agent is running, build_transaction(env) is called:
|
|
8
|
+
#
|
|
9
|
+
# -> BUILDS transaction: /stackify_ruby_apm.rb (#self.transaction)
|
|
10
|
+
# -> builds a [Context] from a Rack `env`: /stackify_ruby_apm.rb (#self.build_context)
|
|
11
|
+
# -> context may include information about the request,
|
|
12
|
+
# response, current user and more
|
|
13
|
+
#
|
|
14
|
+
# -> SUBMITS transaction: stackify_apm/transaction.rb (#submit)
|
|
15
|
+
# -> instrumenter submits transaction
|
|
16
|
+
# -> worker will run (if != running), responsible for sending transactions to APM
|
|
17
|
+
# for every 10 secs (based on config.flush_interval)
|
|
18
|
+
# -> transaction will be stored in queue by Agent
|
|
19
|
+
# -> worker will constantly execute transaction sending to APM
|
|
20
|
+
#
|
|
21
|
+
|
|
22
|
+
module StackifyRubyAPM
|
|
23
|
+
# @api private
|
|
24
|
+
class Middleware
|
|
25
|
+
def initialize(app)
|
|
26
|
+
@app = app
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# This is where the requests are received, built into a transaction, and then submitted
|
|
30
|
+
#
|
|
31
|
+
def call(env)
|
|
32
|
+
begin
|
|
33
|
+
# if running? && !path_ignored?(env)
|
|
34
|
+
transaction = build_transaction(env) if running?
|
|
35
|
+
|
|
36
|
+
resp = @app.call env
|
|
37
|
+
|
|
38
|
+
submit_transaction(transaction, *resp) if transaction
|
|
39
|
+
rescue InternalError
|
|
40
|
+
raise # Don't report StackifyRubyAPM errors
|
|
41
|
+
rescue StandardError
|
|
42
|
+
transaction.submit('500', status: 500) if transaction
|
|
43
|
+
raise
|
|
44
|
+
ensure
|
|
45
|
+
transaction.release if transaction
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
resp
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def submit_transaction(transaction, status, headers, _body)
|
|
52
|
+
result = status.to_i
|
|
53
|
+
transaction.submit(result, status: status, headers: headers)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Start of transaction building with params: name, type, context
|
|
57
|
+
#
|
|
58
|
+
def build_transaction(env)
|
|
59
|
+
StackifyRubyAPM.transaction 'Rack', 'request', context: StackifyRubyAPM.build_context(env)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def running?
|
|
63
|
+
StackifyRubyAPM.running?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def config
|
|
67
|
+
StackifyRubyAPM.agent.config
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|