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