scout_apm 0.1.18.stackprof4 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7040acd30e2e30aceb89d48e43c699e007d87ea5
4
- data.tar.gz: 76222f981eb632a50948c4f765ad387c671bbf80
3
+ metadata.gz: 359e7ebbd4d2be52175b519c7eed26801f332cf6
4
+ data.tar.gz: d54ba2ef21fc61b38e54136637bd97391ba0c26b
5
5
  SHA512:
6
- metadata.gz: 811ca92ad91009f8e3577caa8641a7b8c6e189bf2460b871f24c1d98d9e5a8b75376194391729aa42d47e3a47e9bf138dfcb34f0cd316f346281b870fd50e902
7
- data.tar.gz: 5b0e5825e3d97e4ba7ce950792890bc5318be6e5fb23d60e6ad4c8bbeac6f1599a14d2f8ecf721c44cc56f046b711b090e322f8f87133dadf912220eeef7f613
6
+ metadata.gz: d5c7c714ffa299176340a4b6d1c62f248106840565245c1ecef1696e103218f3c91dcd2e31d3f0164bf97d125f36f6312c4f4db1c3875dc6c4a2a9b3d12c3420
7
+ data.tar.gz: 45cabecb512ef84af5ab618d227a787d92f64e62874352c770d70a8b8ccf23facf992b30a0ce7ded385b291bf44f11858a5cf3b5f5544d63766fa34fb504ab7b
data/CHANGELOG.markdown CHANGED
@@ -1,6 +1,10 @@
1
+ # 0.9.0
2
+
3
+ * Come out of alpha, and release a beta version.
4
+
1
5
  # 0.1.16
2
6
 
3
- * Beta support for Sinatra monitoring.
7
+ * Initial support for Sinatra monitoring.
4
8
 
5
9
  # 0.1.15
6
10
 
data/lib/scout_apm.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  module ScoutApm
2
2
  end
3
3
 
4
- #####################################
5
- # Ruby StdLibrary Requires
6
- #####################################
7
4
  require 'cgi'
8
5
  require 'logger'
9
6
  require 'net/http'
@@ -13,18 +10,6 @@ require 'socket'
13
10
  require 'yaml'
14
11
  require 'thread'
15
12
 
16
- #####################################
17
- # Gem Requires
18
- #####################################
19
- begin
20
- require 'stackprof'
21
- rescue LoadError
22
- require 'scout_apm/utils/fake_stack_prof'
23
- end
24
-
25
- #####################################
26
- # Internal Requires
27
- #####################################
28
13
  require 'scout_apm/version'
29
14
 
30
15
  require 'scout_apm/server_integrations/passenger'
@@ -40,9 +25,6 @@ require 'scout_apm/framework_integrations/rails_3_or_4'
40
25
  require 'scout_apm/framework_integrations/sinatra'
41
26
  require 'scout_apm/framework_integrations/ruby'
42
27
 
43
- require 'scout_apm/deploy_integrations/capistrano_3'
44
- #require 'scout_apm/deploy_integrations/capistrano_2'
45
-
46
28
  require 'scout_apm/instruments/net_http'
47
29
  require 'scout_apm/instruments/moped'
48
30
  require 'scout_apm/instruments/mongoid'
@@ -59,7 +41,6 @@ require 'scout_apm/utils/sql_sanitizer'
59
41
  require 'scout_apm/utils/null_logger'
60
42
  require 'scout_apm/utils/installed_gems'
61
43
  require 'scout_apm/utils/time'
62
-
63
44
  require 'scout_apm/config'
64
45
  require 'scout_apm/environment'
65
46
  require 'scout_apm/agent'
@@ -75,14 +56,12 @@ require 'scout_apm/stack_item'
75
56
  require 'scout_apm/store'
76
57
  require 'scout_apm/tracer'
77
58
  require 'scout_apm/context'
78
- require 'scout_apm/stackprof_tree_collapser'
79
59
  require 'scout_apm/slow_transaction'
80
60
  require 'scout_apm/capacity'
81
61
 
82
62
  require 'scout_apm/serializers/payload_serializer'
83
63
  require 'scout_apm/serializers/directive_serializer'
84
64
  require 'scout_apm/serializers/app_server_load_serializer'
85
- require 'scout_apm/serializers/deploy_serializer'
86
65
 
87
66
  if defined?(Rails) and Rails.respond_to?(:version) and Rails.version >= '3'
88
67
  module ScoutApm
@@ -78,11 +78,6 @@ module ScoutApm
78
78
  init_logger
79
79
  logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
80
80
 
81
- if environment.deploy_integration
82
- logger.info "Starting monitoring for [#{environment.deploy_integration.name}]]."
83
- return environment.deploy_integration.install
84
- end
85
-
86
81
  return false unless preconditions_met?
87
82
 
88
83
  @started = true
@@ -202,9 +197,5 @@ module ScoutApm
202
197
  @installed_instruments << instance
203
198
  instance.install
204
199
  end
205
-
206
- def deploy_integration
207
- environment.deploy_integration
208
- end
209
200
  end
210
201
  end
@@ -21,7 +21,6 @@ module ScoutApm
21
21
  DEFAULTS = {
22
22
  'host' => 'https://apm.scoutapp.com',
23
23
  'log_level' => 'info',
24
- 'stackprof_interval' => 20000 # microseconds, 1000 = 1 millisecond, so 20k == 20 milliseconds
25
24
  }.freeze
26
25
 
27
26
  def initialize(config_path = nil)
@@ -36,10 +35,11 @@ module ScoutApm
36
35
  # all, and only read off the ENV var this is useful to break a loop during
37
36
  # boot, where we needed an option to set the application root.
38
37
  def value(key, env_only=false)
39
- value = ENV['SCOUT_'+key.upcase]
40
- if !value && !env_only
41
- value = setting(key)
42
- end
38
+ value = if env_only
39
+ ENV['SCOUT_'+key.upcase]
40
+ else
41
+ ENV['SCOUT_'+key.upcase] || settings[key]
42
+ end
43
43
 
44
44
  value.to_s.strip.length.zero? ? nil : value
45
45
  end
@@ -54,12 +54,8 @@ module ScoutApm
54
54
  File.expand_path(config_path)
55
55
  end
56
56
 
57
- def setting(key)
58
- settings[key] || settings(true)[key]
59
- end
60
-
61
- def settings(try_reload=false)
62
- (@settings.nil? || try_reload) ? @settings = load_file : @settings
57
+ def settings
58
+ @settings ||= load_file
63
59
  end
64
60
 
65
61
  def config_environment
@@ -24,13 +24,8 @@ module ScoutApm
24
24
  ScoutApm::FrameworkIntegrations::Ruby.new, # Fallback if none match
25
25
  ]
26
26
 
27
- DEPLOY_INTEGRATIONS = [
28
- ScoutApm::DeployIntegrations::Capistrano3.new(Logger.new(STDOUT)),
29
- # ScoutApm::DeployIntegrations::Capistrano2.new(Logger.new(STDOUT)),
30
- ]
31
-
32
27
  def env
33
- @env ||= deploy_integration? ? deploy_integration.env : framework_integration.env
28
+ @env ||= framework_integration.env
34
29
  end
35
30
 
36
31
  def framework
@@ -63,7 +58,6 @@ module ScoutApm
63
58
  end
64
59
 
65
60
  def root
66
- return deploy_integration.root if deploy_integration
67
61
  framework_root
68
62
  end
69
63
 
@@ -71,6 +65,7 @@ module ScoutApm
71
65
  if override_root = Agent.instance.config.value("application_root", true)
72
66
  return override_root
73
67
  end
68
+
74
69
  if framework == :rails
75
70
  RAILS_ROOT.to_s
76
71
  elsif framework == :rails3_or_4
@@ -111,14 +106,6 @@ module ScoutApm
111
106
  app_server_integration.forking?
112
107
  end
113
108
 
114
- def deploy_integration
115
- @deploy_integration ||= DEPLOY_INTEGRATIONS.detect{ |integration| integration.present? }
116
- end
117
-
118
- def deploy_integration?
119
- !@deploy_integration.nil?
120
- end
121
-
122
109
  ### ruby checks
123
110
 
124
111
  def rubinius?
@@ -27,25 +27,12 @@ module ScoutApm
27
27
 
28
28
  if defined?(::ActionView) && defined?(::ActionView::PartialRenderer)
29
29
  ScoutApm::Agent.instance.logger.debug "Instrumenting ActionView::PartialRenderer"
30
- ::ActionView::PartialRenderer.class_eval do
30
+ ActionView::PartialRenderer.class_eval do
31
31
  include ScoutApm::Tracer
32
- instrument_method :render_partial,
33
- :metric_name => 'View/#{@template.virtual_path rescue "Unknown Partial"}/Rendering',
34
- :scope => true
35
-
36
- instrument_method :collection_with_template,
37
- :metric_name => 'View/#{@template.virtual_path rescue "Unknown Collection"}/Rendering',
38
- :scope => true
39
- end
40
-
41
- ScoutApm::Agent.instance.logger.debug "Instrumenting ActionView::TemplateRenderer"
42
- ::ActionView::TemplateRenderer.class_eval do
43
- include ScoutApm::Tracer
44
- instrument_method :render_template,
45
- :metric_name => 'View/#{args[0].virtual_path rescue "Unknown"}/Rendering',
46
- :scope => true
32
+ instrument_method :render_partial, :metric_name => 'View/#{@template.virtual_path}/Rendering', :scope => true
47
33
  end
48
34
  end
35
+
49
36
  end
50
37
  end
51
38
 
@@ -55,18 +42,13 @@ module ScoutApm
55
42
  scout_controller_action = "Controller/#{controller_path}/#{action_name}"
56
43
 
57
44
  self.class.scout_apm_trace(scout_controller_action, :uri => request.fullpath, :ip => request.remote_ip) do
58
- Thread::current[:scout_apm_prof] = nil
59
- StackProf.start(mode: :wall, interval: ScoutApm::Agent.instance.config.value("stackprof_interval"))
60
-
61
45
  begin
62
46
  super
63
47
  rescue Exception
64
- ScoutApm::Agent.instance.store.track!("Errors/Request", 1, :scope => nil)
48
+ ScoutApm::Agent.instance.store.track!("Errors/Request",1, :scope => nil)
65
49
  raise
66
50
  ensure
67
51
  Thread::current[:scout_apm_scope_name] = nil
68
- StackProf.stop
69
- Thread::current[:scout_apm_prof] = StackProf.results
70
52
  end
71
53
  end
72
54
  end
@@ -74,3 +56,9 @@ module ScoutApm
74
56
  end
75
57
  end
76
58
 
59
+
60
+ # Rails 3/4
61
+ module ScoutApm
62
+ module Instruments
63
+ end
64
+ end
@@ -16,8 +16,8 @@ module ScoutApm
16
16
  end
17
17
 
18
18
  # TODO: Parse & return a real response object, not the HTTP Response object
19
- def report(payload, headers = {})
20
- post(uri, payload, headers)
19
+ def report(payload)
20
+ post(uri, payload)
21
21
  end
22
22
 
23
23
  def uri
@@ -26,26 +26,9 @@ module ScoutApm
26
26
  URI.parse("#{config.value('host')}/apps/checkin.scout?key=#{config.value('key')}&name=#{CGI.escape(Environment.instance.application_name)}")
27
27
  when :app_server_load
28
28
  URI.parse("#{config.value('host')}/apps/app_server_load.scout?key=#{config.value('key')}&name=#{CGI.escape(Environment.instance.application_name)}")
29
- when :deploy_hook
30
- URI.parse("#{config.value('host')}/apps/deploy.scout?key=#{config.value('key')}&name=#{CGI.escape(config.value('name'))}")
31
29
  end.tap{|u| logger.debug("Posting to #{u.to_s}")}
32
30
  end
33
31
 
34
- def can_report?
35
- case type
36
- when :deploy_hook
37
- %w(host key name).each do |k|
38
- if config.value(k).nil?
39
- logger.warn "/#{type} FAILED: missing required config value for #{k}"
40
- return false
41
- end
42
- end
43
- return true
44
- else
45
- return true
46
- end
47
- end
48
-
49
32
  private
50
33
 
51
34
  def post(uri, body, headers = Hash.new)
@@ -69,8 +52,6 @@ module ScoutApm
69
52
  logger.debug "/#{type} OK"
70
53
  when Net::HTTPBadRequest
71
54
  logger.warn "/#{type} FAILED: The Account Key [#{config.value('key')}] is invalid."
72
- when Net::HTTPUnprocessableEntity
73
- logger.warn "/#{type} FAILED: #{response.body}"
74
55
  else
75
56
  logger.debug "/#{type} FAILED: #{response.inspect}"
76
57
  end
@@ -1,49 +1,36 @@
1
- module ScoutApm
2
- class SlowTransaction
3
- BACKTRACE_THRESHOLD = 0.5 # the minimum threshold to record the backtrace for a metric.
4
- BACKTRACE_LIMIT = 5 # Max length of callers to display
5
- MAX_SIZE = 100 # Limits the size of the metric hash to prevent a metric explosion.
1
+ class ScoutApm::SlowTransaction
2
+ BACKTRACE_THRESHOLD = 0.5 # the minimum threshold to record the backtrace for a metric.
3
+ BACKTRACE_LIMIT = 5 # Max length of callers to display
4
+ MAX_SIZE = 100 # Limits the size of the metric hash to prevent a metric explosion.
5
+ attr_reader :metric_name, :total_call_time, :metrics, :meta, :uri, :context, :time, :prof, :raw_prof
6
6
 
7
- attr_reader :metric_name
8
- attr_reader :total_call_time
9
- attr_reader :metrics
10
- attr_reader :meta
11
- attr_reader :uri
12
- attr_reader :context
13
- attr_reader :time
14
- attr_reader :prof
15
- attr_reader :raw_prof
16
-
17
- # Given a call stack, generates a filtered backtrace that:
18
- # * Limits to the app/models, app/controllers, or app/views directories
19
- # * Limits to 5 total callers
20
- # * Makes the app folder the top-level folder used in trace info
21
- def self.backtrace_parser(backtrace)
22
- stack = []
23
- backtrace.each do |c|
24
- if m=c.match(/(\/app\/(controllers|models|views)\/.+)/)
25
- stack << m[1]
26
- break if stack.size == BACKTRACE_LIMIT
27
- end
7
+ # Given a call stack, generates a filtered backtrace that:
8
+ # * Limits to the app/models, app/controllers, or app/views directories
9
+ # * Limits to 5 total callers
10
+ # * Makes the app folder the top-level folder used in trace info
11
+ def self.backtrace_parser(backtrace)
12
+ stack = []
13
+ backtrace.each do |c|
14
+ if m=c.match(/(\/app\/(controllers|models|views)\/.+)/)
15
+ stack << m[1]
16
+ break if stack.size == BACKTRACE_LIMIT
28
17
  end
29
- stack
30
18
  end
19
+ stack
20
+ end
31
21
 
32
- def initialize(uri, metric_name, total_call_time, metrics, context, time, raw_stackprof)
33
- @uri = uri
34
- @metric_name = metric_name
35
- @total_call_time = total_call_time
36
- @metrics = metrics
37
- @context = context
38
- @time = time
39
- @prof = ScoutApm::StackprofTreeCollapser.new(raw_stackprof).call
40
- @raw_prof = raw_stackprof # Send whole data up to server
41
- end
22
+ def initialize(uri,metric_name,total_call_time,metrics,context,time)
23
+ @uri = uri
24
+ @metric_name = metric_name
25
+ @total_call_time = total_call_time
26
+ @metrics = metrics
27
+ @context = context
28
+ @time = time
29
+ end
42
30
 
43
- # Used to remove metrics when the payload will be too large.
44
- def clear_metrics!
45
- @metrics = nil
46
- self
47
- end
31
+ # Used to remove metrics when the payload will be too large.
32
+ def clear_metrics!
33
+ @metrics = nil
34
+ self
48
35
  end
49
36
  end
@@ -72,7 +72,7 @@ module ScoutApm
72
72
  end
73
73
 
74
74
  duration = Time.now - item.start_time
75
- if last = stack.last
75
+ if last=stack.last
76
76
  last.children_time += duration
77
77
  end
78
78
 
@@ -90,8 +90,8 @@ module ScoutApm
90
90
 
91
91
  # Uses controllers as the entry point for a transaction. Otherwise, stats are ignored.
92
92
  if stack_empty and meta.metric_name.match(/\AController\//)
93
- aggs = aggregate_calls(transaction_hash.dup,meta)
94
- store_slow(options[:uri], transaction_hash.dup.merge(aggs), meta, stat)
93
+ aggs=aggregate_calls(transaction_hash.dup,meta)
94
+ store_slow(options[:uri],transaction_hash.dup.merge(aggs),meta,stat)
95
95
  # deep duplicate
96
96
  duplicate = aggs.dup
97
97
  duplicate.each_pair do |k,v|
@@ -139,20 +139,12 @@ module ScoutApm
139
139
  aggregates
140
140
  end
141
141
 
142
- SLOW_TRANSACTION_THRESHOLD = 2
143
-
144
142
  # Stores slow transactions. This will be sent to the server.
145
- def store_slow(uri, transaction_hash, parent_meta, parent_stat, options = {})
143
+ def store_slow(uri,transaction_hash,parent_meta,parent_stat,options = {})
146
144
  @slow_transaction_lock.synchronize do
147
- if parent_stat.total_call_time >= SLOW_TRANSACTION_THRESHOLD
148
- slow_transaction = ScoutApm::SlowTransaction.new(uri,
149
- parent_meta.metric_name,
150
- parent_stat.total_call_time,
151
- transaction_hash.dup,
152
- ScoutApm::Context.current,
153
- Thread::current[:scout_apm_trace_time],
154
- Thread::current[:scout_apm_prof])
155
- @slow_transactions.push(slow_transaction)
145
+ # tree map of all slow transactions
146
+ if parent_stat.total_call_time >= 2
147
+ @slow_transactions.push(ScoutApm::SlowTransaction.new(uri,parent_meta.metric_name,parent_stat.total_call_time,transaction_hash.dup,ScoutApm::Context.current,Thread::current[:scout_apm_trace_time]))
156
148
  ScoutApm::Agent.instance.logger.debug "Slow transaction sample added. [URI: #{uri}] [Context: #{ScoutApm::Context.current.to_hash}] Array Size: #{@slow_transactions.size}"
157
149
  end
158
150
  end
@@ -54,16 +54,13 @@ module ScoutApm
54
54
  elsif Thread::current[:scout_ignore_children]
55
55
  return yield
56
56
  end
57
-
58
57
  if options.delete(:scope)
59
58
  Thread::current[:scout_apm_sub_scope] = metric_name
60
59
  end
61
-
62
60
  if options[:ignore_children]
63
61
  Thread::current[:scout_ignore_children] = true
64
62
  end
65
63
  stack_item = ScoutApm::Agent.instance.store.record(metric_name)
66
-
67
64
  begin
68
65
  yield
69
66
  ensure
@@ -71,21 +68,15 @@ module ScoutApm
71
68
  if options[:ignore_children]
72
69
  Thread::current[:scout_ignore_children] = nil
73
70
  end
74
-
75
71
  ScoutApm::Agent.instance.store.stop_recording(stack_item,options)
76
72
  end
77
73
  end
78
74
 
79
- def instrument_method(method, options = {})
75
+ def instrument_method(method,options = {})
80
76
  ScoutApm::Agent.instance.logger.info "Instrumenting #{method}"
81
77
  metric_name = options[:metric_name] || default_metric_name(method)
82
78
  return if !instrumentable?(method) or instrumented?(method,metric_name)
83
-
84
- class_eval(instrumented_method_string(
85
- method,
86
- {:metric_name => metric_name, :scope => options[:scope] }),
87
- __FILE__, __LINE__
88
- )
79
+ class_eval instrumented_method_string(method, {:metric_name => metric_name, :scope => options[:scope]}), __FILE__, __LINE__
89
80
 
90
81
  alias_method _uninstrumented_method_name(method, metric_name), method
91
82
  alias_method method, _instrumented_method_name(method, metric_name)
@@ -95,15 +86,12 @@ module ScoutApm
95
86
 
96
87
  def instrumented_method_string(method, options)
97
88
  klass = (self === Module) ? "self" : "self.class"
98
- method_str = "def #{_instrumented_method_name(method, options[:metric_name])}(*args, &block)
89
+ "def #{_instrumented_method_name(method, options[:metric_name])}(*args, &block)
99
90
  result = #{klass}.instrument(\"#{options[:metric_name]}\",{:scope => #{options[:scope] || false}}) do
100
91
  #{_uninstrumented_method_name(method, options[:metric_name])}(*args, &block)
101
92
  end
102
93
  result
103
94
  end"
104
-
105
- ScoutApm::Agent.instance.logger.debug "Instrumented Method:\n#{method_str}"
106
- method_str
107
95
  end
108
96
 
109
97
  # The method must exist to be instrumented.
@@ -1,4 +1,4 @@
1
1
  module ScoutApm
2
- VERSION = "0.1.18.stackprof4"
2
+ VERSION = "0.9.0"
3
3
  end
4
4
 
data/scout_apm.gemspec CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib","data"]
20
20
 
21
- s.add_dependency 'stackprof'
22
-
23
21
  s.add_development_dependency "minitest"
24
22
  s.add_development_dependency "pry"
25
23
  s.add_development_dependency "m"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18.stackprof4
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Haynes
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-09-28 00:00:00.000000000 Z
12
+ date: 2015-09-29 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: stackprof
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: minitest
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -89,10 +75,6 @@ files:
89
75
  - lib/scout_apm/capacity.rb
90
76
  - lib/scout_apm/config.rb
91
77
  - lib/scout_apm/context.rb
92
- - lib/scout_apm/deploy_integrations/capistrano_2.cap
93
- - lib/scout_apm/deploy_integrations/capistrano_2.rb
94
- - lib/scout_apm/deploy_integrations/capistrano_3.cap
95
- - lib/scout_apm/deploy_integrations/capistrano_3.rb
96
78
  - lib/scout_apm/environment.rb
97
79
  - lib/scout_apm/framework_integrations/rails_2.rb
98
80
  - lib/scout_apm/framework_integrations/rails_3_or_4.rb
@@ -113,7 +95,6 @@ files:
113
95
  - lib/scout_apm/metric_stats.rb
114
96
  - lib/scout_apm/reporter.rb
115
97
  - lib/scout_apm/serializers/app_server_load_serializer.rb
116
- - lib/scout_apm/serializers/deploy_serializer.rb
117
98
  - lib/scout_apm/serializers/directive_serializer.rb
118
99
  - lib/scout_apm/serializers/payload_serializer.rb
119
100
  - lib/scout_apm/server_integrations/null.rb
@@ -125,10 +106,8 @@ files:
125
106
  - lib/scout_apm/server_integrations/webrick.rb
126
107
  - lib/scout_apm/slow_transaction.rb
127
108
  - lib/scout_apm/stack_item.rb
128
- - lib/scout_apm/stackprof_tree_collapser.rb
129
109
  - lib/scout_apm/store.rb
130
110
  - lib/scout_apm/tracer.rb
131
- - lib/scout_apm/utils/fake_stack_prof.rb
132
111
  - lib/scout_apm/utils/installed_gems.rb
133
112
  - lib/scout_apm/utils/null_logger.rb
134
113
  - lib/scout_apm/utils/sql_sanitizer.rb
@@ -158,9 +137,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
137
  version: '0'
159
138
  required_rubygems_version: !ruby/object:Gem::Requirement
160
139
  requirements:
161
- - - ">"
140
+ - - ">="
162
141
  - !ruby/object:Gem::Version
163
- version: 1.3.1
142
+ version: '0'
164
143
  requirements: []
165
144
  rubyforge_project: scout_apm
166
145
  rubygems_version: 2.2.2
@@ -1,12 +0,0 @@
1
- namespace :scout_apm do
2
- namespace :deploy do
3
- task :starting do
4
- # Warn if missing scout apm deploy creds?
5
- end
6
- task :finished do
7
- ScoutApm::Agent.instance.deploy_integration.report
8
- end
9
- end
10
- end
11
-
12
- after 'deploy:finished', 'scout_apm:deploy:finished'
@@ -1,83 +0,0 @@
1
- require 'scout_apm'
2
-
3
- module ScoutApm
4
- module DeployIntegrations
5
- class Capistrano2
6
- attr_reader :logger
7
-
8
- def initialize(logger)
9
- @logger = logger
10
- @cap = defined?(Capistrano::Configuration) ? ObjectSpace.each_object(Capistrano::Configuration).map.first : nil rescue nil
11
- end
12
-
13
- def name
14
- :capistrano_2
15
- end
16
-
17
- def version
18
- present? ? Capistrano::VERSION : nil
19
- end
20
-
21
- def present?
22
- if !@cap.nil? && @cap.is_a?(Capistrano::Configuration)
23
- require 'capistrano/version'
24
- defined?(Capistrano::VERSION) && Gem::Dependency.new('', '~> 2.0').match?('', Capistrano::VERSION.to_s)
25
- else
26
- return false
27
- end
28
- return true
29
- rescue
30
- return false
31
- end
32
-
33
- def install
34
- logger.debug "Initializing Capistrano2 Deploy Integration."
35
- @cap.load File.expand_path("../capistrano_2.cap", __FILE__)
36
- end
37
-
38
- def root
39
- '.'
40
- end
41
-
42
- def env
43
- @cap.fetch(:stage)
44
- end
45
-
46
- def found?
47
- true
48
- end
49
-
50
- def report
51
- if reporter.can_report?
52
- data = deploy_data
53
- logger.debug "Sending deploy hook data: #{data}"
54
- payload = ScoutApm::Serializers::DeploySerializer.serialize(data)
55
- reporter.report(payload, ScoutApm::Serializers::DeploySerializer::HTTP_HEADERS)
56
- else
57
- logger.warn "Unable to post deploy hook data"
58
- end
59
- end
60
-
61
- def reporter
62
- @reporter ||= ScoutApm::Reporter.new(:deploy_hook, ScoutApm::Agent.instance.config, @logger)
63
- end
64
-
65
- def deploy_data
66
- {:revision => current_revision, :branch => branch, :deployed_by => deployed_by}
67
- end
68
-
69
- def branch
70
- @cap.fetch(:branch)
71
- end
72
-
73
- def current_revision
74
- @cap.fetch(:current_revision) || `git rev-list --max-count=1 --abbrev-commit --abbrev=12 #{branch}`.chomp
75
- end
76
-
77
- def deployed_by
78
- ScoutApm::Agent.instance.config.value('deployed_by')
79
- end
80
-
81
- end
82
- end
83
- end
@@ -1,12 +0,0 @@
1
- namespace :scout_apm do
2
- namespace :deploy do
3
- task :starting do
4
- # Warn if missing scout apm deploy creds?
5
- end
6
- task :finished do
7
- ScoutApm::Agent.instance.deploy_integration.report
8
- end
9
- end
10
- end
11
-
12
- after 'deploy:finished', 'scout_apm:deploy:finished'
@@ -1,82 +0,0 @@
1
- require 'scout_apm'
2
-
3
- module ScoutApm
4
- module DeployIntegrations
5
- class Capistrano3
6
- attr_reader :logger
7
-
8
- def initialize(logger)
9
- @logger = logger
10
- @cap = Rake.application rescue nil
11
- end
12
-
13
- def name
14
- :capistrano_3
15
- end
16
-
17
- def version
18
- present? ? Capistrano::VERSION : nil
19
- end
20
-
21
- def present?
22
- if !@cap.nil? && @cap.is_a?(Capistrano::Application)
23
- require 'capistrano/version'
24
- defined?(Capistrano::VERSION) && Gem::Dependency.new('', '~> 3.0').match?('', Capistrano::VERSION.to_s)
25
- else
26
- return false
27
- end
28
- rescue
29
- return false
30
- end
31
-
32
- def install
33
- logger.debug "Initializing Capistrano3 Deploy Integration."
34
- load File.expand_path("../capistrano_3.cap", __FILE__)
35
- end
36
-
37
- def root
38
- '.'
39
- end
40
-
41
- def env
42
- @cap.fetch(:stage).to_s
43
- end
44
-
45
- def found?
46
- true
47
- end
48
-
49
- def report
50
- if reporter.can_report?
51
- data = deploy_data
52
- logger.debug "Sending deploy hook data: #{data}"
53
- payload = ScoutApm::Serializers::DeploySerializer.serialize(data)
54
- reporter.report(payload, ScoutApm::Serializers::DeploySerializer::HTTP_HEADERS)
55
- else
56
- logger.warn "Unable to post deploy hook data"
57
- end
58
- end
59
-
60
- def reporter
61
- @reporter ||= ScoutApm::Reporter.new(:deploy_hook, ScoutApm::Agent.instance.config, @logger)
62
- end
63
-
64
- def deploy_data
65
- {:revision => current_revision, :branch => branch, :deployed_by => deployed_by}
66
- end
67
-
68
- def branch
69
- @cap.fetch(:branch)
70
- end
71
-
72
- def current_revision
73
- @cap.fetch(:current_revision) || `git rev-list --max-count=1 --abbrev-commit --abbrev=12 #{branch}`.chomp
74
- end
75
-
76
- def deployed_by
77
- ScoutApm::Agent.instance.config.value('deployed_by')
78
- end
79
-
80
- end
81
- end
82
- end
@@ -1,16 +0,0 @@
1
- # Serialize & deserialize deploy data up to the APM server
2
- module ScoutApm
3
- module Serializers
4
- class DeploySerializer
5
- HTTP_HEADERS = {'Content-Type' => 'application/x-www-form-urlencoded'}
6
-
7
- def self.serialize(data)
8
- URI.encode_www_form(data)
9
- end
10
-
11
- def self.deserialize(data)
12
- Marshal.load(data)
13
- end
14
- end
15
- end
16
- end
@@ -1,218 +0,0 @@
1
- # require 'json'; p = JSON::parse(File.read("/Users/cschneid/example_stackprof.out")); p=p.with_indifferent_access; ScoutApm::StackprofTreeCollapser.new(p).call
2
- # require 'json'; p = JSON::parse(File.read("/Users/cschneid/profile_appscontroller.json")); p=p.with_indifferent_access; ScoutApm::StackprofTreeCollapser.new(p).call
3
- # require 'json'; p = JSON::parse(File.read("/Users/cschneid/profile_elasticsearch.json")); p=p.with_indifferent_access; ScoutApm::StackprofTreeCollapser.new(p).call
4
-
5
- # in_app_nodes.map{|n| [n.samples_for_self_and_descendants, n.name, n.file, n.line]}.sort_by {|x| x[0] }
6
- # in_app_nodes.map{|n| [n.total_samples, n.name] }.sort_by {|x| x[0] }
7
-
8
-
9
-
10
- module ScoutApm
11
- class StackprofTreeCollapser
12
- attr_reader :raw_stackprof
13
- attr_reader :nodes # the current set of nodes under consideration
14
-
15
- def initialize(raw_stackprof)
16
- @raw_stackprof = raw_stackprof
17
- ScoutApm::Agent.instance.logger.info("StackProf - Samples: #{raw_stackprof[:samples]}, GC: #{raw_stackprof[:gc_samples]}, missed: #{raw_stackprof[:missed_samples]}, Interval: #{raw_stackprof[:interval]}")
18
- end
19
-
20
- def call
21
- build_tree
22
- connect_children
23
- total_samples_of_app_nodes
24
- end
25
-
26
- private
27
-
28
- def build_tree
29
- @nodes = raw_stackprof[:frames].map do |(frame_id, frame_data)|
30
- TreeNode.new(frame_id, # frame_id
31
- frame_data[:name], # name
32
- frame_data[:file], # file
33
- frame_data[:line], # line
34
- frame_data[:samples], # samples
35
- frame_data[:total_samples], # total_samples
36
- (frame_data[:edges] || {}), # children_edges [ { id => weight } ]
37
- [], # children [ treenode, ... ]
38
- [] # parents [ [treenode, int (weight) ], [...] ]
39
- )
40
- end
41
- end
42
-
43
- def connect_children
44
- nodes.each do |node|
45
- children = nodes.find_all { |n| node.children_edges.keys.include? n.frame_id }
46
-
47
- node.children_edges.each do |(frame_id, weight)|
48
- child = children.detect{ |c| c.frame_id == frame_id }
49
- child.parents << [node, weight]
50
- end
51
-
52
- node.children = children
53
- end
54
- end
55
-
56
- def in_app_nodes
57
- nodes.select {|n| n.app? }
58
- end
59
-
60
- def total_samples_of_app_nodes
61
- in_app_nodes.reject{|n| n.calls_only_app_nodes? && !n.has_samples? }.
62
- map{|n| { samples: n.total_samples,
63
- name: n.name,
64
- file: n.file,
65
- line: n.line
66
- }
67
- }
68
- end
69
-
70
- # @results will be [{name, samples, file, line}]
71
- # def calculate_results
72
- # @results = in_app_nodes.map do |node|
73
- # desc = node.all_descendants
74
- # total_samples = desc.map(&:samples).sum
75
- # { desc_count: desc.length, name: node.name, file: node.file, line: node.line, samples: total_samples }
76
- # end
77
- # end
78
-
79
- # def collapse_tree
80
- # while true
81
- # number_changed = collapse_tree_one_level
82
- # break if number_changed == 0
83
- # end
84
- # end
85
- #
86
- # # For each leaf node, sees if it is internal to the monitored app. If not,
87
- # # collapse that node to its parents, weighted by the edge counts
88
- # # If that node was internal to the monitored app, leave it.
89
- # # Returns 0 if nothing changed, a positive integer if things did change,
90
- # # indicating how many leaves were collapsed
91
- # def collapse_tree_one_level
92
- # number_changed = 0
93
- #
94
- # puts "===========ITERATION==========="
95
- # leaves.each do |leaf_node|
96
- # next if leaf_node.app?
97
- # puts "Collapsing - #{leaf_node.name}"
98
- # # app parent: #{leaf_node.self_or_parents_in_app?.map {|x| x.name}}"
99
- # number_changed += 1
100
- # leaf_node.collapse_to_parent!
101
- # @nodes = @nodes.reject { |n| n == leaf_node }
102
- # end
103
- #
104
- # number_changed
105
- # end
106
- #
107
- # # Returns the final result, an array of hashes
108
- # def generate_output
109
- # leaves.map{|x| { name: x.name, samples: x.samples, file: x.file, line: x.line } }
110
- # end
111
- #
112
- # # A leaf node has no children.
113
- # def leaves
114
- # nodes.find_all { |n| n.children.empty? }
115
- # end
116
- #
117
-
118
- ###########################################
119
- # TreeNode class represents a single node.
120
- ###########################################
121
- TreeNode = Struct.new(:frame_id, :name, :file, :line, :samples, :total_samples,
122
- :children_edges, :children, :parents) do
123
- def app?
124
- @is_app ||= file =~ /^#{ScoutApm::Environment.instance.root}/
125
- end
126
-
127
- # My samples, and the weighted samples of all of my children
128
- #def samples_for_self_and_descendants(seen=Set.new)
129
- # viable_children = children.reject(&:app?)
130
- # @samples_for_self_and_descendants ||= samples + viable_children.map{ |c_node|
131
- # if seen.include? self
132
- # puts "I've already seen #{self.name}, bailing"
133
- # return samples # we've already been included, we're looping
134
- # else
135
- # seen << self
136
- # c_node.samples_for_parent(self, seen.dup).tap { |val| puts "Child gave me #{val}" }
137
- # end
138
- # }.sum
139
- #end
140
-
141
- # For this parent of mine, how many of my samples do they get.
142
- # is combo of "how many samples do I have, and what's the relative weight of this parent"
143
- #def samples_for_parent(p_node, seen=Set.new)
144
- # samples_for_self_and_descendants(seen) * relative_weight_of_parent(p_node)
145
- #end
146
-
147
- #def relative_weight_of_parent(p_node)
148
- # total = parents.map{|(_, weight)| weight}.sum
149
- # p_node_weight = parents.detect(0) {|(this_parent, _)| this_parent == p_node }[1]
150
- # p_node_weight.to_f / total.to_f
151
- #end
152
-
153
- # Allocate this node's samples to its parents, in relation to the rate at
154
- # which each parent called this method. Then clear the child from each of the parents
155
- #def collapse_to_parent!
156
- # total_weight = parents.map{ |(_, weight)| weight }.inject(0){ |sum, weight| sum + weight }
157
- # parents.each do |(p_node, weight)|
158
- # relative_weight = weight.to_f / total_weight.to_f
159
- # p_node.samples += (samples * relative_weight)
160
- # end
161
-
162
- # parents.each {|(p_node, _)| p_node.delete_child!(self) }
163
- #end
164
-
165
- #def delete_child!(node)
166
- # self.children = self.children.reject {|c| c == node }
167
- #end
168
-
169
- # Force object_id to be the equality mechanism, rather than struct's
170
- # default which delegates to == on each value. That is wrong because
171
- # we want to be able to dup a node in the tree construction process and
172
- # not have those compare equal to each other.
173
- def ==(other)
174
- object_id == other.object_id
175
- end
176
-
177
- def inspect
178
- "#{frame_id}: #{name} - ##{samples}\n" +
179
- " Parents: #{parents.map{ |(p, w)| "#{p.name}: #{w}"}.join("\n ") }\n" +
180
- " Children: #{children_edges.inspect} \n"
181
- end
182
-
183
- #def all_descendants(max_depth=100)
184
- # descendants = [self]
185
- # unchecked_edge = self.children.reject(&:app?)
186
- # stop = false
187
-
188
- # puts "----------------------------------------"
189
-
190
- # while max_depth > 0 && !stop
191
- # before_count = descendants.length
192
-
193
- # descendants = (descendants + unchecked_edge).uniq
194
- # unchecked_edge = unchecked_edge.map(&:children).flatten.uniq.reject(&:app?)
195
- # puts "UncheckedEdge Children: #{unchecked_edge.length}"
196
-
197
- # after_count = descendants.length
198
- # stop = true if before_count == after_count
199
- # max_depth = max_depth - 1
200
- # end
201
-
202
- # puts "#{name} - Found #{descendants.length} children after #{100 - max_depth} iterations"
203
-
204
- # puts "----------------------------------------"
205
-
206
- # descendants
207
- #end
208
-
209
- def calls_only_app_nodes?
210
- children.all?(&:app?)
211
- end
212
-
213
- def has_samples?
214
- samples > 0
215
- end
216
- end
217
- end
218
- end
@@ -1,36 +0,0 @@
1
- # A fake implementation of stackprof, for systems that don't support it.
2
- class StackProf
3
- def self.start(*args)
4
- @running = true
5
- end
6
-
7
- def self.stop(*args)
8
- @running = false
9
- end
10
-
11
- def running?
12
- !!@running
13
- end
14
-
15
- def run(*args)
16
- start
17
- yield
18
- stop
19
- results
20
- end
21
-
22
- def sample(*args)
23
- end
24
-
25
- def results(*args)
26
- {
27
- :version => 0.0,
28
- :mode => :wall,
29
- :interval => 1000,
30
- :samples => 0,
31
- :gc_samples => 0,
32
- :missed_samples => 0,
33
- :frames => {},
34
- }
35
- end
36
- end