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
@@ -0,0 +1,312 @@
1
+ # Takes in a ton of traces. Structure is a several nested arrays:
2
+ # [ # Traces
3
+ # [ # Trace
4
+ # [file,line,method,klass] # TraceLine (raw)
5
+ # ]
6
+ # ]
7
+ #
8
+ # Cleans them
9
+ # Merges them by gem/app
10
+ #
11
+ module ScoutApm
12
+ class TraceSet
13
+ # A TraceCube object which is a glorified hash of { Trace -> Count }. Used to
14
+ # collect up the count of each unique trace we've seen
15
+ attr_reader :cube
16
+
17
+ # Allow layer to push values in
18
+ attr_accessor :raw_traces
19
+ attr_accessor :skipped_in_gc
20
+ attr_accessor :skipped_in_handler
21
+ attr_accessor :skipped_in_job_registered
22
+ attr_accessor :skipped_in_not_running
23
+
24
+ def initialize
25
+ @raw_traces = []
26
+ @cube = TraceCube.new
27
+ end
28
+
29
+ # We need to know what the "Start" of this trace is. An untrimmed trace generally is:
30
+ #
31
+ # Gem
32
+ # Gem
33
+ # App
34
+ # App
35
+ # App <---- set root_class of this.
36
+ # Rails
37
+ # Rails
38
+ def set_root_class(klass_name)
39
+ @root_klass = klass_name.to_s
40
+ end
41
+
42
+ def to_a
43
+ res = []
44
+ create_cube!
45
+ @cube.each do |(trace, count)|
46
+ res << [trace.to_a, count]
47
+ end
48
+
49
+ res
50
+ end
51
+
52
+ def as_json
53
+ res = []
54
+ create_cube!
55
+ @cube.each do |(trace, count)|
56
+ res << [trace.as_json, count]
57
+ end
58
+
59
+ res
60
+ end
61
+
62
+ def create_cube!
63
+ while raw_trace = @raw_traces.shift
64
+ clean_trace = ScoutApm::CleanTrace.new(raw_trace, @root_klass)
65
+ @cube << clean_trace
66
+ end
67
+ @raw_traces = []
68
+ end
69
+
70
+ def total_count
71
+ create_cube!
72
+ cube.inject(0) do |sum, (_, count)|
73
+ sum + count
74
+ end
75
+ end
76
+
77
+ def inspect
78
+ create_cube!
79
+ cube.map do |(trace, count)|
80
+ "\t#{count} -- #{trace.first.klass}##{trace.first.method}\n\t\t#{trace.to_a[1].try(:klass)}##{trace.to_a[1].try(:method)}"
81
+ end.join("\n")
82
+ end
83
+ end
84
+
85
+ # A trace is a list of individual lines, where one called another, forming a backtrace.
86
+ # Each line is made up of File, Line #, Klass, Method
87
+ #
88
+ # For the purpouses of this class:
89
+ # "Top" of the trace means the currently-running method.
90
+ # "Bottom" means the root of the call tree, from program start into rails and so on.
91
+ #
92
+ # This class trims off top and bottom to get a the meat of the trace
93
+ class CleanTrace
94
+ include Enumerable
95
+
96
+ attr_reader :lines
97
+
98
+ def initialize(raw_trace, root_klass=nil)
99
+ @lines = Array(raw_trace).map {|frame, lineno| TraceLine.new(frame, lineno)}
100
+ @root_klass = root_klass
101
+
102
+ # A trace has interesting data in the middle of it, since normally it'll go
103
+ # RailsCode -> App Code -> Gem Code.
104
+ #
105
+ # So we drop the code that leads up to your app, since a deep trace that
106
+ # always says that you went through middleware and the rails router doesn't
107
+ # help diagnose issues.
108
+ drop_below_app
109
+
110
+ # Then we drop most of the Gem Code, since you didn't write it, and in the
111
+ # vast majority of the cases, the time spent there is because your app code
112
+ # asked, not because of inherent issues with the gem. For instance, if you
113
+ # fire off a slow query to a database gem, you probably want to be
114
+ # optimizing the query, not trying to make the database gem faster.
115
+ drop_above_app
116
+ end
117
+
118
+ # Iterate starting at END of array until a controller line is found. Pop off at that index - 1.
119
+ def drop_below_app
120
+ pops = 0
121
+ index = lines.size - 1 # last index, not size.
122
+
123
+ while index >= 0 && !lines[index].controller?(@root_klass)
124
+ index -= 1
125
+ pops += 1
126
+ end
127
+
128
+ lines.pop(pops)
129
+ end
130
+
131
+ # Find the closest mention of the application code from the currently-running method.
132
+ # Then adjust by 1 if possible to capture the "first" line
133
+ def drop_above_app
134
+ ai = @lines.find_index(&:app?)
135
+ if ai
136
+ ai -= 1 if ai > 0
137
+ @lines = @lines[ai .. -1]
138
+ else
139
+ @lines = [] # No app line in backtrace, nothing to show?
140
+ end
141
+ end
142
+
143
+ def each
144
+ @lines.each { |line| yield line }
145
+ end
146
+
147
+ def empty?
148
+ @lines.empty?
149
+ end
150
+
151
+ def as_json
152
+ @lines.map { |line| line.as_json }
153
+ end
154
+
155
+ ###############################
156
+ # Hash Key interface
157
+ def hash
158
+ @lines.hash
159
+ end
160
+
161
+ def eql?(other)
162
+ @lines.eql?(other.lines)
163
+ end
164
+ ###############################
165
+ end
166
+
167
+ class TraceLine
168
+ # An opaque C object, only call Stacks#frame_* methods on this.
169
+ attr_reader :frame
170
+
171
+ # The line number. This doesn't appear to be obtainable from the frame itself
172
+ attr_reader :lineno
173
+
174
+ def initialize(frame, lineno)
175
+ @frame = frame
176
+ @lineno = lineno
177
+ end
178
+
179
+ # Returns the name of the last gem in the line
180
+ def gem_name
181
+ @gem_name ||= begin
182
+ r = %r{\/gems/(.*?)/}.freeze
183
+ results = file.scan(r)
184
+ results[-1][0] # Scan will return a nested array, so extract out that nesting
185
+ rescue
186
+ nil
187
+ end
188
+ end
189
+
190
+ def stdlib_name
191
+ @stdlib_name ||= begin
192
+ r = %r{#{Regexp.escape(RbConfig::TOPDIR)}/(.*?)}.freeze
193
+ results = file.scan(r)
194
+ results[-1][0] # Scan will return a nested array, so extract out that nesting
195
+ rescue
196
+ nil
197
+ end
198
+ end
199
+
200
+ def file
201
+ ScoutApm::Instruments::Stacks.frame_file(frame)
202
+ end
203
+
204
+
205
+ # If we ever want to get the "first line of the method" - ScoutApm::Instruments::Stacks.frame_lineno(frame)
206
+ def line
207
+ lineno
208
+ end
209
+
210
+ def klass
211
+ ScoutApm::Instruments::Stacks.frame_klass(frame)
212
+ end
213
+
214
+ def method
215
+ ScoutApm::Instruments::Stacks.frame_method(frame)
216
+ end
217
+
218
+ def gem?
219
+ !!gem_name
220
+ end
221
+
222
+ def stdlib?
223
+ !!stdlib_name
224
+ end
225
+
226
+ def app?
227
+ r = %r|^#{Regexp.escape(ScoutApm::Environment.instance.root.to_s)}/|.freeze
228
+ result = !gem_name && !stdlib_name && file =~ r
229
+ !!result # coerce to a bool
230
+ end
231
+
232
+ def trim_file(file_path)
233
+ return if file_path.nil?
234
+ if gem?
235
+ r = %r{.*gems/.*?/}.freeze
236
+ file_path.sub(r, "/")
237
+ elsif stdlib?
238
+ file_path.sub(RbConfig::TOPDIR, '')
239
+ elsif app?
240
+ file_path.sub(ScoutApm::Environment.instance.root.to_s, '')
241
+ end
242
+ end
243
+
244
+ # If root_klass is provided, just see if this is exactly that class. If not,
245
+ # fall back on "is this in the app"
246
+ def controller?(root_klass)
247
+ return false if klass.nil? # main function doesn't have a file associated
248
+
249
+ if root_klass
250
+ klass == root_klass
251
+ else
252
+ app?
253
+ end
254
+ end
255
+
256
+ def formatted_to_s
257
+ "#{stdlib_name} #{klass}##{method} -- #{file}:#{line}"
258
+ end
259
+
260
+ def as_json
261
+ [ trim_file(file), line, klass, method, app?, gem_name, stdlib_name ]
262
+ end
263
+
264
+ ###############################
265
+ # Hash Key interface
266
+
267
+ def hash
268
+ # Note that this does not include line number. It caused a few situations
269
+ # where we had a bunch of time spent in one method, but across a few lines,
270
+ # we decided that it made sense to group them together.
271
+ file.hash ^ method.hash ^ klass.hash
272
+ end
273
+
274
+ def eql?(other)
275
+ file == other.file &&
276
+ method == other.method &&
277
+ klass == other.klass
278
+ end
279
+
280
+ ###############################
281
+ end
282
+
283
+ # Collects clean traces and counts how many of each we have.
284
+ class TraceCube
285
+ include Enumerable
286
+
287
+ attr_reader :traces
288
+ attr_reader :total_count
289
+
290
+ def initialize
291
+ @traces = Hash.new{ |h,k| h[k] = 0 }
292
+ @total_count = 0
293
+ end
294
+
295
+ def <<(clean_trace)
296
+ @total_count += 1
297
+ @traces[clean_trace] += 1
298
+ end
299
+
300
+ # Yields two element array, the trace and the count of that trace
301
+ # In descending order of count.
302
+ def each
303
+ @traces
304
+ .to_a
305
+ .each { |(trace, count)|
306
+ next if trace.empty?
307
+ yield [trace, count]
308
+ }
309
+ end
310
+ end
311
+ end
312
+
@@ -12,36 +12,31 @@ module ScoutApm
12
12
  klass.extend ClassMethods
13
13
  end
14
14
 
15
- # Type: the Layer type - "View" or similar
16
- # Name: specific name - "users/_gravatar". The object must respond to "#to_s". This allows us to be more efficient - in most cases, the metric name isn't needed unless we are processing a slow transaction.
17
- # A Block: The code to be instrumented
18
- #
19
- # Options:
20
- # * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
21
- # when rendering the transaction tree in the UI.
22
- # * :desc - Additional capture, SQL, or HTTP url or similar
23
- # * :scope - set to true if you want to make this layer a subscope
24
- def self.instrument(type, name, options={}) # Takes a block
25
- layer = ScoutApm::Layer.new(type, name)
26
- layer.desc = options[:desc] if options[:desc]
27
- layer.subscopable! if options[:scope]
28
-
29
- req = ScoutApm::RequestManager.lookup
30
- req.start_layer(layer)
31
- req.ignore_children! if options[:ignore_children]
32
-
33
- begin
34
- yield
35
- ensure
36
- req.acknowledge_children! if options[:ignore_children]
37
- req.stop_layer
38
- end
39
- end
40
-
41
15
  module ClassMethods
42
- # See ScoutApm::Tracer.instrument
43
- def instrument(type, name, options={}, &block)
44
- ScoutApm::Tracer.instrument(type, name, options, &block)
16
+ # Type: the Layer type - "View" or similar
17
+ # Name: specific name - "users/_gravatar". The object must respond to "#to_s". This allows us to be more efficient - in most cases, the metric name isn't needed unless we are processing a slow transaction.
18
+ # A Block: The code to be instrumented
19
+ #
20
+ # Options:
21
+ # * :ignore_children - will not instrument any method calls beneath this call. Example use case: InfluxDB uses Net::HTTP, which is instrumented. However, we can provide more specific data if we know we're doing an influx call, so we'd rather just instrument the Influx call and ignore Net::HTTP.
22
+ # when rendering the transaction tree in the UI.
23
+ # * :desc - Additional capture, SQL, or HTTP url or similar
24
+ # * :scope - set to true if you want to make this layer a subscope
25
+ def instrument(type, name, options={}) # Takes a block
26
+ layer = ScoutApm::Layer.new(type, name)
27
+ layer.desc = options[:desc] if options[:desc]
28
+ layer.subscopable! if options[:scope]
29
+
30
+ req = ScoutApm::RequestManager.lookup
31
+ req.start_layer(layer)
32
+ req.ignore_children! if options[:ignore_children]
33
+
34
+ begin
35
+ yield
36
+ ensure
37
+ req.acknowledge_children! if options[:ignore_children]
38
+ req.stop_layer
39
+ end
45
40
  end
46
41
 
47
42
  # Wraps a method in a call to #instrument via aggressive monkey patching.
@@ -50,13 +45,13 @@ module ScoutApm
50
45
  # type - "View" or "ActiveRecord" and similar
51
46
  # name - "users/show", "App#find"
52
47
  def instrument_method(method_name, options = {})
53
- ScoutApm::Agent.instance.context.logger.info "Instrumenting #{method_name}"
48
+ ScoutApm::Agent.instance.logger.info "Instrumenting #{method_name}"
54
49
  type = options[:type] || "Custom"
55
50
  name = options[:name] || "#{self.name}/#{method_name.to_s}"
56
51
 
57
52
  instrumented_name, uninstrumented_name = _determine_instrumented_name(method_name, type)
58
53
 
59
- ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_name}, #{uninstrumented_name}"
54
+ ScoutApm::Agent.instance.logger.info "Instrumenting #{instrumented_name}, #{uninstrumented_name}"
60
55
 
61
56
  return if !_instrumentable?(method_name) or _instrumented?(instrumented_name, method_name)
62
57
 
@@ -90,16 +85,17 @@ module ScoutApm
90
85
  end
91
86
 
92
87
  def _instrumented_method_string(instrumented_name, uninstrumented_name, type, name, options={})
88
+ klass = (self === Module) ? "self" : "self.class"
93
89
  method_str = <<-EOF
94
90
  def #{instrumented_name}(*args, &block)
95
91
  name = begin
96
92
  "#{name}"
97
93
  rescue => e
98
- ScoutApm::Agent.instance.context.logger.error("Error raised while interpreting instrumented name: %s, %s" % ['#{name}', e.message])
94
+ ScoutApm::Agent.instance.logger.error("Error raised while interpreting instrumented name: %s, %s" % ['#{name}', e.message])
99
95
  "Unknown"
100
96
  end
101
97
 
102
- ::ScoutApm::Tracer.instrument( "#{type}",
98
+ #{klass}.instrument( "#{type}",
103
99
  name,
104
100
  {:scope => #{options[:scope] || false}}
105
101
  ) do
@@ -114,14 +110,14 @@ module ScoutApm
114
110
  # The method must exist to be instrumented.
115
111
  def _instrumentable?(method_name)
116
112
  exists = method_defined?(method_name) || private_method_defined?(method_name)
117
- ScoutApm::Agent.instance.context.logger.warn "The method [#{self.name}##{method_name}] does not exist and will not be instrumented" unless exists
113
+ ScoutApm::Agent.instance.logger.warn "The method [#{self.name}##{method_name}] does not exist and will not be instrumented" unless exists
118
114
  exists
119
115
  end
120
116
 
121
117
  # +True+ if the method is already instrumented.
122
118
  def _instrumented?(instrumented_name, method_name)
123
119
  instrumented = method_defined?(instrumented_name)
124
- ScoutApm::Agent.instance.context.logger.warn("The method [#{self.name}##{method_name}] has already been instrumented") if instrumented
120
+ ScoutApm::Agent.instance.logger.warn("The method [#{self.name}##{method_name}] has already been instrumented") if instrumented
125
121
  instrumented
126
122
  end
127
123