rails-profiler 0.1.4 → 0.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/lib/profiler/collectors/exception_collector.rb +93 -0
- data/lib/profiler/collectors/log_collector.rb +122 -0
- data/lib/profiler/railtie.rb +3 -1
- data/lib/profiler/version.rb +1 -1
- data/lib/profiler.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59da55aba7ca1284fdda2c948c456bffc05de245d876dba9c9b477257f56654d
|
|
4
|
+
data.tar.gz: e3df3028c4a547e83cda3cb2d6170c279c059d140725efb38a489022e02d15e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f04910c4c4592f4ee1168c5010330d36d460deb8b7ef890ecc4680013c107aaba9c627cbdeb5674a401379b457e0ea13077dcafb5490ca2124804be152fadeb7
|
|
7
|
+
data.tar.gz: d50f9dcded83688a09009c5aa5436e7726007b7b72e44b78d4107d11ddbd72046eef1e812bf606804cb1965fd58ccdae999b7542651baf0a5ddd280c7b2812a4
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_collector"
|
|
4
|
+
|
|
5
|
+
module Profiler
|
|
6
|
+
module Collectors
|
|
7
|
+
class ExceptionCollector < BaseCollector
|
|
8
|
+
def icon
|
|
9
|
+
"💥"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def priority
|
|
13
|
+
5
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def name
|
|
17
|
+
"exception"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def tab_config
|
|
21
|
+
{
|
|
22
|
+
key: "exception",
|
|
23
|
+
label: "Exception",
|
|
24
|
+
icon: icon,
|
|
25
|
+
priority: priority,
|
|
26
|
+
enabled: true,
|
|
27
|
+
default_active: false
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def subscribe
|
|
32
|
+
@exception_data = nil
|
|
33
|
+
|
|
34
|
+
@subscriber = ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
|
|
35
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
36
|
+
ex = event.payload[:exception_object]
|
|
37
|
+
capture_exception(ex) if ex && @exception_data.nil?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def collect
|
|
42
|
+
ActiveSupport::Notifications.unsubscribe(@subscriber) if @subscriber
|
|
43
|
+
|
|
44
|
+
store_data(@exception_data || {})
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def has_data?
|
|
48
|
+
!@exception_data.nil? && !@exception_data.empty?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def toolbar_summary
|
|
52
|
+
return { text: "", color: "gray" } unless has_data?
|
|
53
|
+
|
|
54
|
+
{ text: @exception_data[:exception_class], color: "red" }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def capture_exception(ex)
|
|
60
|
+
raw_backtrace = ex.backtrace || []
|
|
61
|
+
|
|
62
|
+
cleaned = if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
|
|
63
|
+
Rails.backtrace_cleaner.clean(raw_backtrace)
|
|
64
|
+
else
|
|
65
|
+
raw_backtrace.first(30)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Fall back to raw if cleaner returned nothing
|
|
69
|
+
cleaned = raw_backtrace.first(30) if cleaned.empty?
|
|
70
|
+
|
|
71
|
+
backtrace = cleaned.map do |line|
|
|
72
|
+
{
|
|
73
|
+
location: line,
|
|
74
|
+
app_frame: app_frame?(line)
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@exception_data = {
|
|
79
|
+
exception_class: ex.class.name,
|
|
80
|
+
message: ex.message.to_s,
|
|
81
|
+
backtrace: backtrace
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def app_frame?(line)
|
|
86
|
+
return false if line.include?("/gems/")
|
|
87
|
+
return false if line.match?(%r{/ruby/\d+\.\d+\.\d+/})
|
|
88
|
+
return false if line.include?("vendor/bundle")
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
require_relative "base_collector"
|
|
5
|
+
|
|
6
|
+
module Profiler
|
|
7
|
+
module Collectors
|
|
8
|
+
class LogCollector < BaseCollector
|
|
9
|
+
SEVERITY_LABELS = %w[DEBUG INFO WARN ERROR FATAL UNKNOWN].freeze
|
|
10
|
+
|
|
11
|
+
class CaptureLogger < ::Logger
|
|
12
|
+
def initialize
|
|
13
|
+
super(File::NULL)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add(severity, message = nil, progname = nil)
|
|
17
|
+
msg = message || progname
|
|
18
|
+
msg = yield if block_given? && msg.nil?
|
|
19
|
+
return true if msg.nil?
|
|
20
|
+
|
|
21
|
+
Thread.current[:profiler_logs] ||= []
|
|
22
|
+
Thread.current[:profiler_logs] << {
|
|
23
|
+
level: SEVERITY_LABELS[severity] || "UNKNOWN",
|
|
24
|
+
message: msg.to_s.strip,
|
|
25
|
+
timestamp: Time.now.iso8601(3)
|
|
26
|
+
}
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def <<(msg)
|
|
31
|
+
add(0, msg.to_s)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def icon
|
|
36
|
+
"📋"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def priority
|
|
40
|
+
18
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def name
|
|
44
|
+
"logs"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def tab_config
|
|
48
|
+
{
|
|
49
|
+
key: "logs",
|
|
50
|
+
label: "Logs",
|
|
51
|
+
icon: icon,
|
|
52
|
+
priority: priority,
|
|
53
|
+
enabled: true,
|
|
54
|
+
default_active: false
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def subscribe
|
|
59
|
+
Thread.current[:profiler_logs] = []
|
|
60
|
+
@capture_logger = CaptureLogger.new
|
|
61
|
+
|
|
62
|
+
if defined?(Rails) && Rails.logger
|
|
63
|
+
if Rails.logger.respond_to?(:broadcast_to)
|
|
64
|
+
Rails.logger.broadcast_to(@capture_logger)
|
|
65
|
+
elsif defined?(ActiveSupport::Logger)
|
|
66
|
+
Rails.logger.extend(ActiveSupport::Logger.broadcast(@capture_logger))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
rescue => e
|
|
70
|
+
warn "LogCollector#subscribe failed: #{e.message}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def collect
|
|
74
|
+
logs = Thread.current[:profiler_logs] || []
|
|
75
|
+
|
|
76
|
+
if defined?(Rails) && Rails.logger && @capture_logger
|
|
77
|
+
if Rails.logger.respond_to?(:stop_broadcasting_to)
|
|
78
|
+
Rails.logger.stop_broadcasting_to(@capture_logger)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
Thread.current[:profiler_logs] = []
|
|
83
|
+
|
|
84
|
+
errors = logs.count { |l| %w[ERROR FATAL].include?(l[:level]) }
|
|
85
|
+
warnings = logs.count { |l| l[:level] == "WARN" }
|
|
86
|
+
|
|
87
|
+
store_data({
|
|
88
|
+
count: logs.size,
|
|
89
|
+
errors: errors,
|
|
90
|
+
warnings: warnings,
|
|
91
|
+
logs: logs
|
|
92
|
+
})
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def toolbar_summary
|
|
96
|
+
return { text: "0 logs", color: "gray" } if @data.empty?
|
|
97
|
+
|
|
98
|
+
count = @data[:count] || 0
|
|
99
|
+
errors = @data[:errors] || 0
|
|
100
|
+
warnings = @data[:warnings] || 0
|
|
101
|
+
|
|
102
|
+
color = if errors > 0
|
|
103
|
+
"red"
|
|
104
|
+
elsif warnings > 0
|
|
105
|
+
"orange"
|
|
106
|
+
else
|
|
107
|
+
"gray"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
label = if errors > 0
|
|
111
|
+
"#{errors} error#{errors != 1 ? "s" : ""}"
|
|
112
|
+
elsif warnings > 0
|
|
113
|
+
"#{warnings} warning#{warnings != 1 ? "s" : ""}"
|
|
114
|
+
else
|
|
115
|
+
"#{count} log#{count != 1 ? "s" : ""}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
{ text: label, color: color }
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
data/lib/profiler/railtie.rb
CHANGED
|
@@ -35,6 +35,7 @@ module Profiler
|
|
|
35
35
|
if Profiler.configuration.collectors.empty?
|
|
36
36
|
Profiler.configure do |config|
|
|
37
37
|
config.collectors = [
|
|
38
|
+
Profiler::Collectors::ExceptionCollector,
|
|
38
39
|
Profiler::Collectors::RequestCollector,
|
|
39
40
|
Profiler::Collectors::DumpCollector,
|
|
40
41
|
Profiler::Collectors::DatabaseCollector,
|
|
@@ -42,7 +43,8 @@ module Profiler
|
|
|
42
43
|
Profiler::Collectors::ViewCollector,
|
|
43
44
|
Profiler::Collectors::CacheCollector,
|
|
44
45
|
Profiler::Collectors::HttpCollector,
|
|
45
|
-
Profiler::Collectors::FlameGraphCollector
|
|
46
|
+
Profiler::Collectors::FlameGraphCollector,
|
|
47
|
+
Profiler::Collectors::LogCollector
|
|
46
48
|
]
|
|
47
49
|
end
|
|
48
50
|
end
|
data/lib/profiler/version.rb
CHANGED
data/lib/profiler.rb
CHANGED
|
@@ -63,6 +63,8 @@ require_relative "profiler/collectors/cache_collector"
|
|
|
63
63
|
require_relative "profiler/collectors/dump_collector"
|
|
64
64
|
require_relative "profiler/collectors/http_collector"
|
|
65
65
|
require_relative "profiler/collectors/flamegraph_collector"
|
|
66
|
+
require_relative "profiler/collectors/log_collector"
|
|
67
|
+
require_relative "profiler/collectors/exception_collector"
|
|
66
68
|
|
|
67
69
|
require_relative "profiler/railtie" if defined?(Rails::Railtie)
|
|
68
70
|
require_relative "profiler/engine" if defined?(Rails::Engine)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-profiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sébastien Duplessy
|
|
@@ -126,9 +126,11 @@ files:
|
|
|
126
126
|
- lib/profiler/collectors/cache_collector.rb
|
|
127
127
|
- lib/profiler/collectors/database_collector.rb
|
|
128
128
|
- lib/profiler/collectors/dump_collector.rb
|
|
129
|
+
- lib/profiler/collectors/exception_collector.rb
|
|
129
130
|
- lib/profiler/collectors/flamegraph_collector.rb
|
|
130
131
|
- lib/profiler/collectors/http_collector.rb
|
|
131
132
|
- lib/profiler/collectors/job_collector.rb
|
|
133
|
+
- lib/profiler/collectors/log_collector.rb
|
|
132
134
|
- lib/profiler/collectors/performance_collector.rb
|
|
133
135
|
- lib/profiler/collectors/request_collector.rb
|
|
134
136
|
- lib/profiler/collectors/view_collector.rb
|
|
@@ -187,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
187
189
|
- !ruby/object:Gem::Version
|
|
188
190
|
version: '0'
|
|
189
191
|
requirements: []
|
|
190
|
-
rubygems_version: 3.
|
|
192
|
+
rubygems_version: 3.5.22
|
|
191
193
|
signing_key:
|
|
192
194
|
specification_version: 4
|
|
193
195
|
summary: Rails profiler with web toolbar and profiling UI
|