scout_apm 2.6.10 → 3.0.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.rubocop.yml +3 -11
  4. data/CHANGELOG.markdown +4 -362
  5. data/Gemfile +1 -14
  6. data/README.markdown +7 -52
  7. data/Rakefile +1 -0
  8. data/ext/allocations/allocations.c +1 -7
  9. data/ext/allocations/extconf.rb +0 -1
  10. data/ext/rusage/rusage.c +0 -26
  11. data/ext/stacks/extconf.rb +37 -0
  12. data/ext/stacks/scout_atomics.h +86 -0
  13. data/ext/stacks/stacks.c +811 -0
  14. data/lib/scout_apm/agent/logging.rb +69 -0
  15. data/lib/scout_apm/agent/reporting.rb +126 -0
  16. data/lib/scout_apm/agent.rb +259 -138
  17. data/lib/scout_apm/app_server_load.rb +15 -41
  18. data/lib/scout_apm/attribute_arranger.rb +3 -14
  19. data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -70
  20. data/lib/scout_apm/background_job_integrations/sidekiq.rb +24 -31
  21. data/lib/scout_apm/background_worker.rb +12 -23
  22. data/lib/scout_apm/capacity.rb +57 -0
  23. data/lib/scout_apm/config.rb +37 -206
  24. data/lib/scout_apm/context.rb +4 -20
  25. data/lib/scout_apm/deploy_integrations/capistrano_2.cap +12 -0
  26. data/lib/scout_apm/deploy_integrations/capistrano_2.rb +83 -0
  27. data/lib/scout_apm/deploy_integrations/capistrano_3.cap +12 -0
  28. data/lib/scout_apm/deploy_integrations/capistrano_3.rb +88 -0
  29. data/lib/scout_apm/environment.rb +28 -42
  30. data/lib/scout_apm/fake_store.rb +0 -12
  31. data/lib/scout_apm/framework_integrations/rails_2.rb +1 -2
  32. data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +6 -17
  33. data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
  34. data/lib/scout_apm/histogram.rb +3 -12
  35. data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
  36. data/lib/scout_apm/instant/middleware.rb +54 -202
  37. data/lib/scout_apm/instant_reporting.rb +7 -7
  38. data/lib/scout_apm/instruments/.DS_Store +0 -0
  39. data/lib/scout_apm/instruments/action_controller_rails_2.rb +9 -15
  40. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +76 -124
  41. data/lib/scout_apm/instruments/active_record.rb +29 -324
  42. data/lib/scout_apm/instruments/delayed_job.rb +57 -0
  43. data/lib/scout_apm/instruments/elasticsearch.rb +6 -10
  44. data/lib/scout_apm/instruments/grape.rb +9 -12
  45. data/lib/scout_apm/instruments/http_client.rb +7 -14
  46. data/lib/scout_apm/instruments/influxdb.rb +6 -10
  47. data/lib/scout_apm/instruments/middleware_detailed.rb +11 -15
  48. data/lib/scout_apm/instruments/middleware_summary.rb +5 -11
  49. data/lib/scout_apm/instruments/mongoid.rb +8 -39
  50. data/lib/scout_apm/instruments/moped.rb +6 -11
  51. data/lib/scout_apm/instruments/net_http.rb +9 -27
  52. data/lib/scout_apm/instruments/percentile_sampler.rb +23 -42
  53. data/lib/scout_apm/instruments/process/process_cpu.rb +6 -11
  54. data/lib/scout_apm/instruments/process/process_memory.rb +12 -17
  55. data/lib/scout_apm/instruments/rails_router.rb +6 -12
  56. data/lib/scout_apm/instruments/redis.rb +6 -10
  57. data/lib/scout_apm/instruments/sinatra.rb +4 -5
  58. data/lib/scout_apm/job_record.rb +2 -4
  59. data/lib/scout_apm/layaway.rb +34 -88
  60. data/lib/scout_apm/layaway_file.rb +3 -13
  61. data/lib/scout_apm/layer.rb +60 -25
  62. data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +6 -7
  63. data/lib/scout_apm/layer_converters/converter_base.rb +14 -203
  64. data/lib/scout_apm/layer_converters/depth_first_walker.rb +10 -22
  65. data/lib/scout_apm/layer_converters/error_converter.rb +8 -8
  66. data/lib/scout_apm/layer_converters/job_converter.rb +50 -37
  67. data/lib/scout_apm/layer_converters/metric_converter.rb +19 -18
  68. data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +13 -13
  69. data/lib/scout_apm/layer_converters/slow_job_converter.rb +116 -52
  70. data/lib/scout_apm/layer_converters/slow_request_converter.rb +120 -51
  71. data/lib/scout_apm/metric_meta.rb +5 -0
  72. data/lib/scout_apm/metric_set.rb +1 -9
  73. data/lib/scout_apm/metric_stats.rb +8 -7
  74. data/lib/scout_apm/middleware.rb +9 -7
  75. data/lib/scout_apm/reporter.rb +24 -71
  76. data/lib/scout_apm/request_histograms.rb +0 -12
  77. data/lib/scout_apm/request_manager.rb +7 -5
  78. data/lib/scout_apm/scored_item_set.rb +0 -7
  79. data/lib/scout_apm/serializers/app_server_load_serializer.rb +0 -4
  80. data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
  81. data/lib/scout_apm/serializers/directive_serializer.rb +0 -4
  82. data/lib/scout_apm/serializers/payload_serializer.rb +4 -11
  83. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +16 -35
  84. data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
  85. data/lib/scout_apm/server_integrations/passenger.rb +1 -1
  86. data/lib/scout_apm/server_integrations/puma.rb +2 -5
  87. data/lib/scout_apm/slow_job_policy.rb +13 -25
  88. data/lib/scout_apm/slow_job_record.rb +4 -13
  89. data/lib/scout_apm/slow_request_policy.rb +13 -25
  90. data/lib/scout_apm/slow_transaction.rb +5 -25
  91. data/lib/scout_apm/store.rb +32 -99
  92. data/lib/scout_apm/trace_compactor.rb +312 -0
  93. data/lib/scout_apm/tracer.rb +31 -35
  94. data/lib/scout_apm/tracked_request.rb +95 -262
  95. data/lib/scout_apm/utils/active_record_metric_name.rb +13 -88
  96. data/lib/scout_apm/utils/backtrace_parser.rb +4 -7
  97. data/lib/scout_apm/utils/fake_stacks.rb +87 -0
  98. data/lib/scout_apm/utils/installed_gems.rb +3 -7
  99. data/lib/scout_apm/utils/klass_helper.rb +2 -8
  100. data/lib/scout_apm/utils/null_logger.rb +13 -0
  101. data/lib/scout_apm/utils/sql_sanitizer.rb +5 -16
  102. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +0 -7
  103. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +0 -6
  104. data/lib/scout_apm/utils/unique_id.rb +0 -27
  105. data/lib/scout_apm/version.rb +2 -1
  106. data/lib/scout_apm.rb +25 -84
  107. data/scout_apm.gemspec +3 -17
  108. data/test/test_helper.rb +3 -57
  109. data/test/unit/agent_test.rb +54 -1
  110. data/test/unit/background_job_integrations/sidekiq_test.rb +3 -0
  111. data/test/unit/config_test.rb +12 -25
  112. data/test/unit/context_test.rb +4 -4
  113. data/test/unit/histogram_test.rb +4 -25
  114. data/test/unit/ignored_uris_test.rb +1 -1
  115. data/test/unit/instruments/active_record_instruments_test.rb +5 -0
  116. data/test/unit/layaway_test.rb +2 -62
  117. data/test/unit/serializers/payload_serializer_test.rb +15 -43
  118. data/test/unit/slow_request_policy_test.rb +6 -15
  119. data/test/unit/sql_sanitizer_test.rb +6 -53
  120. data/test/unit/store_test.rb +4 -73
  121. data/test/unit/utils/active_record_metric_name_test.rb +5 -59
  122. data/test/unit/utils/backtrace_parser_test.rb +1 -6
  123. data/tester.rb +53 -0
  124. metadata +28 -229
  125. data/.travis.yml +0 -26
  126. data/Guardfile +0 -43
  127. data/gems/README.md +0 -28
  128. data/gems/octoshark.gemfile +0 -4
  129. data/gems/rails3.gemfile +0 -5
  130. data/gems/rails4.gemfile +0 -4
  131. data/gems/rails5.gemfile +0 -4
  132. data/gems/rails6.gemfile +0 -4
  133. data/lib/scout_apm/agent/exit_handler.rb +0 -65
  134. data/lib/scout_apm/agent/preconditions.rb +0 -81
  135. data/lib/scout_apm/agent_context.rb +0 -261
  136. data/lib/scout_apm/auto_instrument/instruction_sequence.rb +0 -31
  137. data/lib/scout_apm/auto_instrument/layer.rb +0 -23
  138. data/lib/scout_apm/auto_instrument/parser.rb +0 -27
  139. data/lib/scout_apm/auto_instrument/rails.rb +0 -175
  140. data/lib/scout_apm/auto_instrument.rb +0 -5
  141. data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +0 -55
  142. data/lib/scout_apm/background_job_integrations/que.rb +0 -134
  143. data/lib/scout_apm/background_job_integrations/resque.rb +0 -88
  144. data/lib/scout_apm/background_job_integrations/shoryuken.rb +0 -124
  145. data/lib/scout_apm/background_job_integrations/sneakers.rb +0 -87
  146. data/lib/scout_apm/background_recorder.rb +0 -48
  147. data/lib/scout_apm/db_query_metric_set.rb +0 -97
  148. data/lib/scout_apm/db_query_metric_stats.rb +0 -102
  149. data/lib/scout_apm/debug.rb +0 -37
  150. data/lib/scout_apm/detailed_trace.rb +0 -217
  151. data/lib/scout_apm/error.rb +0 -27
  152. data/lib/scout_apm/error_service/error_buffer.rb +0 -39
  153. data/lib/scout_apm/error_service/error_record.rb +0 -211
  154. data/lib/scout_apm/error_service/ignored_exceptions.rb +0 -66
  155. data/lib/scout_apm/error_service/middleware.rb +0 -32
  156. data/lib/scout_apm/error_service/notifier.rb +0 -33
  157. data/lib/scout_apm/error_service/payload.rb +0 -47
  158. data/lib/scout_apm/error_service/periodic_work.rb +0 -17
  159. data/lib/scout_apm/error_service/railtie.rb +0 -11
  160. data/lib/scout_apm/error_service/sidekiq.rb +0 -80
  161. data/lib/scout_apm/error_service.rb +0 -32
  162. data/lib/scout_apm/extensions/config.rb +0 -87
  163. data/lib/scout_apm/extensions/transaction_callback_payload.rb +0 -74
  164. data/lib/scout_apm/git_revision.rb +0 -59
  165. data/lib/scout_apm/instrument_manager.rb +0 -88
  166. data/lib/scout_apm/instruments/action_view.rb +0 -141
  167. data/lib/scout_apm/instruments/http.rb +0 -48
  168. data/lib/scout_apm/instruments/memcached.rb +0 -43
  169. data/lib/scout_apm/instruments/resque.rb +0 -39
  170. data/lib/scout_apm/instruments/samplers.rb +0 -11
  171. data/lib/scout_apm/layer_children_set.rb +0 -86
  172. data/lib/scout_apm/layer_converters/database_converter.rb +0 -70
  173. data/lib/scout_apm/layer_converters/find_layer_by_type.rb +0 -38
  174. data/lib/scout_apm/layer_converters/histograms.rb +0 -15
  175. data/lib/scout_apm/layer_converters/trace_converter.rb +0 -184
  176. data/lib/scout_apm/limited_layer.rb +0 -126
  177. data/lib/scout_apm/logger.rb +0 -158
  178. data/lib/scout_apm/periodic_work.rb +0 -47
  179. data/lib/scout_apm/rack.rb +0 -26
  180. data/lib/scout_apm/remote/message.rb +0 -27
  181. data/lib/scout_apm/remote/recorder.rb +0 -57
  182. data/lib/scout_apm/remote/router.rb +0 -49
  183. data/lib/scout_apm/remote/server.rb +0 -60
  184. data/lib/scout_apm/reporting.rb +0 -143
  185. data/lib/scout_apm/serializers/db_query_serializer_to_json.rb +0 -15
  186. data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
  187. data/lib/scout_apm/synchronous_recorder.rb +0 -30
  188. data/lib/scout_apm/tasks/doctor.rb +0 -75
  189. data/lib/scout_apm/tasks/support.rb +0 -22
  190. data/lib/scout_apm/transaction.rb +0 -13
  191. data/lib/scout_apm/transaction_time_consumed.rb +0 -51
  192. data/lib/scout_apm/utils/gzip_helper.rb +0 -24
  193. data/lib/scout_apm/utils/marshal_logging.rb +0 -90
  194. data/lib/scout_apm/utils/numbers.rb +0 -14
  195. data/lib/scout_apm/utils/scm.rb +0 -14
  196. data/lib/tasks/doctor.rake +0 -11
  197. data/test/tmp/README.md +0 -17
  198. data/test/unit/agent_context_test.rb +0 -15
  199. data/test/unit/auto_instrument/assignments-instrumented.rb +0 -31
  200. data/test/unit/auto_instrument/assignments.rb +0 -31
  201. data/test/unit/auto_instrument/controller-ast.txt +0 -57
  202. data/test/unit/auto_instrument/controller-instrumented.rb +0 -49
  203. data/test/unit/auto_instrument/controller.rb +0 -49
  204. data/test/unit/auto_instrument/rescue_from-instrumented.rb +0 -13
  205. data/test/unit/auto_instrument/rescue_from.rb +0 -13
  206. data/test/unit/auto_instrument_test.rb +0 -54
  207. data/test/unit/db_query_metric_set_test.rb +0 -67
  208. data/test/unit/db_query_metric_stats_test.rb +0 -113
  209. data/test/unit/error_service/error_buffer_test.rb +0 -25
  210. data/test/unit/error_service/ignored_exceptions_test.rb +0 -49
  211. data/test/unit/extensions/periodic_callbacks_test.rb +0 -58
  212. data/test/unit/extensions/transaction_callbacks_test.rb +0 -58
  213. data/test/unit/fake_store_test.rb +0 -10
  214. data/test/unit/git_revision_test.rb +0 -15
  215. data/test/unit/instruments/active_record_test.rb +0 -40
  216. data/test/unit/instruments/net_http_test.rb +0 -27
  217. data/test/unit/instruments/percentile_sampler_test.rb +0 -133
  218. data/test/unit/layer_children_set_test.rb +0 -97
  219. data/test/unit/layer_converters/depth_first_walker_test.rb +0 -70
  220. data/test/unit/layer_converters/metric_converter_test.rb +0 -22
  221. data/test/unit/layer_converters/stubs.rb +0 -33
  222. data/test/unit/limited_layer_test.rb +0 -53
  223. data/test/unit/logger_test.rb +0 -69
  224. data/test/unit/remote/test_message.rb +0 -13
  225. data/test/unit/remote/test_router.rb +0 -33
  226. data/test/unit/remote/test_server.rb +0 -15
  227. data/test/unit/request_histograms_test.rb +0 -17
  228. data/test/unit/tracer_test.rb +0 -76
  229. data/test/unit/tracked_request_test.rb +0 -71
  230. data/test/unit/transaction_test.rb +0 -14
  231. data/test/unit/transaction_time_consumed_test.rb +0 -46
  232. data/test/unit/utils/numbers_test.rb +0 -15
  233. data/test/unit/utils/scm.rb +0 -17
@@ -1,211 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- # Converts the raw error data captured into the captured data, and holds it
4
- # until it's ready to be reported.
5
- class ErrorRecord
6
- attr_reader :exception_class
7
- attr_reader :message
8
- attr_reader :request_uri
9
- attr_reader :request_params
10
- attr_reader :request_session
11
- attr_reader :environment
12
- attr_reader :trace
13
- attr_reader :request_components
14
- attr_reader :context
15
-
16
- def initialize(agent_context, exception, env, context=nil)
17
- @agent_context = agent_context
18
-
19
- @context = if context
20
- context.to_hash
21
- else
22
- {}
23
- end
24
-
25
- @exception_class = LengthLimit.new(exception.class.name).to_s
26
- @message = LengthLimit.new(exception.message, 100).to_s
27
- @request_uri = LengthLimit.new(rack_request_url(env), 200).to_s
28
- @request_params = clean_params(env["action_dispatch.request.parameters"])
29
- @request_session = clean_params(session_data(env))
30
- @environment = clean_params(strip_env(env))
31
- @trace = clean_backtrace(exception.backtrace)
32
- @request_components = components(env)
33
- end
34
-
35
- # TODO: This is rails specific
36
- def components(env)
37
- components = {}
38
- unless env["action_dispatch.request.parameters"].nil?
39
- components[:controller] = env["action_dispatch.request.parameters"][:controller] || nil
40
- components[:action] = env["action_dispatch.request.parameters"][:action] || nil
41
- components[:module] = env["action_dispatch.request.parameters"][:module] || nil
42
- end
43
-
44
- # For background workers like sidekiq
45
- # TODO: extract data creation for background jobs
46
- components[:controller] ||= env[:custom_controller]
47
-
48
- components
49
- end
50
-
51
- # TODO: Can I use the same thing we use in traces?
52
- def rack_request_url(env)
53
- protocol = rack_scheme(env)
54
- protocol = protocol.nil? ? "" : "#{protocol}://"
55
-
56
- host = env["SERVER_NAME"] || ""
57
- path = env["REQUEST_URI"] || ""
58
- port = env["SERVER_PORT"] || "80"
59
- port = ["80", "443"].include?(port.to_s) ? "" : ":#{port}"
60
-
61
- protocol.to_s + host.to_s + port.to_s + path.to_s
62
- end
63
-
64
- def rack_scheme(env)
65
- if env["HTTPS"] == "on"
66
- "https"
67
- elsif env["HTTP_X_FORWARDED_PROTO"]
68
- env["HTTP_X_FORWARDED_PROTO"].split(",")[0]
69
- else
70
- env["rack.url_scheme"]
71
- end
72
- end
73
-
74
- # TODO: This name is too vague
75
- def clean_params(params)
76
- return if params.nil?
77
-
78
- normalized = normalize_data(params)
79
- filter_params(normalized)
80
- end
81
-
82
- # TODO: When was backtrace_cleaner introduced?
83
- def clean_backtrace(backtrace)
84
- if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
85
- Rails.backtrace_cleaner.send(:filter, backtrace)
86
- else
87
- backtrace
88
- end
89
- end
90
-
91
- # Deletes params from env
92
- #
93
- # These are not configurable, and will leak PII info up to Scout if
94
- # allowed through. Things like specific parameters can be exposed with
95
- # the ScoutApm::Context interface.
96
- KEYS_TO_REMOVE = [
97
- "rack.request.form_hash",
98
- "rack.request.form_vars",
99
- "async.callback",
100
-
101
- # Security related items
102
- "action_dispatch.secret_key_base",
103
- "action_dispatch.http_auth_salt",
104
- "action_dispatch.signed_cookie_salt",
105
- "action_dispatch.encrypted_cookie_salt",
106
- "action_dispatch.encrypted_signed_cookie_salt",
107
- "action_dispatch.authenticated_encrypted_cookie_salt",
108
-
109
- # Raw data from the URL & parameters. Would bypass our normal params filtering
110
- "QUERY_STRING",
111
- "REQUEST_URI",
112
- "REQUEST_PATH",
113
- "ORIGINAL_FULLPATH",
114
- "action_dispatch.request.query_parameters",
115
- "action_dispatch.request.parameters",
116
- "rack.request.query_string",
117
- "rack.request.query_hash",
118
- ]
119
- def strip_env(env)
120
- env.reject { |k, v| KEYS_TO_REMOVE.include?(k) }
121
- end
122
-
123
- def session_data(env)
124
- session = env["action_dispatch.request.session"]
125
- return if session.nil?
126
-
127
- if session.respond_to?(:to_hash)
128
- session.to_hash
129
- else
130
- session.data
131
- end
132
- end
133
-
134
- # TODO: Rename and make this clearer. I think it maps over the whole tree of a hash, and to_s each leaf node?
135
- def normalize_data(hash)
136
- new_hash = {}
137
-
138
- hash.each do |key, value|
139
- if value.respond_to?(:to_hash)
140
- begin
141
- new_hash[key] = normalize_data(value.to_hash)
142
- rescue
143
- new_hash[key] = LengthLimit.new(value.to_s).to_s
144
- end
145
- else
146
- new_hash[key] = LengthLimit.new(value.to_s).to_s
147
- end
148
- end
149
-
150
- new_hash
151
- end
152
-
153
- ###################
154
- # Filtering Params
155
- ###################
156
-
157
- # Replaces parameter values with a string / set in config file
158
- def filter_params(params)
159
- return params unless filtered_params_config
160
-
161
- params.each do |k, v|
162
- if filter_key?(k)
163
- params[k] = "[FILTERED]"
164
- elsif v.respond_to?(:to_hash)
165
- filter_params(params[k])
166
- end
167
- end
168
-
169
- params
170
- end
171
-
172
- # Check, if a key should be filtered
173
- def filter_key?(key)
174
- params_to_filter.any? do |filter|
175
- key.to_s == filter.to_s # key.to_s.include?(filter.to_s)
176
- end
177
- end
178
-
179
- def params_to_filter
180
- @params_to_filter ||= filtered_params_config + rails_filtered_params
181
- end
182
-
183
- # Accessor for the filtered params config value. Will be removed as we refactor and clean up this code.
184
- # TODO: Flip this over to use a new class like filtered exceptions?
185
- def filtered_params_config
186
- @agent_context.config.value("errors_filtered_params")
187
- end
188
-
189
- def rails_filtered_params
190
- return [] unless defined?(Rails)
191
- Rails.configuration.filter_parameters
192
- rescue
193
- []
194
- end
195
-
196
- class LengthLimit
197
- attr_reader :text
198
- attr_reader :char_limit
199
-
200
- def initialize(text, char_limit=100)
201
- @text = text
202
- @char_limit = char_limit
203
- end
204
-
205
- def to_s
206
- text[0..char_limit]
207
- end
208
- end
209
- end
210
- end
211
- end
@@ -1,66 +0,0 @@
1
- # Encapsulates the management and checking of ignored exceptions. Allows using
2
- # string matches on the class name, or arbitrary matching with a callback
3
- module ScoutApm
4
- module ErrorService
5
- class IgnoredExceptions
6
- attr_reader :ignored_exceptions
7
- attr_reader :blocks
8
-
9
- def initialize(context, from_config)
10
- @context = context
11
- @ignored_exceptions = Array(from_config).map{ |e| normalize_as_klass(e) }
12
- @blocks = []
13
- end
14
-
15
- # Add a single ignored exception by class name
16
- def add(klass_or_str)
17
- @ignored_exceptions << normalize_as_klass(klass_or_str)
18
- end
19
-
20
- # Add a callback block that will be called on every error. If it returns
21
- # Signature of blocks: ->(exception object): truthy or falsy value
22
- def add_callback(&block)
23
- @blocks << block
24
- end
25
-
26
- def ignored?(exception_object)
27
- klass = normalize_as_klass(exception_object)
28
-
29
- # Check if we ignored this error by name (typical way to ignore)
30
- if ignored_exceptions.any? { |ignored| klass.ancestors.include?(ignored) }
31
- return true
32
- end
33
-
34
- # For each block, see if it says we should ignore this error
35
- blocks.each do |b|
36
- if b.call(exception_object)
37
- return true
38
- end
39
- end
40
-
41
- false
42
- end
43
-
44
- private
45
-
46
- def normalize_as_klass(klass_or_str)
47
- if Module === klass_or_str
48
- return klass_or_str
49
- end
50
-
51
- if klass_or_str.is_a?(Exception)
52
- return klass_or_str.class
53
- end
54
-
55
- if String === klass_or_str
56
- maybe = ScoutApm::Utils::KlassHelper.lookup(klass_or_str)
57
- if Module === maybe
58
- return maybe
59
- end
60
- end
61
-
62
- klass_or_str
63
- end
64
- end
65
- end
66
- end
@@ -1,32 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class Middleware
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- begin
10
- response = @app.call(env)
11
- rescue Exception => exception
12
- puts "[Scout Error Service] Caught Exception: #{exception.class.name}"
13
-
14
- context = ScoutApm::Agent.instance.context
15
-
16
- # Bail out early, and reraise if the error is not interesting.
17
- if context.ignored_exceptions.ignored?(exception)
18
- raise
19
- end
20
-
21
- # Capture the error for further processing and shipping
22
- context.error_buffer.capture(exception, env)
23
-
24
- # Finally re-raise
25
- raise
26
- end
27
-
28
- response
29
- end
30
- end
31
- end
32
- end
@@ -1,33 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class Notifier
4
- attr_reader :context
5
- attr_reader :reporter
6
-
7
- def initialize(context)
8
- @context = context
9
- @reporter = ScoutApm::Reporter.new(context, :errors)
10
- end
11
-
12
- def ship
13
- error_records = context.error_buffer.get_and_reset_error_records
14
- if error_records.any?
15
- payload = ScoutApm::ErrorService::Payload.new(context, error_records)
16
- reporter.report(
17
- payload.serialize,
18
- default_headers.merge("X-Error-Count" => error_records.length.to_s)
19
- )
20
- end
21
- end
22
-
23
- private
24
-
25
- def default_headers
26
- {
27
- "Content-Type" => "application/json",
28
- "Accept" => "application/json"
29
- }
30
- end
31
- end
32
- end
33
- end
@@ -1,47 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class Payload
4
- attr_reader :context
5
- attr_reader :errors
6
-
7
- def initialize(context, errors)
8
- @context = context
9
- @errors = errors
10
- end
11
-
12
- # TODO: Don't use to_json since it isn't supported in Ruby 1.8.7
13
- def serialize
14
- payload = as_json.to_json
15
- context.logger.info(payload)
16
- payload
17
- end
18
-
19
- def as_json
20
- serialized_errors = errors.map do |error_record|
21
- serialize_error_record(error_record)
22
- end
23
-
24
- {
25
- :notifier => "scout_apm_ruby",
26
- :environment => context.environment.env,
27
- :root => context.environment.root,
28
- :problems => serialized_errors,
29
- }
30
- end
31
-
32
- def serialize_error_record(error_record)
33
- {
34
- :exception_class => error_record.exception_class,
35
- :message => error_record.message,
36
- :request_uri => error_record.request_uri,
37
- :request_params => error_record.request_params,
38
- :request_session => error_record.request_session,
39
- :environment => error_record.environment,
40
- :trace => error_record.trace,
41
- :request_components => error_record.request_components,
42
- :context => error_record.context,
43
- }
44
- end
45
- end
46
- end
47
- end
@@ -1,17 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class PeriodicWork
4
- attr_reader :context
5
-
6
- def initialize(context)
7
- @context = context
8
- @notifier = ScoutApm::ErrorService::Notifier.new(context)
9
- end
10
-
11
- # Expected to be called many times over the life of the agent
12
- def run
13
- @notifier.ship
14
- end
15
- end
16
- end
17
- end
@@ -1,11 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class Railtie < Rails::Railtie
4
- initializer "scoutapm_error_service.middleware" do |app|
5
- next if ScoutApm::Agent.instance.config.value("error_service")
6
-
7
- app.config.middleware.insert_after ActionDispatch::DebugExceptions, ScoutApm::ErrorService::Rack
8
- end
9
- end
10
- end
11
- end
@@ -1,80 +0,0 @@
1
- module ScoutApm
2
- module ErrorService
3
- class Sidekiq
4
- def initialize
5
- @context = ScoutApm::Agent.instance.context
6
- end
7
-
8
- def install
9
- return false unless defined?(::Sidekiq)
10
-
11
- if ::Sidekiq::VERSION < "3"
12
- install_sidekiq_with_middleware
13
- else
14
- install_sidekiq_with_error_handler
15
- end
16
-
17
- true
18
- end
19
-
20
- def install_sidekiq_with_middleware
21
- # old behavior
22
- ::Sidekiq.configure_server do |config|
23
- config.server_middleware do |chain|
24
- chain.add ScoutApm::ErrorService::Sidekiq::SidekiqExceptionMiddleware
25
- end
26
- end
27
- end
28
-
29
- def install_sidekiq_with_error_handler
30
- ::Sidekiq.configure_server do |config|
31
- config.error_handlers << proc { |exception, job_info|
32
- context = ScoutApm::Agent.instance.context
33
-
34
- # Bail out early, and reraise if the error is not interesting.
35
- if context.ignored_exceptions.ignored?(exception)
36
- raise
37
- end
38
-
39
- job_class =
40
- begin
41
- job_class = job_info[:job]["class"]
42
- job_class = job_info[:job]["args"][0]["job_class"] if job_class == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
43
- job_class
44
- rescue
45
- "UnknownJob"
46
- end
47
-
48
- # Capture the error for further processing and shipping
49
- context.error_buffer.capture(exception, job_info.merge(:custom_controller => job_class))
50
- }
51
- end
52
- end
53
-
54
- class SidekiqExceptionMiddleware
55
- def call(worker, msg, queue)
56
- yield
57
- rescue => exception
58
- context = ScoutApm::Agent.instance.context
59
-
60
- # Bail out early, and reraise if the error is not interesting.
61
- if context.ignored_exceptions.ignored?(exception)
62
- raise
63
- end
64
-
65
- # Capture the error for further processing and shipping
66
- context.error_buffer.capture(
67
- exception,
68
- {
69
- :custom_params => msg,
70
- :custom_controller => msg["class"]
71
- }
72
- )
73
-
74
- # Finally, reraise
75
- raise exception
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,32 +0,0 @@
1
- require "net/http"
2
- require "net/https"
3
- require "uri"
4
-
5
- module ScoutApm
6
- module ErrorService
7
- API_VERSION = "1"
8
-
9
- HEADERS = {
10
- "Content-type" => "application/json",
11
- "Accept" => "application/json"
12
- }
13
-
14
- # Public API to force a given exception to be captured.
15
- # Still obeys the ignore list
16
- # Used internally by SidekiqException
17
- def self.capture(exception, params = {})
18
- return if disabled?
19
- return if ScoutApm::Agent.instance.context.ignored_exceptions.ignore?(exception)
20
-
21
- context.errors_buffer.capture(exception, env)
22
- end
23
-
24
- def self.enabled?
25
- ScoutApm::Agent.instance.context.config.value("errors_enabled")
26
- end
27
-
28
- def self.disabled?
29
- !enabled?
30
- end
31
- end
32
- end
@@ -1,87 +0,0 @@
1
- module ScoutApm
2
- module Extensions
3
- # !!! Extensions are a 0.x level API and breakage is expected as the API is refined.
4
- # Extensions fan out data collected by the agent to additional services.
5
- class Config
6
- attr_reader :agent_context
7
- attr_accessor :transaction_callbacks
8
- attr_accessor :periodic_callbacks
9
-
10
- # Adds a new callback that runs after a transaction completes.
11
- # These run inline during the request and thus should add minimal overhead.
12
- # For example, a transaction callback should NOT make inline HTTP calls to outside services.
13
- # +callback+ must be an object that respond to a +call(payload)+ method.
14
- #
15
- # Example:
16
- # ScoutApm::Extensions::Config.add_transaction_callback(Proc.new { |payload| puts "Duration: #{payload.duration_ms}" })
17
- #
18
- # +payload+ is a +ScoutApm::Extensions::TransactionCallbackPayload+ object.
19
- def self.add_transaction_callback(callback)
20
- agent_context.extensions.transaction_callbacks << callback
21
- end
22
-
23
- # Adds a callback that runs when the per-minute report data is sent to Scout.
24
- # These run in a background thread so external HTTP calls are OK.
25
- # +callback+ must be an object that responds to a +call(reporting_period, metadata)+ method.
26
- #
27
- # Example:
28
- # ScoutApm::Extensions::Config.add_periodic_callback(Proc.new { |reporting_period, metadata| ... })
29
- def self.add_periodic_callback(callback)
30
- agent_context.extensions.periodic_callbacks << callback
31
- end
32
-
33
- def initialize(agent_context)
34
- @agent_context = agent_context
35
- @transaction_callbacks = []
36
- @periodic_callbacks = []
37
- end
38
-
39
- # Runs each reporting period callback.
40
- # Each callback runs inside a begin/rescue block so a broken callback doesn't prevent other
41
- # callbacks from executing or reporting data from being sent.
42
- def run_periodic_callbacks(reporting_period, metadata)
43
- return unless periodic_callbacks.any?
44
-
45
- periodic_callbacks.each do |callback|
46
- begin
47
- callback.call(reporting_period, metadata)
48
- rescue => e
49
- logger.warn "Error running reporting callback extension=#{callback}"
50
- logger.info e.message
51
- logger.debug e.backtrace
52
- end
53
- end
54
- end
55
-
56
- # Runs each transaction callback.
57
- # Each callback runs inside a begin/rescue block so a broken callback doesn't prevent other
58
- # callbacks from executing or the transaction from being recorded.
59
- def run_transaction_callbacks(converter_results, context, scope_layer)
60
- # It looks like layer_finder.scope = nil when a Sidekiq job is retried
61
- return unless scope_layer
62
- return unless transaction_callbacks.any?
63
-
64
- payload = ScoutApm::Extensions::TransactionCallbackPayload.new(agent_context,converter_results,context,scope_layer)
65
-
66
- transaction_callbacks.each do |callback|
67
- begin
68
- callback.call(payload)
69
- rescue => e
70
- logger.warn "Error running transaction callback extension=#{callback}"
71
- logger.info e.message
72
- logger.debug e.backtrace
73
- end
74
- end
75
- end
76
-
77
- def self.agent_context
78
- ScoutApm::Agent.instance.context
79
- end
80
-
81
- def logger
82
- agent_context.logger
83
- end
84
-
85
- end
86
- end
87
- end
@@ -1,74 +0,0 @@
1
- module ScoutApm
2
- module Extensions
3
- # A +TransactionCallbackPayload+ is passed to each Transaction callback's +call+ method.
4
- # It encapsulates the data about a specific transaction.
5
- class TransactionCallbackPayload
6
- # A Hash that stores the output of each layer converter by name. See the naming conventions in +TrackedRequest+.
7
- attr_accessor :converter_results
8
-
9
- def initialize(agent_context,converter_results,context,scope_layer)
10
- @agent_context = agent_context
11
- @converter_results = converter_results
12
- @context = context
13
- @scope_layer = scope_layer
14
- end
15
-
16
- # A flat hash of the context associated w/this transaction (ie user ip and another other data added to context).
17
- def context
18
- @context.to_flat_hash
19
- end
20
-
21
- # The total duration of the transaction
22
- def duration_ms
23
- @scope_layer.total_call_time*1000 # ms
24
- end
25
-
26
- # The time in queue of the transaction in ms. If not present, +nil+ is returned as this is unknown.
27
- def queue_time_ms
28
- # Controller logic
29
- if converter_results[:queue_time] && converter_results[:queue_time].any?
30
- converter_results[:queue_time].values.first.total_call_time*1000 # ms
31
- # Job logic
32
- elsif converter_results[:job]
33
- stat = converter_results[:job].metric_set.metrics[ScoutApm::MetricMeta.new("Latency/all", :scope => transaction_name)]
34
- stat ? stat.total_call_time*1000 : nil
35
- else
36
- nil
37
- end
38
- end
39
-
40
- def hostname
41
- @agent_context.environment.hostname
42
- end
43
-
44
- def app_name
45
- @agent_context.config.value('name')
46
- end
47
-
48
- # Returns +true+ if the transaction raised an exception.
49
- def error?
50
- converter_results[:errors] && converter_results[:errors].any?
51
- end
52
-
53
- def transation_type
54
- @scope_layer.type
55
- end
56
-
57
- def transaction_name
58
- @scope_layer.legacy_metric_name
59
- end
60
-
61
- # Web/Job are more language-agnostic names for controller/job. For example, Python Django does not have controllers.
62
- def transaction_type_slug
63
- case transation_type
64
- when 'Controller'
65
- 'web'
66
- when 'Job'
67
- 'job'
68
- else
69
- 'transaction'
70
- end
71
- end
72
- end
73
- end
74
- end