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,20 +1,18 @@
1
1
  # frozen_string_literal: true
2
- #
2
+
3
3
  # Monkey patch for the Sinatra::Base class which is responsible for handling requests.
4
- #
5
4
 
6
5
  module StackifyRubyAPM
7
6
  # @api private
8
7
  module Spies
9
8
  # @api private
10
9
  class SinatraSpy
11
- # rubocop:disable Metrics/MethodLength
12
10
  def install
13
11
  ::Sinatra::Base.class_eval do
14
- alias dispatch_without_apm! dispatch!
15
- alias compile_template_without_apm compile_template
12
+ alias_method 'dispatch_without_apm!', 'dispatch!'
13
+ alias_method 'compile_template_without_apm', 'compile_template'
16
14
 
17
- # Sets transaction name from Sinatra env's route name
15
+ # Sets transaction name from Sinatra env's route name
18
16
  #
19
17
  def dispatch!(*args, &block)
20
18
  dispatch_without_apm!(*args, &block).tap do
@@ -25,7 +23,7 @@ module StackifyRubyAPM
25
23
  end
26
24
  end
27
25
 
28
- # Tilt engine template
26
+ # Tilt engine template
29
27
  #
30
28
  def compile_template(engine, data, opts, *args, &block)
31
29
  opts[:__stackify_apm_template_name] =
@@ -38,15 +36,14 @@ module StackifyRubyAPM
38
36
  end
39
37
  end
40
38
  end
41
- # rubocop:enable Metrics/MethodLength
42
39
  end
43
40
 
44
- # Registers Sinatra spy, go to: /stackify/spies.rb
41
+ # Registers Sinatra spy, go to: /stackify_apm/spies.rb
45
42
  #
46
43
  register 'Sinatra::Base', 'sinatra/base', SinatraSpy.new
47
44
 
48
45
  # Tilt template helper & span creator
49
46
  #
50
- require 'stackify/spies/tilt'
47
+ require 'stackify_apm/spies/tilt'
51
48
  end
52
49
  end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
+
5
+ module StackifyRubyAPM
6
+ # @api private
7
+ module Spies
8
+ # @api private
9
+ class MysqlAdapterSpy
10
+ TYPE = 'db.sinatra_active_record.sql'.freeze
11
+
12
+ if ActiveRecord::VERSION::MAJOR.to_i >= 5
13
+ def install
14
+ ActiveRecord::ConnectionAdapters::MySQL::DatabaseStatements.class_eval do
15
+ alias_method 'exec_query_without_apm', 'exec_query'
16
+ alias_method 'exec_delete_without_apm', 'exec_delete'
17
+ alias_method 'exec_update_without_apm', 'exec_update'
18
+
19
+ def exec_update(sql, name = nil, binds = [])
20
+ result = nil
21
+
22
+ unless StackifyRubyAPM.current_transaction
23
+ exec_update_without_apm(sql, name, binds)
24
+ end
25
+
26
+ ctx = Span::Context.new(
27
+ CATEGORY: 'Database',
28
+ SUBCATEGORY: 'Execute',
29
+ COMPONENT_CATEGORY: 'DB Query',
30
+ COMPONENT_DETAIL: 'Execute SQL Query',
31
+ SQL: sql,
32
+ PROVIDER: 'mysql'
33
+ )
34
+
35
+ result = exec_update_without_apm(sql, name, binds)
36
+
37
+ StackifyRubyAPM.span name, TYPE, context: ctx do
38
+ return result
39
+ end
40
+ end
41
+
42
+ def exec_delete(sql, name = nil, binds = [])
43
+ result = nil
44
+
45
+ unless StackifyRubyAPM.current_transaction
46
+ exec_delete_without_apm(sql, name, binds)
47
+ end
48
+
49
+ ctx = Span::Context.new(
50
+ CATEGORY: 'Database',
51
+ SUBCATEGORY: 'Execute',
52
+ COMPONENT_CATEGORY: 'DB Query',
53
+ COMPONENT_DETAIL: 'Execute SQL Query',
54
+ SQL: sql,
55
+ PROVIDER: 'mysql'
56
+ )
57
+
58
+ result = exec_delete_without_apm(sql, name, binds)
59
+
60
+ StackifyRubyAPM.span name, TYPE, context: ctx do
61
+ return result
62
+ end
63
+ end
64
+
65
+ # rubocop:disable Lint/UnusedMethodArgument
66
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
67
+ result = nil
68
+
69
+ unless StackifyRubyAPM.current_transaction
70
+ exec_query_without_apm(sql, name, binds)
71
+ end
72
+
73
+ ctx = Span::Context.new(
74
+ CATEGORY: 'Database',
75
+ SUBCATEGORY: 'Execute',
76
+ COMPONENT_CATEGORY: 'DB Query',
77
+ COMPONENT_DETAIL: 'Execute SQL Query',
78
+ SQL: sql,
79
+ PROVIDER: 'mysql'
80
+ )
81
+
82
+ result = exec_query_without_apm(sql, name, binds)
83
+
84
+ StackifyRubyAPM.span name, TYPE, context: ctx do
85
+ return result
86
+ end
87
+ end
88
+ # rubocop:enable Lint/UnusedMethodArgument
89
+ end
90
+ end
91
+ else
92
+ def install
93
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do
94
+ alias_method 'exec_query_without_apm', 'exec_query'
95
+ alias_method 'exec_delete_without_apm', 'exec_delete'
96
+ alias_method 'exec_update_without_apm', 'exec_update'
97
+ alias_method 'exec_insert_without_apm', 'exec_insert'
98
+
99
+ def exec_query(sql, name = 'SQL', binds = [], _prepare: false)
100
+ result = nil
101
+
102
+ unless StackifyRubyAPM.current_transaction
103
+ exec_query_without_apm(sql, name, binds)
104
+ end
105
+
106
+ ctx = Span::Context.new(
107
+ CATEGORY: 'Database',
108
+ SUBCATEGORY: 'Execute',
109
+ COMPONENT_CATEGORY: 'DB Query',
110
+ COMPONENT_DETAIL: 'Execute SQL Query',
111
+ SQL: sql,
112
+ PROVIDER: 'mysql'
113
+ )
114
+
115
+ result = exec_query_without_apm(sql, name, binds)
116
+
117
+ StackifyRubyAPM.span name, TYPE, context: ctx do
118
+ return result
119
+ end
120
+ end
121
+
122
+ def exec_delete(sql, name = nil, binds = [])
123
+ result = nil
124
+
125
+ unless StackifyRubyAPM.current_transaction
126
+ exec_delete_without_apm(sql, name, binds)
127
+ end
128
+
129
+ ctx = Span::Context.new(
130
+ CATEGORY: 'Database',
131
+ SUBCATEGORY: 'Execute',
132
+ COMPONENT_CATEGORY: 'DB Query',
133
+ COMPONENT_DETAIL: 'Execute SQL Query',
134
+ SQL: sql,
135
+ PROVIDER: 'mysql'
136
+ )
137
+
138
+ result = exec_delete_without_apm(sql, name, binds)
139
+
140
+ StackifyRubyAPM.span name, TYPE, context: ctx do
141
+ return result
142
+ end
143
+ end
144
+
145
+ def exec_update(sql, name, binds)
146
+ result = nil
147
+
148
+ unless StackifyRubyAPM.current_transaction
149
+ exec_update_without_apm(sql, name, binds)
150
+ end
151
+
152
+ ctx = Span::Context.new(
153
+ CATEGORY: 'Database',
154
+ SUBCATEGORY: 'Execute',
155
+ COMPONENT_CATEGORY: 'DB Query',
156
+ COMPONENT_DETAIL: 'Execute SQL Query',
157
+ SQL: sql,
158
+ PROVIDER: 'mysql'
159
+ )
160
+
161
+ result = exec_update_without_apm(sql, name, binds)
162
+
163
+ StackifyRubyAPM.span name, TYPE, context: ctx do
164
+ return result
165
+ end
166
+ end
167
+
168
+ def exec_insert(sql, name, binds, _pk = nil, _sequence_name = nil)
169
+ result = nil
170
+
171
+ unless StackifyRubyAPM.current_transaction
172
+ exec_insert_without_apm(sql, name, binds, _pk = nil, _sequence_name = nil)
173
+ end
174
+
175
+ ctx = Span::Context.new(
176
+ CATEGORY: 'Database',
177
+ SUBCATEGORY: 'Execute',
178
+ COMPONENT_CATEGORY: 'DB Query',
179
+ COMPONENT_DETAIL: 'Execute SQL Query',
180
+ SQL: sql,
181
+ PROVIDER: 'mysql'
182
+ )
183
+
184
+ result = exec_insert_without_apm(sql, name, binds, _pk = nil, _sequence_name = nil)
185
+
186
+ StackifyRubyAPM.span name, TYPE, context: ctx do
187
+ return result
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ if ActiveRecord::VERSION::MAJOR.to_i >= 5
196
+ register 'ActiveRecord::ConnectionAdapters::MySQL::DatabaseStatements', 'active_record/connection_adapters/mysql/database_statements', MysqlAdapterSpy.new
197
+ else
198
+ register 'ActiveRecord::ConnectionAdapters::Mysql2Adapter', 'active_record/connection_adapters/mysql2_adapter', MysqlAdapterSpy.new
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
+
5
+ module StackifyRubyAPM
6
+ # @api private
7
+ module Spies
8
+ # @api private
9
+ class PostgresqlAdapterSpy
10
+ TYPE = 'db.sinatra_active_record.sql'.freeze
11
+
12
+ def install
13
+ ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements.class_eval do
14
+ alias_method 'exec_query_without_apm', 'exec_query'
15
+ alias_method 'exec_delete_without_apm', 'exec_delete'
16
+ alias_method 'exec_update_without_apm', 'exec_update'
17
+
18
+ def exec_update(sql, name = nil, binds = [])
19
+ result = nil
20
+
21
+ unless StackifyRubyAPM.current_transaction
22
+ exec_update_without_apm(sql, name, binds)
23
+ end
24
+
25
+ ctx = Span::Context.new(
26
+ CATEGORY: 'Database',
27
+ SUBCATEGORY: 'Execute',
28
+ COMPONENT_CATEGORY: 'DB Query',
29
+ COMPONENT_DETAIL: 'Execute SQL Query',
30
+ SQL: sql,
31
+ PROVIDER: 'postgresql'
32
+ )
33
+
34
+ result = exec_update_without_apm(sql, name, binds)
35
+
36
+ StackifyRubyAPM.span name, TYPE, context: ctx do
37
+ return result
38
+ end
39
+ end
40
+
41
+ def exec_delete(sql, name = nil, binds = [])
42
+ result = nil
43
+
44
+ unless StackifyRubyAPM.current_transaction
45
+ exec_delete_without_apm(sql, name, binds)
46
+ end
47
+
48
+ ctx = Span::Context.new(
49
+ CATEGORY: 'Database',
50
+ SUBCATEGORY: 'Execute',
51
+ COMPONENT_CATEGORY: 'DB Query',
52
+ COMPONENT_DETAIL: 'Execute SQL Query',
53
+ SQL: sql,
54
+ PROVIDER: 'postgresql'
55
+ )
56
+
57
+ result = exec_delete_without_apm(sql, name, binds)
58
+
59
+ StackifyRubyAPM.span name, TYPE, context: ctx do
60
+ return result
61
+ end
62
+ end
63
+
64
+ # rubocop:disable Lint/UnusedMethodArgument
65
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
66
+ result = nil
67
+
68
+ unless StackifyRubyAPM.current_transaction
69
+ exec_query_without_apm(sql, name, binds)
70
+ end
71
+
72
+ ctx = Span::Context.new(
73
+ CATEGORY: 'Database',
74
+ SUBCATEGORY: 'Execute',
75
+ COMPONENT_CATEGORY: 'DB Query',
76
+ COMPONENT_DETAIL: 'Execute SQL Query',
77
+ SQL: sql,
78
+ PROVIDER: 'postgresql'
79
+ )
80
+
81
+ result = exec_query_without_apm(sql, name, binds)
82
+
83
+ StackifyRubyAPM.span name, TYPE, context: ctx do
84
+ return result
85
+ end
86
+ end
87
+ # rubocop:enable Lint/UnusedMethodArgument
88
+ end
89
+ end
90
+ end
91
+
92
+ register 'ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements', 'active_record/connection_adapters/postgresql/database_statements', PostgresqlAdapterSpy.new
93
+ end
94
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
+
5
+ module StackifyRubyAPM
6
+ # @api private
7
+ module Spies
8
+ # @api private
9
+ class SqliteAdapterSpy
10
+ TYPE = 'db.sinatra_active_record.sql'.freeze
11
+
12
+ def install
13
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.class_eval do
14
+ alias_method 'exec_query_without_apm', 'exec_query'
15
+
16
+ # rubocop:disable Lint/UnusedMethodArgument
17
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
18
+ result = nil
19
+
20
+ unless StackifyRubyAPM.current_transaction
21
+ exec_query_without_apm(sql, name, binds)
22
+ end
23
+
24
+ ctx = Span::Context.new(
25
+ CATEGORY: 'Database',
26
+ SUBCATEGORY: 'Execute',
27
+ COMPONENT_CATEGORY: 'DB Query',
28
+ COMPONENT_DETAIL: 'Execute SQL Query',
29
+ SQL: sql,
30
+ PROVIDER: 'generic'
31
+ )
32
+
33
+ result = exec_query_without_apm(sql, name, binds)
34
+
35
+ StackifyRubyAPM.span name, TYPE, context: ctx do
36
+ return result
37
+ end
38
+ end
39
+ # rubocop:enable Lint/UnusedMethodArgument
40
+ end
41
+ end
42
+ end
43
+
44
+ register 'ActiveRecord::ConnectionAdapters::SQLite3Adapter', 'active_record/connection_adapters/sqlite3_adapter', SqliteAdapterSpy.new
45
+ end
46
+ end
@@ -0,0 +1,60 @@
1
+ # Monkeypatch for the MsgObject to set the value id for Logging / Trace Linking
2
+ #
3
+ module StackifyRubyAPM
4
+ # @api private
5
+ module Spies
6
+ # @api private
7
+ class StackifyLoggerSpy
8
+ if defined? Stackify
9
+ ::Stackify::LoggerClient.class_eval do
10
+ require 'securerandom'
11
+ alias_method 'log_message_task_without_apm', 'log_message_task'
12
+ alias_method 'log_exception_task_without_apm', 'log_exception_task'
13
+ # set trans_id parameter on log message to be passed unto MsgObject
14
+ def log_message_task(level, msg, call_trace)
15
+ return log_message_task_without_apm(level, msg, call_trace) unless StackifyRubyAPM.current_transaction
16
+
17
+ trans_id = StackifyRubyAPM.current_transaction.id
18
+ log_uuid = SecureRandom.uuid
19
+
20
+ # build span context
21
+ ctx = Span::Context.new(
22
+ CATEGORY: 'Stackify',
23
+ SUBCATEGORY: 'Log',
24
+ ID: log_uuid # matching the MsgObject id
25
+ )
26
+
27
+ # create log span
28
+ StackifyRubyAPM.span(msg, 'stackify.log', context: ctx) do
29
+ log_message_task_without_apm(level, msg, call_trace, trans_id, log_uuid)
30
+ end
31
+ end
32
+
33
+ # set trans_id parameter on log exception to be passed unto MsgObject
34
+ def log_exception_task(level, ex)
35
+ return log_exception_task_without_apm(level, ex) unless StackifyRubyAPM.current_transaction
36
+
37
+ trans_id = StackifyRubyAPM.agent.current_transaction.id
38
+ log_uuid = SecureRandom.uuid
39
+
40
+ # build span context
41
+ ctx = Span::Context.new(
42
+ CATEGORY: 'Stackify',
43
+ SUBCATEGORY: 'Log',
44
+ ID: log_uuid # matching the MsgObject id
45
+ )
46
+
47
+ # create log span
48
+ StackifyRubyAPM.span(ex.message, 'stackify.log', context: ctx) do
49
+ log_exception_task_without_apm(level, ex, trans_id, log_uuid)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Registers StackifyLogger spy, go to: /stackify_apm/spies.rb
57
+ #
58
+ register 'StackifyLogger', 'stackifylogger', StackifyLoggerSpy.new if defined? Stackify
59
+ end
60
+ end