active-profiling 0.1.2 → 2.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 +4 -4
- data/.rubocop.yml +5722 -0
- data/.rubocop_todo.yml +20 -0
- data/FUNDING.yml +2 -0
- data/Gemfile +6 -7
- data/MIT-LICENSE +1 -1
- data/Rakefile +2 -4
- data/active-profiling.gemspec +18 -15
- data/lib/active-profiling/action_controller/action_profiling.rb +7 -10
- data/lib/active-profiling/action_controller/log_subscriber.rb +17 -18
- data/lib/active-profiling/action_controller.rb +1 -0
- data/lib/active-profiling/active_record/backtrace_log_subscriber.rb +16 -14
- data/lib/active-profiling/active_record.rb +1 -1
- data/lib/active-profiling/gc_statistics.rb +14 -19
- data/lib/active-profiling/railtie.rb +19 -18
- data/lib/active-profiling/ruby_profiler/output.rb +102 -108
- data/lib/active-profiling/ruby_profiler.rb +2 -1
- data/lib/active-profiling/version.rb +2 -1
- data/lib/active-profiling.rb +1 -1
- metadata +15 -11
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2024-04-15 15:03:39 UTC using RuboCop version 1.63.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
11
|
+
Metrics/PerceivedComplexity:
|
12
|
+
Max: 9
|
13
|
+
|
14
|
+
# Offense count: 1
|
15
|
+
# Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
16
|
+
# CheckDefinitionPathHierarchyRoots: lib, spec, test, src
|
17
|
+
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
18
|
+
Naming/FileName:
|
19
|
+
Exclude:
|
20
|
+
- 'lib/active-profiling.rb'
|
data/FUNDING.yml
ADDED
data/Gemfile
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
|
-
source
|
3
|
+
source 'https://rubygems.org'
|
3
4
|
|
4
5
|
gemspec
|
5
6
|
|
6
|
-
gem
|
7
|
-
gem
|
8
|
-
|
9
|
-
if File.exists?('Gemfile.local')
|
10
|
-
instance_eval File.read('Gemfile.local')
|
11
|
-
end
|
7
|
+
gem 'rake'
|
8
|
+
gem 'rdoc'
|
9
|
+
gem 'rubocop', require: false
|
12
10
|
|
11
|
+
instance_eval File.read('Gemfile.local') if File.exist?('Gemfile.local')
|
data/MIT-LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
# -*- ruby -*-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require 'rubygems'
|
5
4
|
require 'rubygems/package_task'
|
@@ -7,7 +6,7 @@ require 'rake/testtask'
|
|
7
6
|
require 'rdoc/task'
|
8
7
|
require 'bundler/gem_tasks'
|
9
8
|
|
10
|
-
|
9
|
+
$LOAD_PATH.push File.expand_path(File.dirname(__FILE__), 'lib')
|
11
10
|
|
12
11
|
version = ActiveProfiling::VERSION
|
13
12
|
|
@@ -25,4 +24,3 @@ Rake::RDocTask.new do |t|
|
|
25
24
|
t.rdoc_dir = 'doc'
|
26
25
|
t.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb')
|
27
26
|
end
|
28
|
-
|
data/active-profiling.gemspec
CHANGED
@@ -1,26 +1,29 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('
|
3
|
+
require File.expand_path('lib/active-profiling/version', __dir__)
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'active-profiling'
|
7
7
|
s.version = ActiveProfiling::VERSION
|
8
8
|
|
9
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
10
|
-
s.
|
11
|
-
|
9
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
10
|
+
s.required_ruby_version = '>= 3.0'
|
11
|
+
|
12
|
+
s.authors = ['J Smith']
|
13
|
+
s.description = 'A Rails profiling suite.'
|
12
14
|
s.summary = s.description
|
13
|
-
s.email =
|
14
|
-
s.license =
|
15
|
+
s.email = 'dark.panda@gmail.com'
|
16
|
+
s.license = 'MIT'
|
15
17
|
s.extra_rdoc_files = [
|
16
|
-
|
18
|
+
'README.rdoc'
|
17
19
|
]
|
18
|
-
s.files = `git ls-files`.split(
|
20
|
+
s.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
19
21
|
s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
20
|
-
s.
|
21
|
-
s.
|
22
|
-
s.require_paths = ["lib"]
|
22
|
+
s.homepage = 'https://github.com/dark-panda/active-profiling'
|
23
|
+
s.require_paths = ['lib']
|
23
24
|
|
24
|
-
s.add_dependency(
|
25
|
+
s.add_dependency('rails', ['>= 6.0'])
|
26
|
+
s.metadata = {
|
27
|
+
'rubygems_mfa_required' => 'true'
|
28
|
+
}
|
25
29
|
end
|
26
|
-
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActionController
|
3
4
|
module ActionProfiling
|
@@ -13,25 +14,21 @@ module ActionController
|
|
13
14
|
:around_filter
|
14
15
|
end
|
15
16
|
|
16
|
-
send around_filter_method, :action_profiler, :
|
17
|
+
send around_filter_method, :action_profiler, if: proc {
|
17
18
|
Rails.application.config.active_profiling.profiler.enabled && ActiveProfiling.ruby_prof?
|
18
19
|
}
|
19
20
|
|
20
|
-
send around_filter_method, :action_gc_statistics, :
|
21
|
+
send around_filter_method, :action_gc_statistics, if: proc {
|
21
22
|
Rails.application.config.active_profiling.gc_statistics.enabled && ActiveProfiling.gc_statistics?
|
22
23
|
}
|
23
24
|
end
|
24
25
|
|
25
|
-
def action_profiler(
|
26
|
-
ruby_profiler(:
|
27
|
-
yield
|
28
|
-
end
|
26
|
+
def action_profiler(*, &block)
|
27
|
+
ruby_profiler(name: "#{controller_name}.#{action_name}", &block)
|
29
28
|
end
|
30
29
|
|
31
|
-
def action_gc_statistics(
|
32
|
-
gc_statistics
|
33
|
-
yield
|
34
|
-
end
|
30
|
+
def action_gc_statistics(*, &block)
|
31
|
+
gc_statistics(&block)
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
@@ -1,49 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActiveProfiling::ActionController
|
3
4
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
4
5
|
def profiler_output(event)
|
5
|
-
return unless logger
|
6
|
-
logger.send("#{config.profiler.log_level}?")
|
6
|
+
return unless logger&.send("#{config.profiler.log_level}?")
|
7
7
|
|
8
|
-
report =
|
8
|
+
report = indent(event.payload[:profiler_output])
|
9
9
|
title = event.payload[:title]
|
10
10
|
|
11
11
|
logger.send(
|
12
12
|
config.profiler.log_level,
|
13
|
-
"#{color("Profiler Output: #{title}", YELLOW, true)}\n#{report}"
|
13
|
+
"#{color("Profiler Output: #{title}", YELLOW, bold: true)}\n#{report}"
|
14
14
|
)
|
15
15
|
end
|
16
16
|
|
17
17
|
def profiler_output_to_file(event)
|
18
|
-
return unless logger
|
19
|
-
logger.send("#{config.profiler.log_level}?")
|
18
|
+
return unless logger&.send("#{config.profiler.log_level}?")
|
20
19
|
|
21
20
|
logger.send(
|
22
21
|
config.profiler.log_level,
|
23
|
-
color("Wrote profiling information to #{event.payload[:file_name]}", YELLOW, true)
|
22
|
+
color("Wrote profiling information to #{event.payload[:file_name]}", YELLOW, bold: true)
|
24
23
|
)
|
25
24
|
end
|
26
25
|
|
27
26
|
def gc_statistics(event)
|
28
|
-
return unless logger
|
29
|
-
logger.send("#{config.gc_statistics.log_level}?")
|
27
|
+
return unless logger&.send("#{config.gc_statistics.log_level}?")
|
30
28
|
|
31
|
-
|
32
|
-
title = event.payload[:title]
|
33
|
-
report = self.indent(event.payload[:report])
|
29
|
+
return if event.payload[:report].blank?
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
title = event.payload[:title]
|
32
|
+
report = indent(event.payload[:report])
|
33
|
+
|
34
|
+
logger.send(
|
35
|
+
config.gc_statistics.log_level,
|
36
|
+
"#{color("GC Statistics: #{title}", YELLOW, bold: true)}\n#{report}"
|
37
|
+
)
|
40
38
|
end
|
41
39
|
|
42
40
|
def logger
|
43
41
|
::Rails.logger
|
44
42
|
end
|
45
43
|
|
46
|
-
|
44
|
+
private
|
45
|
+
|
47
46
|
def config
|
48
47
|
Rails.application.config.active_profiling
|
49
48
|
end
|
@@ -1,33 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActiveProfiling::ActiveRecord
|
3
4
|
class BacktraceLogSubscriber < ::ActiveSupport::LogSubscriber
|
4
5
|
def sql(event)
|
5
|
-
return unless
|
6
|
-
config.log_level &&
|
7
|
-
logger &&
|
8
|
-
logger.send("#{config.log_level}?")
|
6
|
+
return unless skip_backtrace?
|
9
7
|
|
10
8
|
payload = event.payload
|
11
9
|
|
12
|
-
return if
|
10
|
+
return if payload[:name] == 'SCHEMA'
|
13
11
|
|
14
12
|
backtrace = event.send(:caller).collect { |line|
|
15
|
-
if line_match(line)
|
16
|
-
" #{line}"
|
17
|
-
end
|
13
|
+
" #{line}" if line_match(line)
|
18
14
|
}.compact
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
return if backtrace.empty?
|
17
|
+
|
18
|
+
name = color(payload[:name], YELLOW, true)
|
19
|
+
logger.send(config.log_level, " #{name}\n#{backtrace.join("\n")}")
|
24
20
|
end
|
25
21
|
|
26
22
|
def logger
|
27
23
|
::ActiveRecord::Base.logger
|
28
24
|
end
|
29
25
|
|
30
|
-
|
26
|
+
private
|
27
|
+
|
28
|
+
def skip_backtrace?
|
29
|
+
config.enabled &&
|
30
|
+
config.log_level &&
|
31
|
+
logger&.send("#{config.log_level}?")
|
32
|
+
end
|
33
|
+
|
31
34
|
def config
|
32
35
|
Rails.application.config.active_profiling.active_record.backtrace_logger
|
33
36
|
end
|
@@ -39,4 +42,3 @@ module ActiveProfiling::ActiveRecord
|
|
39
42
|
end
|
40
43
|
|
41
44
|
ActiveProfiling::ActiveRecord::BacktraceLogSubscriber.attach_to :active_record
|
42
|
-
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActiveProfiling
|
3
4
|
module GCStatistics
|
@@ -6,7 +7,7 @@ module ActiveProfiling
|
|
6
7
|
if defined?(GC::Profiler)
|
7
8
|
def gc_statistics_report(options = {})
|
8
9
|
options = {
|
9
|
-
:
|
10
|
+
disable_gc: false
|
10
11
|
}.merge(options)
|
11
12
|
|
12
13
|
GC.disable if options[:disable_gc]
|
@@ -15,14 +16,11 @@ module ActiveProfiling
|
|
15
16
|
|
16
17
|
retval = yield
|
17
18
|
|
18
|
-
if options[:disable_gc]
|
19
|
-
GC.enable
|
20
|
-
end
|
19
|
+
GC.enable if options[:disable_gc]
|
21
20
|
|
22
21
|
result = GC::Profiler.result
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
[retval, result]
|
26
24
|
ensure
|
27
25
|
GC.enable if options[:disable_gc]
|
28
26
|
GC::Profiler.disable
|
@@ -31,7 +29,7 @@ module ActiveProfiling
|
|
31
29
|
elsif GC.respond_to?(:enable_stats)
|
32
30
|
def gc_statistics_report(options = {})
|
33
31
|
options = {
|
34
|
-
:
|
32
|
+
disable_gc: false
|
35
33
|
}.merge(options)
|
36
34
|
|
37
35
|
GC.disable if options[:disable_gc]
|
@@ -47,18 +45,17 @@ module ActiveProfiling
|
|
47
45
|
"Time (ms): #{GC.time / 1000.0}"
|
48
46
|
].join("\n")
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
[retval, result]
|
52
49
|
ensure
|
53
50
|
GC.enable if options[:disable_gc]
|
54
51
|
GC.disable_stats
|
55
52
|
GC.clear_stats
|
56
53
|
end
|
57
54
|
else
|
58
|
-
$stderr.
|
55
|
+
$stderr.warn 'NOTICE: this version of Ruby cannot report on GC statistics.'
|
59
56
|
|
60
|
-
def gc_statistics_report(*
|
61
|
-
[
|
57
|
+
def gc_statistics_report(*)
|
58
|
+
[yield, nil]
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
@@ -85,21 +82,19 @@ module ActiveProfiling
|
|
85
82
|
# with the GC statistics patch found here:
|
86
83
|
#
|
87
84
|
# http://blog.pluron.com/2008/02/memory-profilin.html
|
88
|
-
def gc_statistics(*args)
|
85
|
+
def gc_statistics(*args, &block)
|
89
86
|
options = Rails.application.config.active_profiling.gc_statistics.merge(args.extract_options!)
|
90
87
|
|
91
|
-
result, gc_report = gc_statistics_report(options)
|
92
|
-
yield
|
93
|
-
end
|
88
|
+
result, gc_report = gc_statistics_report(options, &block)
|
94
89
|
|
95
90
|
ActiveSupport::Notifications.instrument('gc_statistics.active_profiling', {
|
96
|
-
:
|
97
|
-
:
|
91
|
+
report: gc_report,
|
92
|
+
title: options[:title] || args.first
|
98
93
|
})
|
99
94
|
|
100
95
|
result
|
101
96
|
end
|
102
97
|
end
|
103
98
|
|
104
|
-
|
99
|
+
extend(GCStatistics)
|
105
100
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActiveProfiling
|
3
4
|
class Railtie < Rails::Railtie
|
@@ -43,23 +44,23 @@ module ActiveProfiling
|
|
43
44
|
# :print_file => true
|
44
45
|
# }
|
45
46
|
DEFAULT_PROFILER_OPTIONS = {
|
46
|
-
:
|
47
|
+
enabled: false,
|
47
48
|
|
48
|
-
:
|
49
|
+
measure_mode: :process_time,
|
49
50
|
|
50
|
-
:
|
51
|
+
disable_gc: true,
|
51
52
|
|
52
|
-
:
|
53
|
+
printer: :graph,
|
53
54
|
|
54
|
-
:
|
55
|
+
call_tree_prefix: 'callgrind.out.',
|
55
56
|
|
56
|
-
:
|
57
|
+
output: nil,
|
57
58
|
|
58
|
-
:
|
59
|
+
log_level: :info,
|
59
60
|
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:
|
61
|
+
printer_options: {
|
62
|
+
min_percent: 1,
|
63
|
+
print_file: true
|
63
64
|
}
|
64
65
|
}.freeze
|
65
66
|
|
@@ -77,11 +78,11 @@ module ActiveProfiling
|
|
77
78
|
# whenever you need to and see results as you go.
|
78
79
|
# * +:log_level+ - The log level to spit the GC statistics to.
|
79
80
|
DEFAULT_GC_STATISTICS_OPTIONS = {
|
80
|
-
:
|
81
|
+
enabled: false,
|
81
82
|
|
82
|
-
:
|
83
|
+
disable_gc: false,
|
83
84
|
|
84
|
-
:
|
85
|
+
log_level: :info
|
85
86
|
}.freeze
|
86
87
|
|
87
88
|
# These settings are the default values used for the ActiveRecord
|
@@ -98,11 +99,11 @@ module ActiveProfiling
|
|
98
99
|
# /^#{Rails.root}(?!(\/vendor\/rails|\/\.bundle))/ so that only lines
|
99
100
|
# in your application code are logged.
|
100
101
|
DEFAULT_AR_BACKTRACE_LOGGER_OPTIONS = {
|
101
|
-
:
|
102
|
+
enabled: false,
|
102
103
|
|
103
|
-
:
|
104
|
+
verbose: false,
|
104
105
|
|
105
|
-
:
|
106
|
+
log_level: :debug
|
106
107
|
}.freeze
|
107
108
|
|
108
109
|
config.active_profiling = ActiveSupport::OrderedOptions.new
|
@@ -111,13 +112,13 @@ module ActiveProfiling
|
|
111
112
|
config.active_profiling.active_record = ActiveSupport::OrderedOptions.new
|
112
113
|
config.active_profiling.active_record.backtrace_logger = ActiveSupport::OrderedOptions.new
|
113
114
|
|
114
|
-
initializer
|
115
|
+
initializer 'active_profiling.set_profiling_config' do |app|
|
115
116
|
options = app.config.active_profiling
|
116
117
|
|
117
118
|
options.profiler.reverse_merge!(DEFAULT_PROFILER_OPTIONS)
|
118
119
|
options.gc_statistics.reverse_merge!(DEFAULT_GC_STATISTICS_OPTIONS)
|
119
120
|
options.active_record.backtrace_logger.reverse_merge!(DEFAULT_AR_BACKTRACE_LOGGER_OPTIONS)
|
120
|
-
options.active_record.backtrace_logger[:matcher] ||=
|
121
|
+
options.active_record.backtrace_logger[:matcher] ||= %r{#{Rails.root}(?!(/vendor/rails|/\.bundle))}
|
121
122
|
end
|
122
123
|
end
|
123
124
|
end
|