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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +38 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +17 -11
  5. data/Gemfile.lock +98 -95
  6. data/Rakefile +7 -5
  7. data/docker/stackify-ruby +8 -0
  8. data/docker/stackify-ruby-rvm +10 -0
  9. data/docker/stackify-ruby-test +28 -0
  10. data/lib/{stackify → stackify_apm}/agent.rb +42 -33
  11. data/lib/{stackify → stackify_apm}/config.rb +56 -39
  12. data/lib/{stackify → stackify_apm}/context.rb +5 -6
  13. data/lib/{stackify → stackify_apm}/context/request.rb +0 -0
  14. data/lib/{stackify → stackify_apm}/context/request/socket.rb +0 -0
  15. data/lib/{stackify → stackify_apm}/context/request/url.rb +2 -6
  16. data/lib/stackify_apm/context/response.rb +33 -0
  17. data/lib/{stackify → stackify_apm}/context_builder.rb +2 -5
  18. data/lib/{stackify → stackify_apm}/error.rb +7 -6
  19. data/lib/stackify_apm/error/exception.rb +37 -0
  20. data/lib/stackify_apm/error/log.rb +24 -0
  21. data/lib/stackify_apm/error_builder.rb +61 -0
  22. data/lib/stackify_apm/helper/database_helper.rb +27 -0
  23. data/lib/{stackify → stackify_apm}/instrumenter.rb +12 -19
  24. data/lib/{stackify → stackify_apm}/internal_error.rb +0 -0
  25. data/lib/{stackify → stackify_apm}/log.rb +0 -0
  26. data/lib/{stackify → stackify_apm}/logger/log_device.rb +22 -11
  27. data/lib/{stackify → stackify_apm}/logger/logger_high_version.rb +1 -6
  28. data/lib/{stackify → stackify_apm}/logger/logger_lower_version.rb +2 -1
  29. data/lib/stackify_apm/middleware.rb +70 -0
  30. data/lib/{stackify → stackify_apm}/naively_hashable.rb +1 -3
  31. data/lib/{stackify → stackify_apm}/normalizers.rb +3 -2
  32. data/lib/{stackify → stackify_apm}/normalizers/action_controller.rb +0 -0
  33. data/lib/{stackify → stackify_apm}/normalizers/action_mailer.rb +0 -0
  34. data/lib/{stackify → stackify_apm}/normalizers/action_view.rb +0 -0
  35. data/lib/{stackify → stackify_apm}/normalizers/active_record.rb +3 -25
  36. data/lib/{stackify → stackify_apm}/railtie.rb +5 -7
  37. data/lib/{stackify → stackify_apm}/root_info.rb +2 -6
  38. data/lib/{stackify → stackify_apm}/serializers.rb +3 -2
  39. data/lib/{stackify → stackify_apm}/serializers/errors.rb +7 -10
  40. data/lib/{stackify → stackify_apm}/serializers/transactions.rb +11 -18
  41. data/lib/{stackify → stackify_apm}/span.rb +8 -9
  42. data/lib/{stackify → stackify_apm}/span/context.rb +3 -1
  43. data/lib/{stackify → stackify_apm}/spies.rb +3 -2
  44. data/lib/{stackify → stackify_apm}/spies/action_dispatch.rb +3 -4
  45. data/lib/stackify_apm/spies/curb.rb +49 -0
  46. data/lib/stackify_apm/spies/curb/easy.rb +157 -0
  47. data/lib/stackify_apm/spies/curb/multi.rb +43 -0
  48. data/lib/{stackify → stackify_apm}/spies/httpclient.rb +10 -8
  49. data/lib/{stackify → stackify_apm}/spies/httprb.rb +7 -9
  50. data/lib/{stackify → stackify_apm}/spies/mongo.rb +5 -3
  51. data/lib/{stackify → stackify_apm}/spies/net_http.rb +4 -5
  52. data/lib/{stackify → stackify_apm}/spies/redis.rb +19 -18
  53. data/lib/stackify_apm/spies/sequel.rb +65 -0
  54. data/lib/{stackify → stackify_apm}/spies/sinatra.rb +7 -10
  55. data/lib/stackify_apm/spies/sinatra_activerecord/mysql_adapter.rb +201 -0
  56. data/lib/stackify_apm/spies/sinatra_activerecord/postgresql_adapter.rb +94 -0
  57. data/lib/stackify_apm/spies/sinatra_activerecord/sqlite_adapter.rb +46 -0
  58. data/lib/stackify_apm/spies/stackify_logger.rb +60 -0
  59. data/lib/{stackify → stackify_apm}/spies/tilt.rb +3 -3
  60. data/lib/stackify_apm/stacktrace.rb +18 -0
  61. data/lib/stackify_apm/stacktrace/frame.rb +47 -0
  62. data/lib/{stackify → stackify_apm}/stacktrace_builder.rb +10 -11
  63. data/lib/{stackify → stackify_apm}/subscriber.rb +20 -14
  64. data/lib/{stackify → stackify_apm}/trace_logger.rb +10 -16
  65. data/lib/stackify_apm/transaction.rb +127 -0
  66. data/lib/{stackify → stackify_apm}/util.rb +3 -1
  67. data/lib/{stackify → stackify_apm}/util/dig.rb +1 -1
  68. data/lib/{stackify → stackify_apm}/util/inflector.rb +0 -0
  69. data/lib/{stackify → stackify_apm}/util/inspector.rb +1 -3
  70. data/lib/stackify_apm/util/lru_cache.rb +49 -0
  71. data/lib/stackify_apm/util/trace_log_watcher.rb +37 -0
  72. data/lib/stackify_apm/version.rb +6 -0
  73. data/lib/{stackify → stackify_apm}/worker.rb +8 -7
  74. data/lib/stackify_ruby_apm.rb +18 -15
  75. data/run-test-docker.sh +50 -0
  76. data/run-test.sh +1 -3
  77. data/stackify-ruby-apm.gemspec +14 -11
  78. metadata +86 -59
  79. data/lib/stackify/context/response.rb +0 -37
  80. data/lib/stackify/error/exception.rb +0 -36
  81. data/lib/stackify/error/log.rb +0 -25
  82. data/lib/stackify/error_builder.rb +0 -65
  83. data/lib/stackify/middleware.rb +0 -74
  84. data/lib/stackify/spies/sinatra_activerecord/mysql_adapter.rb +0 -177
  85. data/lib/stackify/spies/sinatra_activerecord/postgresql_adapter.rb +0 -96
  86. data/lib/stackify/spies/sinatra_activerecord/sqlite_adapter.rb +0 -48
  87. data/lib/stackify/stacktrace.rb +0 -19
  88. data/lib/stackify/stacktrace/frame.rb +0 -50
  89. data/lib/stackify/transaction.rb +0 -132
  90. data/lib/stackify/util/lru_cache.rb +0 -49
  91. 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 "stackify/normalizers/#{lib}"
69
+ require "stackify_apm/normalizers/#{lib}"
69
70
  end
70
71
  end
@@ -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 "[SqlNormalizer] query_variables payload:"
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 stackify/config.rb
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 'stackify/subscriber'
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
- require 'stackify/spies/action_dispatch'
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
- base = {
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 'stackify/serializers/transactions'
27
- require 'stackify/serializers/errors'
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: "#{current_timestamp.round}",
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 do |span|
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 do |child_span_json|
37
+ children_spans_json.each do |child_span_json|
41
38
  parent_id = child_span_json[:parent_id]
42
- if parent_id == id
43
- child_span_copy = child_span_json.dup
44
- add_children_spans(child_span_copy, children_spans_json)
45
- if span_json[:stacks].nil?
46
- span_json[:stacks] = []
47
- end
48
- span_json[:stacks].push(child_span_copy)
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 'stackify/span/context'
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 = (Time.now).to_f * 1000
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 = (Time.now).to_f * 1000
46
- @duration = (Time.now).to_f * 1000
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,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module StackifyRubyAPM
3
4
  class Span
4
5
  # @api private
@@ -24,7 +25,8 @@ module StackifyRubyAPM
24
25
  :OPERATION,
25
26
  :CACHEKEY,
26
27
  :CACHENAME,
27
- :THREAD_ID
28
+ :THREAD_ID,
29
+ :ID
28
30
  end
29
31
  end
30
32
  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 'stackify/util/inflector'
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 ::Exception => e
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
- alias render_exception_without_apm render_exception
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: /stackify/spies.rb
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