newshound 0.2.1 → 0.2.3

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: 3128baf64381d76f8ba53efd4887d333b875ba981d08f9ca6d6ebde9f5d23921
4
- data.tar.gz: 35110f37798b54c435be13f5ebe0a1d1dfeb0e2629a676fa51c15b2ebafee9ef
3
+ metadata.gz: 17482571ea8f7d999aa1325c6263939d19d2028f8b1ee493dbf937db079ca7cb
4
+ data.tar.gz: 60fb33436b5c573feae6c5fbbf85c4e5c0b5e7a402f4ebb4af0a6d9627aaee27
5
5
  SHA512:
6
- metadata.gz: 9d99bc945f8fd1a1bb0550c94a215006833b962e815a4450fc84281e3ca6d0f37fa98fd6ecfedd5aee9e1f4dc4ad93da9e4cf30710906a0651d1e1959a554c47
7
- data.tar.gz: b01b19aa141e0fe32db7dd188487fd6b8e7840b68194bf1b06b1f666c463240a353d3d8f0c1c408a2d60d0c58a13df517c83b78303d78ebd16caa504a0552180
6
+ metadata.gz: b1d0e8d16a32eec46f8053cd86b2d0bcef597724eef9075e227b054ef3b41fe562bc821c70cad5360b7151ead08599a226a4591c485811d90ebca7d7599261ee
7
+ data.tar.gz: bceefac2030c25e5a833f6b0e4debdc69cc30412b2af500f7cd3e0164b46300eb301f3fbf54aad3c277452f3ea8ae3e7856f105c9040a38cedad0f3d70399380
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.3] - 2025-10-29
9
+
10
+ ### Fixed
11
+
12
+ - Updated styling in banner injector to attempt to keep newshound banner above other application's menus, instead of hovering over them.
13
+
14
+ ### Changed
15
+
16
+ - Consolidated exception data extraction in ExceptionTrack and SolidErrors (55cffd3)
data/Gemfile CHANGED
@@ -4,12 +4,11 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- group :development, :test do
8
- gem "bundler", "~> 2.0"
9
- gem "rake", "~> 13.0"
10
- gem "rspec", "~> 3.0"
11
- gem "rubocop", "~> 1.0"
12
- gem "pg"
13
- gem "pry"
14
- gem "simplecov", require: false
15
- end
7
+ gem "bundler"
8
+ gem "rake"
9
+ gem "rspec"
10
+ gem "reissue"
11
+ gem "standard"
12
+ gem "pg"
13
+ gem "pry"
14
+ gem "simplecov"
data/README.md CHANGED
@@ -201,6 +201,21 @@ bundle exec rubocop
201
201
  bin/console
202
202
  ```
203
203
 
204
+ ## Release Management
205
+
206
+ This gem uses [Reissue](https://github.com/rails/reissue) for release management. To release a new version, perform
207
+ the following steps as you would with any other ruby gem:
208
+
209
+ ```bash
210
+ bundle exec rake build:checksum
211
+ ```
212
+ And then create a new release:
213
+ ```bash
214
+ bundle exec rake release
215
+ ```
216
+
217
+ The final step is to push your version bump branch, open a PR, and merge it.
218
+
204
219
  ## Dependencies
205
220
 
206
221
  - **Rails** >= 6.0
data/Rakefile CHANGED
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
+ require "reissue/gem"
4
5
  require "rspec/core/rake_task"
5
- require "rubocop/rake_task"
6
+ require "standard/rake"
7
+
8
+ Reissue::Task.create :reissue do |task|
9
+ task.version_file = "lib/newshound/version.rb"
10
+ task.fragment = :git
11
+ end
6
12
 
7
13
  RSpec::Core::RakeTask.new(:spec)
8
- RuboCop::RakeTask.new
9
14
 
10
- task default: %i[spec rubocop]
15
+ task default: %i[spec standard]
@@ -0,0 +1 @@
1
+ 4b38b6628a214ff2cf66a400e184a5659a2ba82ccf46efde37293d93dd77534ffe87d3dd41220e0cac43aabaed66318cbdb70b8cbf66988f744f04ead452bbc5
@@ -37,4 +37,4 @@ module Newshound
37
37
  end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -10,6 +10,10 @@ Newshound.configure do |config|
10
10
  # Default is 10
11
11
  config.exception_limit = 10
12
12
 
13
+ # Exception source to use for exceptions
14
+ # Default is :exception_track
15
+ config.exception_source = :exception_track # or :solid_errors
16
+
13
17
  # User roles that are authorized to view the Newshound banner
14
18
  # These should match the role values in your User model
15
19
  # Default is [:developer, :super_user]
@@ -29,4 +33,4 @@ end
29
33
  # # Your custom logic here
30
34
  # # Return true to show the banner, false to hide it
31
35
  # controller.current_user&.admin?
32
- # end
36
+ # end
@@ -3,7 +3,7 @@
3
3
  module Newshound
4
4
  class Configuration
5
5
  attr_accessor :exception_limit, :enabled, :authorized_roles,
6
- :current_user_method, :authorization_block
6
+ :current_user_method, :authorization_block, :exception_source
7
7
 
8
8
  def initialize
9
9
  @exception_limit = 10
@@ -11,6 +11,7 @@ module Newshound
11
11
  @authorized_roles = [:developer, :super_user]
12
12
  @current_user_method = :current_user
13
13
  @authorization_block = nil
14
+ @exception_source = :exception_track
14
15
  end
15
16
 
16
17
  # Allow custom authorization logic
@@ -22,4 +23,4 @@ module Newshound
22
23
  enabled
23
24
  end
24
25
  end
25
- end
26
+ end
@@ -5,8 +5,8 @@ module Newshound
5
5
  attr_reader :exception_source, :configuration, :time_range
6
6
 
7
7
  def initialize(exception_source: nil, configuration: nil, time_range: 24.hours)
8
- @exception_source = exception_source || (defined?(ExceptionTrack::Log) ? ExceptionTrack::Log : nil)
9
8
  @configuration = configuration || Newshound.configuration
9
+ @exception_source = resolve_exception_source(exception_source)
10
10
  @time_range = time_range
11
11
  end
12
12
 
@@ -29,23 +29,19 @@ module Newshound
29
29
  # Returns data formatted for the banner UI
30
30
  def banner_data
31
31
  {
32
- exceptions: recent_exceptions.map { |exception| format_exception_for_banner(exception) }
32
+ exceptions: recent_exceptions.map { |exception| exception_source.format_for_banner(exception) }
33
33
  }
34
34
  end
35
35
 
36
36
  private
37
37
 
38
- def recent_exceptions
39
- @recent_exceptions ||= fetch_recent_exceptions
38
+ def resolve_exception_source(source)
39
+ source ||= @configuration.exception_source
40
+ source.is_a?(Symbol) ? Exceptions.source(source) : source
40
41
  end
41
42
 
42
- def fetch_recent_exceptions
43
- return [] unless exception_source
44
-
45
- exception_source
46
- .where("created_at >= ?", time_range.ago)
47
- .order(created_at: :desc)
48
- .limit(configuration.exception_limit)
43
+ def recent_exceptions
44
+ @recent_exceptions ||= exception_source.recent(time_range: time_range, limit: configuration.exception_limit)
49
45
  end
50
46
 
51
47
  def format_exceptions
@@ -54,109 +50,12 @@ module Newshound
54
50
  type: "section",
55
51
  text: {
56
52
  type: "mrkdwn",
57
- text: format_exception_text(exception, index + 1)
53
+ text: exception_source.format_for_report(exception, index + 1)
58
54
  }
59
55
  }
60
56
  end
61
57
  end
62
58
 
63
- def format_exception_text(exception, number)
64
- details = parse_exception_details(exception)
65
-
66
- <<~TEXT
67
- *#{number}. #{exception_title(exception)}*
68
- • *Time:* #{exception.created_at.strftime('%I:%M %p')}
69
- #{format_controller(details)}
70
- #{format_message(exception, details)}
71
- TEXT
72
- end
73
-
74
- def exception_title(exception)
75
- if exception.respond_to?(:title) && exception.title.present?
76
- exception.title
77
- elsif exception.respond_to?(:exception_class) && exception.exception_class.present?
78
- exception.exception_class
79
- else
80
- "Unknown Exception"
81
- end
82
- end
83
-
84
- def parse_exception_details(exception)
85
- return {} unless exception.respond_to?(:body) && exception.body.present?
86
-
87
- JSON.parse(exception.body)
88
- rescue JSON::ParserError
89
- {}
90
- end
91
-
92
- def format_controller(details)
93
- return String.new unless details["controller_name"] && details["action_name"]
94
-
95
- "• *Controller:* #{details['controller_name']}##{details['action_name']}\n"
96
- end
97
-
98
- def format_message(exception, details = nil)
99
- details ||= parse_exception_details(exception)
100
-
101
- # Try to get message from different sources
102
- message = if details["message"].present?
103
- details["message"]
104
- elsif exception.respond_to?(:message) && exception.message.present?
105
- exception.message
106
- end
107
-
108
- return String.new unless message.present?
109
-
110
- message = message.to_s.truncate(100)
111
- "• *Message:* `#{message}`"
112
- end
113
-
114
- def exception_count(exception)
115
- return 0 unless exception_source
116
-
117
- # Use title for exception-track, exception_class for other systems
118
- if exception.respond_to?(:title) && exception.title.present?
119
- exception_source
120
- .where(title: exception.title)
121
- .where("created_at >= ?", time_range.ago)
122
- .count
123
- elsif exception.respond_to?(:exception_class)
124
- exception_source
125
- .where(exception_class: exception.exception_class)
126
- .where("created_at >= ?", time_range.ago)
127
- .count
128
- else
129
- 0
130
- end
131
- end
132
-
133
- def format_exception_for_banner(exception)
134
- details = parse_exception_details(exception)
135
-
136
- # Extract message
137
- message = if details["message"].present?
138
- details["message"].to_s
139
- elsif exception.respond_to?(:message) && exception.message.present?
140
- exception.message.to_s
141
- else
142
- String.new
143
- end
144
-
145
- # Extract location
146
- location = if details["controller_name"] && details["action_name"]
147
- "#{details['controller_name']}##{details['action_name']}"
148
- else
149
- String.new
150
- end
151
-
152
- {
153
- title: exception_title(exception),
154
- message: message.truncate(100),
155
- location: location,
156
- time: exception.created_at.strftime('%I:%M %p')
157
- }
158
- end
159
-
160
59
  def no_exceptions_block
161
60
  [
162
61
  {
@@ -169,4 +68,4 @@ module Newshound
169
68
  ]
170
69
  end
171
70
  end
172
- end
71
+ end
@@ -0,0 +1,40 @@
1
+ module Newshound
2
+ module Exceptions
3
+ # Base class for exception source adapters
4
+ # Each adapter is responsible for:
5
+ # 1. Fetching recent exceptions from its specific exception tracking system
6
+ # 2. Formatting exception data for reports and banners
7
+ #
8
+ # Subclasses must implement:
9
+ # - #recent(time_range:, limit:) - Returns a collection of exception records
10
+ # - #format_for_report(exception) - Formats a single exception for Slack/report display
11
+ # - #format_for_banner(exception) - Formats a single exception for banner UI
12
+ class Base
13
+ # Fetches recent exceptions from the exception tracking system
14
+ #
15
+ # @param time_range [ActiveSupport::Duration] Time duration to look back (e.g., 24.hours)
16
+ # @param limit [Integer] Maximum number of exceptions to return
17
+ # @return [Array] Collection of exception records
18
+ def recent(time_range:, limit:)
19
+ raise NotImplementedError, "#{self.class} must implement #recent"
20
+ end
21
+
22
+ # Formats an exception for report/Slack display
23
+ #
24
+ # @param exception [Object] Exception record from the tracking system
25
+ # @param number [Integer] Position number in the list
26
+ # @return [String] Formatted markdown text for display
27
+ def format_for_report(exception, number)
28
+ raise NotImplementedError, "#{self.class} must implement #format_for_report"
29
+ end
30
+
31
+ # Formats an exception for banner UI display
32
+ #
33
+ # @param exception [Object] Exception record from the tracking system
34
+ # @return [Hash] Hash with keys: :title, :message, :location, :time
35
+ def format_for_banner(exception)
36
+ raise NotImplementedError, "#{self.class} must implement #format_for_banner"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,71 @@
1
+ module Newshound
2
+ module Exceptions
3
+ class ExceptionTrack < Base
4
+ def recent(time_range:, limit:)
5
+ ::ExceptionTrack::Log
6
+ .where("created_at >= ?", time_range.ago)
7
+ .order(created_at: :desc)
8
+ .limit(limit)
9
+ end
10
+
11
+ def format_for_report(exception, number)
12
+ details = parse_exception_details(exception)
13
+
14
+ <<~TEXT
15
+ *#{number}. #{details[:title]}*
16
+ • *Time:* #{exception.created_at.strftime("%I:%M %p")}
17
+ #{format_controller(details)}
18
+ #{format_message(details)}
19
+ TEXT
20
+ end
21
+
22
+ def format_for_banner(exception)
23
+ details = parse_exception_details(exception)
24
+
25
+ {
26
+ title: details[:title],
27
+ message: details[:message].truncate(100),
28
+ location: details[:location],
29
+ time: exception.created_at.strftime("%I:%M %p")
30
+ }
31
+ end
32
+
33
+ private
34
+
35
+ def parse_exception_details(exception)
36
+ body_data = parse_body(exception)
37
+ controller_name = body_data["controller_name"]
38
+ action_name = body_data["action_name"]
39
+
40
+ {
41
+ title: exception.try(:title).presence || exception.try(:exception_class).presence || "Unknown Exception",
42
+ message: body_data["message"].presence&.to_s || exception.try(:message).presence&.to_s || +"",
43
+ location: (controller_name && action_name) ? "#{controller_name}##{action_name}" : +"",
44
+ controller_name: controller_name,
45
+ action_name: action_name
46
+ }
47
+ end
48
+
49
+ def parse_body(exception)
50
+ return {} unless exception.respond_to?(:body) && exception.body.present?
51
+
52
+ JSON.parse(exception.body)
53
+ rescue JSON::ParserError
54
+ {}
55
+ end
56
+
57
+ def format_controller(details)
58
+ return +"" unless details in {controller_name: String, action_name: String}
59
+
60
+ "• *Controller:* #{details[:location]}\n"
61
+ end
62
+
63
+ def format_message(details)
64
+ return +"" unless details in {message: String}
65
+
66
+ message = details[:message].to_s.truncate(100)
67
+ "• *Message:* `#{message}`"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,78 @@
1
+ module Newshound
2
+ module Exceptions
3
+ class SolidErrors < Base
4
+ def recent(time_range:, limit:)
5
+ ::SolidErrors::Occurrence
6
+ .where("created_at >= ?", time_range.ago)
7
+ .order(created_at: :desc)
8
+ .limit(limit)
9
+ end
10
+
11
+ def format_for_report(exception, number)
12
+ details = parse_exception_details(exception)
13
+
14
+ <<~TEXT
15
+ *#{number}. #{details[:title]}*
16
+ • *Time:* #{exception.created_at.strftime("%I:%M %p")}
17
+ #{format_controller(details)}
18
+ #{format_message(details)}
19
+ TEXT
20
+ end
21
+
22
+ def format_for_banner(exception)
23
+ details = parse_exception_details(exception)
24
+
25
+ {
26
+ title: details[:title],
27
+ message: details[:message].truncate(100),
28
+ location: details[:location],
29
+ time: exception.created_at.strftime("%I:%M %p")
30
+ }
31
+ end
32
+
33
+ private
34
+
35
+ def parse_exception_details(exception)
36
+ context_data = parse_context(exception)
37
+ controller = context_data["controller"]
38
+ action = context_data["action"]
39
+
40
+ {
41
+ title: exception.try(:error_class).presence || "Unknown Exception",
42
+ message: exception.try(:message).presence&.to_s || context_data["message"].presence&.to_s || +"",
43
+ location: (controller && action) ? "#{controller}##{action}" : +"",
44
+ controller: controller,
45
+ action: action
46
+ }
47
+ end
48
+
49
+ def parse_context(exception)
50
+ return {} unless exception.respond_to?(:context) && exception.context.present?
51
+
52
+ case exception.context
53
+ when Hash
54
+ exception.context
55
+ when String
56
+ JSON.parse(exception.context)
57
+ else
58
+ {}
59
+ end
60
+ rescue JSON::ParserError
61
+ {}
62
+ end
63
+
64
+ def format_controller(details)
65
+ return +"" unless details in {controller: String, action: String}
66
+
67
+ "• *Controller:* #{details[:location]}\n"
68
+ end
69
+
70
+ def format_message(details)
71
+ return +"" unless details in {message: String}
72
+
73
+ message = details[:message].to_s.truncate(100)
74
+ "• *Message:* `#{message}`"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,12 @@
1
+ Dir[File.join(__dir__, "exceptions", "*.rb")].each { |file| require file }
2
+
3
+ module Newshound
4
+ module Exceptions
5
+ def self.source(source)
6
+ constant = constants.find { |c| c.to_s.gsub(/(?<!^)([A-Z])/, "_\\1").downcase == source.to_s }
7
+ raise "Invalid exception source: #{source}" unless constant
8
+
9
+ const_get(constant).new
10
+ end
11
+ end
12
+ end
@@ -15,7 +15,7 @@ module Newshound
15
15
  return [status, headers, response] unless status == 200
16
16
 
17
17
  # Check authorization
18
- controller = env['action_controller.instance']
18
+ controller = env["action_controller.instance"]
19
19
  return [status, headers, response] unless controller
20
20
  return [status, headers, response] unless Newshound::Authorization.authorized?(controller)
21
21
 
@@ -26,8 +26,8 @@ module Newshound
26
26
  new_response = inject_banner(response, banner_html)
27
27
 
28
28
  # Update Content-Length header
29
- if headers['Content-Length']
30
- headers['Content-Length'] = new_response.bytesize.to_s
29
+ if headers["Content-Length"]
30
+ headers["Content-Length"] = new_response.bytesize.to_s
31
31
  end
32
32
 
33
33
  [status, headers, [new_response]]
@@ -36,8 +36,8 @@ module Newshound
36
36
  private
37
37
 
38
38
  def html_response?(headers)
39
- content_type = headers['Content-Type']
40
- content_type && content_type.include?('text/html')
39
+ content_type = headers["Content-Type"]
40
+ content_type&.include?("text/html")
41
41
  end
42
42
 
43
43
  def inject_banner(response, banner_html)
@@ -48,7 +48,7 @@ module Newshound
48
48
  end
49
49
 
50
50
  def response_body(response)
51
- body = String.new
51
+ body = +""
52
52
  response.each { |part| body << part }
53
53
  body
54
54
  end
@@ -68,7 +68,7 @@ module Newshound
68
68
  <<~HTML
69
69
  <div id="newshound-banner" class="newshound-banner newshound-collapsed">
70
70
  #{render_styles}
71
- <div class="newshound-header" onclick="document.getElementById('newshound-banner').classList.toggle('newshound-collapsed')">
71
+ <div class="newshound-header" onclick="document.getElementById('newshound-banner').classList.toggle('newshound-collapsed'); window.newshoundUpdatePadding();">
72
72
  <span class="newshound-title">
73
73
  🐕 Newshound
74
74
  #{summary_badge(exception_data, job_data)}
@@ -80,12 +80,46 @@ module Newshound
80
80
  #{render_jobs(job_data)}
81
81
  </div>
82
82
  </div>
83
+ #{render_script}
83
84
  HTML
84
85
  end
85
86
 
87
+ def render_script
88
+ <<~JS
89
+ <script>
90
+ (function() {
91
+ window.newshoundUpdatePadding = function() {
92
+ // Wait for transition to complete
93
+ setTimeout(function() {
94
+ var banner = document.getElementById('newshound-banner');
95
+ if (banner) {
96
+ var height = banner.offsetHeight;
97
+ document.body.style.paddingTop = height + 'px';
98
+ }
99
+ }, 300);
100
+ };
101
+
102
+ // Set initial padding after page load
103
+ if (document.readyState === 'loading') {
104
+ document.addEventListener('DOMContentLoaded', window.newshoundUpdatePadding);
105
+ } else {
106
+ window.newshoundUpdatePadding();
107
+ }
108
+
109
+ // Also update on window resize
110
+ window.addEventListener('resize', window.newshoundUpdatePadding);
111
+ })();
112
+ </script>
113
+ JS
114
+ end
115
+
86
116
  def render_styles
87
117
  <<~CSS
88
118
  <style>
119
+ body {
120
+ padding-top: 50px;
121
+ transition: padding-top 0.3s ease-out;
122
+ }
89
123
  .newshound-banner {
90
124
  position: fixed;
91
125
  top: 0;
@@ -275,13 +309,13 @@ module Newshound
275
309
  end
276
310
 
277
311
  def escape_html(text)
278
- return String.new unless text.present?
312
+ return +"" unless text.present?
279
313
  text.to_s
280
- .gsub('&', '&amp;')
281
- .gsub('<', '&lt;')
282
- .gsub('>', '&gt;')
283
- .gsub('"', '&quot;')
284
- .gsub("'", '&#39;')
314
+ .gsub("&", "&amp;")
315
+ .gsub("<", "&lt;")
316
+ .gsub(">", "&gt;")
317
+ .gsub('"', "&quot;")
318
+ .gsub("'", "&#39;")
285
319
  end
286
320
  end
287
321
  end
@@ -6,7 +6,7 @@ module Newshound
6
6
 
7
7
  def initialize(job_source: nil, logger: nil)
8
8
  @job_source = job_source || (defined?(::Que::Job) ? ::Que::Job : nil)
9
- @logger = logger || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT))
9
+ @logger = logger || (defined?(Rails) ? Rails.logger : Logger.new($stdout))
10
10
  end
11
11
 
12
12
  def generate_report
@@ -42,9 +42,9 @@ module Newshound
42
42
 
43
43
  def job_counts_section
44
44
  counts = job_counts_by_type
45
-
45
+
46
46
  return no_jobs_section if counts.empty?
47
-
47
+
48
48
  {
49
49
  type: "section",
50
50
  text: {
@@ -81,25 +81,25 @@ module Newshound
81
81
 
82
82
  hash[job_class][:total] += count
83
83
  end
84
- rescue StandardError => e
84
+ rescue => e
85
85
  logger.error "Failed to fetch job counts: #{e.message}"
86
86
  {}
87
87
  end
88
88
 
89
89
  def format_job_counts(counts)
90
90
  lines = ["*Job Counts by Type:*"]
91
-
91
+
92
92
  counts.each do |job_class, stats|
93
- status_emoji = stats[:failed] > 0 ? "⚠️" : "✅"
93
+ status_emoji = (stats[:failed] > 0) ? "⚠️" : "✅"
94
94
  lines << "• #{status_emoji} *#{job_class}*: #{stats[:total]} total (#{stats[:success]} success, #{stats[:failed]} failed)"
95
95
  end
96
-
96
+
97
97
  lines.join("\n")
98
98
  end
99
99
 
100
100
  def queue_health_section
101
101
  stats = queue_statistics
102
-
102
+
103
103
  {
104
104
  type: "section",
105
105
  text: {
@@ -122,7 +122,7 @@ module Newshound
122
122
  failed: count_jobs("error_count > 0 AND finished_at IS NULL"),
123
123
  finished_today: count_jobs("finished_at >= #{beginning_of_day}")
124
124
  }
125
- rescue StandardError => e
125
+ rescue => e
126
126
  logger.error "Failed to fetch Que statistics: #{e.message}"
127
127
  default_stats
128
128
  end
@@ -134,12 +134,16 @@ module Newshound
134
134
  end
135
135
 
136
136
  def default_stats
137
- { ready: 0, scheduled: 0, failed: 0, finished_today: 0 }
137
+ {ready: 0, scheduled: 0, failed: 0, finished_today: 0}
138
138
  end
139
139
 
140
140
  def format_queue_health(stats)
141
- health_emoji = stats[:failed] > 10 ? "🔴" : stats[:failed] > 5 ? "🟡" : "🟢"
142
-
141
+ health_emoji = if stats[:failed] > 10
142
+ "🔴"
143
+ else
144
+ (stats[:failed] > 5) ? "🟡" : "🟢"
145
+ end
146
+
143
147
  <<~TEXT
144
148
  *Queue Health #{health_emoji}*
145
149
  • *Ready to Run:* #{stats[:ready]}
@@ -159,4 +163,4 @@ module Newshound
159
163
  }
160
164
  end
161
165
  end
162
- end
166
+ end
@@ -19,9 +19,9 @@ module Newshound
19
19
  puts "Newshound Configuration:"
20
20
  puts " Enabled: #{config.enabled}"
21
21
  puts " Exception Limit: #{config.exception_limit}"
22
- puts " Authorized Roles: #{config.authorized_roles.join(', ')}"
22
+ puts " Authorized Roles: #{config.authorized_roles.join(", ")}"
23
23
  puts " Current User Method: #{config.current_user_method}"
24
- puts " Custom Authorization: #{config.authorization_block.present? ? 'Yes' : 'No'}"
24
+ puts " Custom Authorization: #{config.authorization_block.present? ? "Yes" : "No"}"
25
25
  end
26
26
 
27
27
  desc "Test exception reporter"
@@ -56,4 +56,4 @@ module Newshound
56
56
  end
57
57
  end
58
58
  end
59
- end
59
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Newshound
4
- VERSION = "0.2.1"
5
- end
4
+ VERSION = "0.2.3"
5
+ end
data/lib/newshound.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "newshound/version"
4
4
  require_relative "newshound/configuration"
5
+ require_relative "newshound/exceptions"
5
6
  require_relative "newshound/exception_reporter"
6
7
  require_relative "newshound/que_reporter"
7
8
  require_relative "newshound/authorization"
@@ -25,4 +26,4 @@ module Newshound
25
26
  configuration.authorize_with(&block)
26
27
  end
27
28
  end
28
- end
29
+ end
data/newshound.gemspec CHANGED
@@ -5,14 +5,14 @@ require_relative "lib/newshound/version"
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "newshound"
7
7
  spec.version = Newshound::VERSION
8
- spec.authors = ["salbanez"]
9
- spec.email = ["salbanez@example.com"]
8
+ spec.authors = ["Savannah Moore"]
9
+ spec.email = ["savannah.albanez@sofwarellc.com"]
10
10
 
11
11
  spec.summary = "Real-time web UI banner for monitoring Que jobs and exception tracking"
12
12
  spec.description = "Newshound displays exceptions and job statuses in a collapsible banner for authorized users in your Rails app"
13
- spec.homepage = "https://github.com/salbanez/newshound"
13
+ spec.homepage = "https://github.com/SOFware/newshound"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.7.0"
15
+ spec.required_ruby_version = ">= 3.1.0"
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = spec.homepage
@@ -30,5 +30,4 @@ Gem::Specification.new do |spec|
30
30
  # Runtime dependencies
31
31
  spec.add_dependency "rails", ">= 6.0"
32
32
  spec.add_dependency "que", ">= 1.0"
33
- spec.add_dependency "exception-track", ">= 0.1"
34
- end
33
+ end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newshound
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
- - salbanez
7
+ - Savannah Moore
8
8
  bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
@@ -37,52 +37,44 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.0'
40
- - !ruby/object:Gem::Dependency
41
- name: exception-track
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '0.1'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0.1'
54
40
  description: Newshound displays exceptions and job statuses in a collapsible banner
55
41
  for authorized users in your Rails app
56
42
  email:
57
- - salbanez@example.com
43
+ - savannah.albanez@sofwarellc.com
58
44
  executables: []
59
45
  extensions: []
60
46
  extra_rdoc_files: []
61
47
  files:
62
48
  - ".rspec"
63
49
  - ".tool-versions"
50
+ - CHANGELOG.md
64
51
  - Gemfile
65
52
  - README.md
66
53
  - Rakefile
67
54
  - TRANSPORT_USAGE.md
55
+ - checksums/newshound-0.2.3.gem.sha512
68
56
  - lib/generators/newshound/install/install_generator.rb
69
57
  - lib/generators/newshound/install/templates/newshound.rb
70
58
  - lib/newshound.rb
71
59
  - lib/newshound/authorization.rb
72
60
  - lib/newshound/configuration.rb
73
61
  - lib/newshound/exception_reporter.rb
62
+ - lib/newshound/exceptions.rb
63
+ - lib/newshound/exceptions/base.rb
64
+ - lib/newshound/exceptions/exception_track.rb
65
+ - lib/newshound/exceptions/solid_errors.rb
74
66
  - lib/newshound/middleware/banner_injector.rb
75
67
  - lib/newshound/que_reporter.rb
76
68
  - lib/newshound/railtie.rb
77
69
  - lib/newshound/version.rb
78
70
  - newshound.gemspec
79
- homepage: https://github.com/salbanez/newshound
71
+ homepage: https://github.com/SOFware/newshound
80
72
  licenses:
81
73
  - MIT
82
74
  metadata:
83
- homepage_uri: https://github.com/salbanez/newshound
84
- source_code_uri: https://github.com/salbanez/newshound
85
- changelog_uri: https://github.com/salbanez/newshound/blob/main/CHANGELOG.md
75
+ homepage_uri: https://github.com/SOFware/newshound
76
+ source_code_uri: https://github.com/SOFware/newshound
77
+ changelog_uri: https://github.com/SOFware/newshound/blob/main/CHANGELOG.md
86
78
  rdoc_options: []
87
79
  require_paths:
88
80
  - lib
@@ -90,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
82
  requirements:
91
83
  - - ">="
92
84
  - !ruby/object:Gem::Version
93
- version: 2.7.0
85
+ version: 3.1.0
94
86
  required_rubygems_version: !ruby/object:Gem::Requirement
95
87
  requirements:
96
88
  - - ">="