stackify-ruby-apm 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
# This module converts its result to a hash.
|
4
|
-
#
|
5
4
|
|
6
5
|
module StackifyRubyAPM
|
7
6
|
# @api private
|
@@ -12,7 +11,6 @@ module StackifyRubyAPM
|
|
12
11
|
|
13
12
|
def to_h
|
14
13
|
instance_variables.each_with_object({}) do |name, h|
|
15
|
-
|
16
14
|
key = name.to_s.delete('@').to_sym
|
17
15
|
value = instance_variable_get(name)
|
18
16
|
is_hashable =
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
|
-
# Collects and registers existing events and classes
|
4
|
+
# Collects and registers existing events and classes
|
4
5
|
#
|
5
6
|
|
6
7
|
module StackifyRubyAPM # :nodoc:
|
@@ -65,6 +66,6 @@ module StackifyRubyAPM # :nodoc:
|
|
65
66
|
action_view
|
66
67
|
active_record
|
67
68
|
].each do |lib|
|
68
|
-
require "
|
69
|
+
require "stackify_apm/normalizers/#{lib}"
|
69
70
|
end
|
70
71
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'stackify_apm/helper/database_helper'
|
4
|
+
|
3
5
|
module StackifyRubyAPM
|
4
6
|
module Normalizers
|
5
7
|
module ActiveRecord
|
@@ -25,33 +27,9 @@ module StackifyRubyAPM
|
|
25
27
|
|
26
28
|
private
|
27
29
|
|
28
|
-
# return back valid PROVIDER based on driver name passed in
|
29
|
-
def get_profiler(driver)
|
30
|
-
if driver.to_s.empty?
|
31
|
-
"generic"
|
32
|
-
elsif driver.include? "mysql"
|
33
|
-
"mysql"
|
34
|
-
elsif driver.include? "pg"
|
35
|
-
"postgresql"
|
36
|
-
elsif driver.include? "oci8"
|
37
|
-
"oracle"
|
38
|
-
elsif driver.include? "db2"
|
39
|
-
"db2"
|
40
|
-
elsif driver.include? "sqlite"
|
41
|
-
"sqlite"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
30
|
def query_variables(payload)
|
46
|
-
debug
|
31
|
+
debug '[SqlNormalizer] query_variables payload:'
|
47
32
|
debug payload.inspect
|
48
|
-
|
49
|
-
if payload[:type_casted_binds]
|
50
|
-
row_id = payload[:type_casted_binds][0]
|
51
|
-
else
|
52
|
-
row_id = []
|
53
|
-
end
|
54
|
-
|
55
33
|
{
|
56
34
|
CATEGORY: 'Database',
|
57
35
|
SUBCATEGORY: 'Execute',
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
4
|
# This class loads the specified config of the Rails app and starts the Agent.
|
4
5
|
#
|
5
|
-
# APM Config setting is done at
|
6
|
+
# APM Config setting is done at stackify_apm/config.rb
|
6
7
|
#
|
7
8
|
# After the Agent has been started:
|
8
9
|
# -> the enabled Spies (libraries) are registered
|
@@ -10,13 +11,12 @@
|
|
10
11
|
# -> the Middleware is then inserted
|
11
12
|
#
|
12
13
|
|
13
|
-
require '
|
14
|
+
require 'stackify_apm/subscriber'
|
14
15
|
|
15
16
|
module StackifyRubyAPM
|
16
17
|
# @api private
|
17
18
|
# Railtie - core of the Rails framework and provides several hooks to modify the initialization process.
|
18
19
|
class Railtie < Rails::Railtie
|
19
|
-
|
20
20
|
config.stackify = ActiveSupport::OrderedOptions.new
|
21
21
|
|
22
22
|
Config::DEFAULTS.each { |option, value| config.stackify[option] = value }
|
@@ -26,9 +26,7 @@ module StackifyRubyAPM
|
|
26
26
|
initializer 'stackify_apm.initialize' do |app|
|
27
27
|
config = app.config.stackify.merge(app: app).tap do |c|
|
28
28
|
# Prepend Rails.root to log_path if present
|
29
|
-
if c.log_path && !c.log_path.start_with?('/')
|
30
|
-
c.log_path = Rails.root.join(c.log_path)
|
31
|
-
end
|
29
|
+
c.log_path = Rails.root.join(c.log_path) if c.log_path && !c.log_path.start_with?('/')
|
32
30
|
end
|
33
31
|
|
34
32
|
begin
|
@@ -43,7 +41,7 @@ module StackifyRubyAPM
|
|
43
41
|
end
|
44
42
|
|
45
43
|
config.after_initialize do
|
46
|
-
|
44
|
+
require 'stackify_apm/spies/action_dispatch'
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
# This will format the root information of the Transaction.
|
4
|
-
#
|
5
4
|
|
6
5
|
module StackifyRubyAPM
|
7
6
|
# @api private
|
@@ -11,13 +10,11 @@ module StackifyRubyAPM
|
|
11
10
|
@config = config
|
12
11
|
end
|
13
12
|
|
14
|
-
# rubocop:disable Metrics/MethodLength
|
15
|
-
# rubocop:disable Style/StringLiterals
|
16
13
|
def build
|
17
14
|
# get process id
|
18
15
|
pid = $PID || Process.pid
|
19
16
|
|
20
|
-
|
17
|
+
{
|
21
18
|
CATEGORY: 'Ruby',
|
22
19
|
APPLICATION_PATH: '/',
|
23
20
|
APPLICATION_FILESYSTEM_PATH: @config.root_path,
|
@@ -38,7 +35,6 @@ module StackifyRubyAPM
|
|
38
35
|
TRACE_VERSION: '2.0'
|
39
36
|
}
|
40
37
|
end
|
41
|
-
# rubocop:enable Metrics/MethodLength
|
42
38
|
|
43
39
|
def self.build(config, transaction)
|
44
40
|
new(config, transaction).build
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'json'
|
3
4
|
# After the spans are being build it will serialize or rebuild or reformat the spans created into json format
|
4
5
|
module StackifyRubyAPM
|
@@ -23,5 +24,5 @@ module StackifyRubyAPM
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
require '
|
27
|
-
require '
|
27
|
+
require 'stackify_apm/serializers/transactions'
|
28
|
+
require 'stackify_apm/serializers/errors'
|
@@ -1,30 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
# This module gathers the built Errors and Exceptions into hash formats
|
4
|
-
|
4
|
+
|
5
5
|
module StackifyRubyAPM
|
6
6
|
module Serializers
|
7
7
|
# @api private
|
8
8
|
class Errors < Serializer
|
9
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
10
9
|
def build(error)
|
11
|
-
|
12
10
|
if (exception = error.exception)
|
13
11
|
current_timestamp = error.timestamp
|
14
12
|
|
15
13
|
base = {
|
16
|
-
CaughtBy: exception.module,
|
14
|
+
CaughtBy: exception.module,
|
17
15
|
Exception: exception.type,
|
18
16
|
Message: exception.message,
|
19
|
-
Timestamp:
|
20
|
-
Frames: exception.stacktrace.to_a
|
17
|
+
Timestamp: current_timestamp.round.to_s,
|
18
|
+
Frames: exception.stacktrace.to_a
|
21
19
|
}
|
22
|
-
|
20
|
+
|
23
21
|
end
|
24
22
|
|
25
23
|
base
|
26
24
|
end
|
27
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
28
25
|
|
29
26
|
def build_all(errors)
|
30
27
|
{ exceptions: Array(errors).map(&method(:build)) }
|
@@ -43,4 +40,4 @@ module StackifyRubyAPM
|
|
43
40
|
end
|
44
41
|
end
|
45
42
|
end
|
46
|
-
end
|
43
|
+
end
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
# This class builds and reformats all the gathered spans within the transaction.
|
4
|
-
#
|
5
4
|
|
6
5
|
module StackifyRubyAPM
|
7
6
|
module Serializers
|
8
7
|
# @api private
|
9
|
-
|
10
8
|
class Transactions < Serializer
|
11
9
|
include Log
|
12
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
13
|
-
def build(config, transaction)
|
14
10
|
|
11
|
+
def build(config, transaction)
|
15
12
|
root_span_json = {
|
16
13
|
id: -1,
|
17
14
|
call: transaction.name,
|
@@ -24,7 +21,7 @@ module StackifyRubyAPM
|
|
24
21
|
|
25
22
|
# serialize all the spans
|
26
23
|
children_spans_json = []
|
27
|
-
transaction.spans.each
|
24
|
+
transaction.spans.each do |span|
|
28
25
|
children_spans_json.push(build_span(span))
|
29
26
|
end
|
30
27
|
|
@@ -37,20 +34,18 @@ module StackifyRubyAPM
|
|
37
34
|
# Add Children Spans to span_json
|
38
35
|
def add_children_spans(span_json, children_spans_json)
|
39
36
|
id = span_json[:id]
|
40
|
-
children_spans_json.each
|
37
|
+
children_spans_json.each do |child_span_json|
|
41
38
|
parent_id = child_span_json[:parent_id]
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
39
|
+
|
40
|
+
next unless parent_id == id
|
41
|
+
|
42
|
+
child_span_copy = child_span_json.dup
|
43
|
+
add_children_spans(child_span_copy, children_spans_json)
|
44
|
+
span_json[:stacks] = [] if span_json[:stacks].nil?
|
45
|
+
span_json[:stacks].push(child_span_copy)
|
50
46
|
end
|
51
47
|
end
|
52
48
|
|
53
|
-
# rubocop:disable Metrics/AbcSize
|
54
49
|
def build_span(span)
|
55
50
|
span_type = span.type
|
56
51
|
span_context = span.context && span.context.to_h
|
@@ -65,8 +60,6 @@ module StackifyRubyAPM
|
|
65
60
|
stacks: []
|
66
61
|
}
|
67
62
|
end
|
68
|
-
|
69
|
-
# rubocop:enable Metrics/AbcSize
|
70
63
|
end
|
71
64
|
end
|
72
65
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
4
|
# This modules creates and initializes new Span
|
4
5
|
#
|
5
6
|
|
6
7
|
require 'securerandom'
|
7
|
-
require '
|
8
|
+
require 'stackify_apm/span/context'
|
8
9
|
module StackifyRubyAPM
|
9
10
|
# @api private
|
10
11
|
class Span
|
@@ -36,21 +37,22 @@ module StackifyRubyAPM
|
|
36
37
|
attr_reader :id, :context, :stacktrace, :duration, :parent_id, :relative_start, :relative_end
|
37
38
|
|
38
39
|
def start
|
39
|
-
@relative_start =
|
40
|
+
@relative_start = Time.now.to_f * 1000
|
40
41
|
|
41
42
|
self
|
42
43
|
end
|
43
44
|
|
44
45
|
def done
|
45
|
-
@relative_end =
|
46
|
-
@duration =
|
46
|
+
@relative_end = Time.now.to_f * 1000
|
47
|
+
@duration = Time.now.to_f * 1000
|
47
48
|
self.original_backtrace = nil # release it
|
48
49
|
|
49
50
|
self
|
50
51
|
end
|
51
52
|
|
52
53
|
def done?
|
53
|
-
!!duration
|
54
|
+
# !!duration
|
55
|
+
!duration.nil?
|
54
56
|
end
|
55
57
|
|
56
58
|
def running?
|
@@ -63,8 +65,5 @@ module StackifyRubyAPM
|
|
63
65
|
" type:#{type.inspect}" \
|
64
66
|
'>'
|
65
67
|
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
68
|
end
|
70
|
-
end
|
69
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
4
|
# This module communicates and registers the additional or enabled outside library method
|
4
5
|
#
|
5
6
|
|
6
7
|
require 'forwardable'
|
7
|
-
require '
|
8
|
+
require 'stackify_apm/util/inflector'
|
8
9
|
|
9
10
|
module StackifyRubyAPM
|
10
11
|
# @api private
|
@@ -78,7 +79,7 @@ module Kernel
|
|
78
79
|
|
79
80
|
begin
|
80
81
|
StackifyRubyAPM::Spies.hook_into(path)
|
81
|
-
rescue
|
82
|
+
rescue StandardError => e
|
82
83
|
puts "Failed hooking into '#{path}'. Please report this at " \
|
83
84
|
'git@bitbucket.org:stackify/stackify-ruby-apm.git'
|
84
85
|
puts e.backtrace.join("\n")
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
# Monkey patch for the ActionDispatch::ShowExceptions class which handles exception events.
|
4
|
-
#
|
5
4
|
|
6
5
|
module StackifyRubyAPM
|
7
6
|
# @api private
|
@@ -10,7 +9,7 @@ module StackifyRubyAPM
|
|
10
9
|
class ActionDispatchSpy
|
11
10
|
def install
|
12
11
|
::ActionDispatch::ShowExceptions.class_eval do
|
13
|
-
|
12
|
+
alias_method 'render_exception_without_apm', 'render_exception'
|
14
13
|
|
15
14
|
def render_exception(env, exception)
|
16
15
|
# Creates exception log report
|
@@ -22,7 +21,7 @@ module StackifyRubyAPM
|
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
|
-
# Registers ActionDispatch spy, go to: /
|
24
|
+
# Registers ActionDispatch spy, go to: /stackify_apm/spies.rb
|
26
25
|
#
|
27
26
|
register(
|
28
27
|
'ActionDispatch::ShowExceptions',
|
@@ -0,0 +1,49 @@
|
|
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 CurbSpy
|
10
|
+
def install
|
11
|
+
Curl.module_eval do
|
12
|
+
singleton_class.send(:alias_method, :http_without_apm, :http)
|
13
|
+
def self.http(verb, url, _post_body = nil, _put_data = nil, &block)
|
14
|
+
req = nil
|
15
|
+
return http_without_apm(verb, url, _post_body = nil, _put_data = nil, &block) unless StackifyRubyAPM.current_transaction
|
16
|
+
# Data configuration
|
17
|
+
#
|
18
|
+
method = verb
|
19
|
+
uri = url.strip
|
20
|
+
name = "#{method} #{uri}"
|
21
|
+
type = "ext.Curb.#{method}"
|
22
|
+
# Submits HTTP request
|
23
|
+
#
|
24
|
+
req = http_without_apm(verb, url, _post_body = nil, _put_data = nil, &block)
|
25
|
+
# Builds span context
|
26
|
+
#
|
27
|
+
status_code = req.status.gsub(/^0-9/, '').to_i
|
28
|
+
|
29
|
+
ctx = Span::Context.new(
|
30
|
+
CATEGORY: 'Web External',
|
31
|
+
SUBCATEGORY: 'Execute',
|
32
|
+
URL: uri,
|
33
|
+
STATUS: status_code,
|
34
|
+
METHOD: method
|
35
|
+
)
|
36
|
+
# Creates new span from HTTP result
|
37
|
+
#
|
38
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
39
|
+
req
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# Registers CurbSpy spy, go to: /stackify/spies.rb
|
46
|
+
#
|
47
|
+
register 'Curl', 'curb', CurbSpy.new
|
48
|
+
end
|
49
|
+
end
|