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.
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