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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c51fea9b1ea5a71d65df6d7745b6db964a149eb3047f99b4da37e9590809a3db
4
- data.tar.gz: 43004eef7dfe27bb76b9f2aaa293f4be0e541741abb6a0f8f5e9f013d4448211
3
+ metadata.gz: 59da55aba7ca1284fdda2c948c456bffc05de245d876dba9c9b477257f56654d
4
+ data.tar.gz: e3df3028c4a547e83cda3cb2d6170c279c059d140725efb38a489022e02d15e9
5
5
  SHA512:
6
- metadata.gz: 78e63feb649e6e7fefb0b4c46f96a9f16e07d5e73e11be2da6084cf47f2fc8c11f2e01658a9751b0e51be8d18add250c05ab1d1f025d1cf66f174ea5d2cbcdeb
7
- data.tar.gz: a73dd17ccbfbe8c3a23ed303dc931984716a7a8d29bc14a7d573a42de1b23e5c65b199d3c95cada4ac61539e8360da5851a28e557c942c850fb8c33ac399a996
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Profiler
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
5
5
  end
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.1.4
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.3.15
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