newshound 0.1.0 → 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/.rspec +3 -0
- data/.tool-versions +1 -0
- data/Gemfile +9 -3
- data/README.md +154 -75
- data/TRANSPORT_USAGE.md +117 -0
- data/lib/generators/newshound/install/install_generator.rb +40 -0
- data/lib/generators/newshound/install/templates/newshound.rb +32 -0
- data/lib/newshound/authorization.rb +46 -0
- data/lib/newshound/configuration.rb +12 -11
- data/lib/newshound/exception_reporter.rb +18 -8
- data/lib/newshound/middleware/banner_injector.rb +288 -0
- data/lib/newshound/que_reporter.rb +20 -10
- data/lib/newshound/railtie.rb +32 -36
- data/lib/newshound/version.rb +1 -1
- data/lib/newshound.rb +5 -43
- data/newshound.gemspec +34 -0
- metadata +12 -105
- data/lib/newshound/daily_report_job.rb +0 -19
- data/lib/newshound/scheduler.rb +0 -41
- data/lib/newshound/slack_notifier.rb +0 -61
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Newshound
|
|
4
|
+
module Middleware
|
|
5
|
+
class BannerInjector
|
|
6
|
+
def initialize(app)
|
|
7
|
+
@app = app
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(env)
|
|
11
|
+
status, headers, response = @app.call(env)
|
|
12
|
+
|
|
13
|
+
# Only inject into HTML responses
|
|
14
|
+
return [status, headers, response] unless html_response?(headers)
|
|
15
|
+
return [status, headers, response] unless status == 200
|
|
16
|
+
|
|
17
|
+
# Check authorization
|
|
18
|
+
controller = env['action_controller.instance']
|
|
19
|
+
return [status, headers, response] unless controller
|
|
20
|
+
return [status, headers, response] unless Newshound::Authorization.authorized?(controller)
|
|
21
|
+
|
|
22
|
+
# Get banner HTML
|
|
23
|
+
banner_html = generate_banner_html
|
|
24
|
+
|
|
25
|
+
# Inject banner after <body> tag
|
|
26
|
+
new_response = inject_banner(response, banner_html)
|
|
27
|
+
|
|
28
|
+
# Update Content-Length header
|
|
29
|
+
if headers['Content-Length']
|
|
30
|
+
headers['Content-Length'] = new_response.bytesize.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
[status, headers, [new_response]]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def html_response?(headers)
|
|
39
|
+
content_type = headers['Content-Type']
|
|
40
|
+
content_type && content_type.include?('text/html')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def inject_banner(response, banner_html)
|
|
44
|
+
body = response_body(response)
|
|
45
|
+
|
|
46
|
+
# Inject after <body> tag
|
|
47
|
+
body.sub(/(<body[^>]*>)/i, "\\1\n#{banner_html}")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def response_body(response)
|
|
51
|
+
body = ""
|
|
52
|
+
response.each { |part| body << part }
|
|
53
|
+
body
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def generate_banner_html
|
|
57
|
+
exception_reporter = Newshound::ExceptionReporter.new
|
|
58
|
+
que_reporter = Newshound::QueReporter.new
|
|
59
|
+
|
|
60
|
+
exception_data = exception_reporter.report
|
|
61
|
+
job_data = que_reporter.report
|
|
62
|
+
|
|
63
|
+
# Generate HTML from template
|
|
64
|
+
render_banner(exception_data, job_data)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def render_banner(exception_data, job_data)
|
|
68
|
+
<<~HTML
|
|
69
|
+
<div id="newshound-banner" class="newshound-banner newshound-collapsed">
|
|
70
|
+
#{render_styles}
|
|
71
|
+
<div class="newshound-header" onclick="document.getElementById('newshound-banner').classList.toggle('newshound-collapsed')">
|
|
72
|
+
<span class="newshound-title">
|
|
73
|
+
🐕 Newshound
|
|
74
|
+
#{summary_badge(exception_data, job_data)}
|
|
75
|
+
</span>
|
|
76
|
+
<span class="newshound-toggle">▼</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="newshound-content">
|
|
79
|
+
#{render_exceptions(exception_data)}
|
|
80
|
+
#{render_jobs(job_data)}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
HTML
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def render_styles
|
|
87
|
+
<<~CSS
|
|
88
|
+
<style>
|
|
89
|
+
.newshound-banner {
|
|
90
|
+
position: fixed;
|
|
91
|
+
top: 0;
|
|
92
|
+
left: 0;
|
|
93
|
+
right: 0;
|
|
94
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
95
|
+
color: white;
|
|
96
|
+
z-index: 10000;
|
|
97
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
|
98
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
99
|
+
font-size: 14px;
|
|
100
|
+
}
|
|
101
|
+
.newshound-header {
|
|
102
|
+
padding: 12px 20px;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
display: flex;
|
|
105
|
+
justify-content: space-between;
|
|
106
|
+
align-items: center;
|
|
107
|
+
user-select: none;
|
|
108
|
+
}
|
|
109
|
+
.newshound-title {
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 10px;
|
|
114
|
+
}
|
|
115
|
+
.newshound-badge {
|
|
116
|
+
display: inline-block;
|
|
117
|
+
padding: 2px 8px;
|
|
118
|
+
border-radius: 12px;
|
|
119
|
+
font-size: 12px;
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
background: rgba(255,255,255,0.2);
|
|
122
|
+
}
|
|
123
|
+
.newshound-badge.error {
|
|
124
|
+
background: #ef4444;
|
|
125
|
+
}
|
|
126
|
+
.newshound-badge.warning {
|
|
127
|
+
background: #f59e0b;
|
|
128
|
+
}
|
|
129
|
+
.newshound-badge.success {
|
|
130
|
+
background: #10b981;
|
|
131
|
+
}
|
|
132
|
+
.newshound-toggle {
|
|
133
|
+
transition: transform 0.3s;
|
|
134
|
+
}
|
|
135
|
+
.newshound-banner.newshound-collapsed .newshound-toggle {
|
|
136
|
+
transform: rotate(-90deg);
|
|
137
|
+
}
|
|
138
|
+
.newshound-content {
|
|
139
|
+
max-height: 400px;
|
|
140
|
+
overflow-y: auto;
|
|
141
|
+
border-top: 1px solid rgba(255,255,255,0.2);
|
|
142
|
+
transition: max-height 0.3s ease-out;
|
|
143
|
+
}
|
|
144
|
+
.newshound-banner.newshound-collapsed .newshound-content {
|
|
145
|
+
max-height: 0;
|
|
146
|
+
overflow: hidden;
|
|
147
|
+
border-top: none;
|
|
148
|
+
}
|
|
149
|
+
.newshound-section {
|
|
150
|
+
padding: 15px 20px;
|
|
151
|
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
152
|
+
}
|
|
153
|
+
.newshound-section:last-child {
|
|
154
|
+
border-bottom: none;
|
|
155
|
+
}
|
|
156
|
+
.newshound-section-title {
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
margin-bottom: 10px;
|
|
159
|
+
font-size: 15px;
|
|
160
|
+
}
|
|
161
|
+
.newshound-item {
|
|
162
|
+
background: rgba(255,255,255,0.1);
|
|
163
|
+
padding: 10px;
|
|
164
|
+
margin-bottom: 8px;
|
|
165
|
+
border-radius: 6px;
|
|
166
|
+
font-size: 13px;
|
|
167
|
+
}
|
|
168
|
+
.newshound-item:last-child {
|
|
169
|
+
margin-bottom: 0;
|
|
170
|
+
}
|
|
171
|
+
.newshound-item-title {
|
|
172
|
+
font-weight: 600;
|
|
173
|
+
margin-bottom: 4px;
|
|
174
|
+
}
|
|
175
|
+
.newshound-item-detail {
|
|
176
|
+
opacity: 0.9;
|
|
177
|
+
font-size: 12px;
|
|
178
|
+
}
|
|
179
|
+
.newshound-grid {
|
|
180
|
+
display: grid;
|
|
181
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
182
|
+
gap: 10px;
|
|
183
|
+
}
|
|
184
|
+
.newshound-stat {
|
|
185
|
+
background: rgba(255,255,255,0.1);
|
|
186
|
+
padding: 12px;
|
|
187
|
+
border-radius: 6px;
|
|
188
|
+
text-align: center;
|
|
189
|
+
}
|
|
190
|
+
.newshound-stat-value {
|
|
191
|
+
font-size: 24px;
|
|
192
|
+
font-weight: 700;
|
|
193
|
+
display: block;
|
|
194
|
+
}
|
|
195
|
+
.newshound-stat-label {
|
|
196
|
+
font-size: 11px;
|
|
197
|
+
opacity: 0.8;
|
|
198
|
+
text-transform: uppercase;
|
|
199
|
+
letter-spacing: 0.5px;
|
|
200
|
+
}
|
|
201
|
+
</style>
|
|
202
|
+
CSS
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def summary_badge(exception_data, job_data)
|
|
206
|
+
exception_count = exception_data[:exceptions]&.length || 0
|
|
207
|
+
failed_jobs = job_data.dig(:queue_stats, :failed) || 0
|
|
208
|
+
|
|
209
|
+
if exception_count > 0 || failed_jobs > 10
|
|
210
|
+
badge_class = "error"
|
|
211
|
+
text = "#{exception_count} exceptions, #{failed_jobs} failed jobs"
|
|
212
|
+
elsif failed_jobs > 5
|
|
213
|
+
badge_class = "warning"
|
|
214
|
+
text = "#{failed_jobs} failed jobs"
|
|
215
|
+
else
|
|
216
|
+
badge_class = "success"
|
|
217
|
+
text = "All clear"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
%(<span class="newshound-badge #{badge_class}">#{text}</span>)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def render_exceptions(data)
|
|
224
|
+
exceptions = data[:exceptions] || []
|
|
225
|
+
|
|
226
|
+
if exceptions.empty?
|
|
227
|
+
return %(<div class="newshound-section"><div class="newshound-section-title">✅ Exceptions</div><div class="newshound-item">No exceptions in the last 24 hours</div></div>)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
items = exceptions.take(5).map do |ex|
|
|
231
|
+
<<~HTML
|
|
232
|
+
<div class="newshound-item">
|
|
233
|
+
<div class="newshound-item-title">#{escape_html(ex[:title])}</div>
|
|
234
|
+
<div class="newshound-item-detail">
|
|
235
|
+
#{escape_html(ex[:message])} • #{escape_html(ex[:location])} • #{escape_html(ex[:time])}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
HTML
|
|
239
|
+
end.join
|
|
240
|
+
|
|
241
|
+
<<~HTML
|
|
242
|
+
<div class="newshound-section">
|
|
243
|
+
<div class="newshound-section-title">⚠️ Recent Exceptions (#{exceptions.length})</div>
|
|
244
|
+
#{items}
|
|
245
|
+
</div>
|
|
246
|
+
HTML
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def render_jobs(data)
|
|
250
|
+
stats = data[:queue_stats] || {}
|
|
251
|
+
|
|
252
|
+
<<~HTML
|
|
253
|
+
<div class="newshound-section">
|
|
254
|
+
<div class="newshound-section-title">📊 Job Queue Status</div>
|
|
255
|
+
<div class="newshound-grid">
|
|
256
|
+
<div class="newshound-stat">
|
|
257
|
+
<span class="newshound-stat-value">#{stats[:ready_to_run] || 0}</span>
|
|
258
|
+
<span class="newshound-stat-label">Ready</span>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="newshound-stat">
|
|
261
|
+
<span class="newshound-stat-value">#{stats[:scheduled] || 0}</span>
|
|
262
|
+
<span class="newshound-stat-label">Scheduled</span>
|
|
263
|
+
</div>
|
|
264
|
+
<div class="newshound-stat">
|
|
265
|
+
<span class="newshound-stat-value">#{stats[:failed] || 0}</span>
|
|
266
|
+
<span class="newshound-stat-label">Failed</span>
|
|
267
|
+
</div>
|
|
268
|
+
<div class="newshound-stat">
|
|
269
|
+
<span class="newshound-stat-value">#{stats[:completed_today] || 0}</span>
|
|
270
|
+
<span class="newshound-stat-label">Completed Today</span>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
HTML
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def escape_html(text)
|
|
278
|
+
return "" unless text
|
|
279
|
+
text.to_s
|
|
280
|
+
.gsub('&', '&')
|
|
281
|
+
.gsub('<', '<')
|
|
282
|
+
.gsub('>', '>')
|
|
283
|
+
.gsub('"', '"')
|
|
284
|
+
.gsub("'", ''')
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Newshound
|
|
4
4
|
class QueReporter
|
|
5
|
+
attr_reader :job_source, :logger
|
|
6
|
+
|
|
7
|
+
def initialize(job_source: nil, logger: nil)
|
|
8
|
+
@job_source = job_source || (defined?(::Que::Job) ? ::Que::Job : nil)
|
|
9
|
+
@logger = logger || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT))
|
|
10
|
+
end
|
|
11
|
+
|
|
5
12
|
def generate_report
|
|
6
13
|
[
|
|
7
14
|
{
|
|
@@ -33,9 +40,9 @@ module Newshound
|
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
def job_counts_by_type
|
|
36
|
-
return {} unless
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
return {} unless job_source
|
|
44
|
+
|
|
45
|
+
job_source
|
|
39
46
|
.group(:job_class)
|
|
40
47
|
.group(:error_count)
|
|
41
48
|
.count
|
|
@@ -76,16 +83,19 @@ module Newshound
|
|
|
76
83
|
end
|
|
77
84
|
|
|
78
85
|
def queue_statistics
|
|
79
|
-
return default_stats unless
|
|
80
|
-
|
|
86
|
+
return default_stats unless job_source
|
|
87
|
+
|
|
88
|
+
current_time = Time.now
|
|
89
|
+
beginning_of_day = Date.today.to_time
|
|
90
|
+
|
|
81
91
|
{
|
|
82
|
-
ready:
|
|
83
|
-
scheduled:
|
|
84
|
-
failed:
|
|
85
|
-
finished_today:
|
|
92
|
+
ready: job_source.where(finished_at: nil, expired_at: nil).where("run_at <= ?", current_time).count,
|
|
93
|
+
scheduled: job_source.where(finished_at: nil, expired_at: nil).where("run_at > ?", current_time).count,
|
|
94
|
+
failed: job_source.where.not(error_count: 0).where(finished_at: nil).count,
|
|
95
|
+
finished_today: job_source.where("finished_at >= ?", beginning_of_day).count
|
|
86
96
|
}
|
|
87
97
|
rescue StandardError => e
|
|
88
|
-
|
|
98
|
+
logger.error "Failed to fetch Que statistics: #{e.message}"
|
|
89
99
|
default_stats
|
|
90
100
|
end
|
|
91
101
|
|
data/lib/newshound/railtie.rb
CHANGED
|
@@ -4,59 +4,55 @@ require "rails/railtie"
|
|
|
4
4
|
|
|
5
5
|
module Newshound
|
|
6
6
|
class Railtie < Rails::Railtie
|
|
7
|
+
# Register middleware to inject banner
|
|
8
|
+
initializer "newshound.middleware" do |app|
|
|
9
|
+
if Newshound.configuration.enabled
|
|
10
|
+
app.middleware.use Newshound::Middleware::BannerInjector
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
rake_tasks do
|
|
8
15
|
namespace :newshound do
|
|
9
|
-
desc "Send daily report immediately"
|
|
10
|
-
task report_now: :environment do
|
|
11
|
-
puts "Sending Newshound daily report..."
|
|
12
|
-
Newshound.report!
|
|
13
|
-
puts "Report sent successfully!"
|
|
14
|
-
rescue StandardError => e
|
|
15
|
-
puts "Failed to send report: #{e.message}"
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
desc "Schedule daily report job"
|
|
19
|
-
task schedule: :environment do
|
|
20
|
-
puts "Scheduling Newshound daily report..."
|
|
21
|
-
Newshound::Scheduler.run_now!
|
|
22
|
-
puts "Job enqueued successfully!"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
16
|
desc "Show current configuration"
|
|
26
17
|
task config: :environment do
|
|
27
18
|
config = Newshound.configuration
|
|
28
19
|
puts "Newshound Configuration:"
|
|
29
20
|
puts " Enabled: #{config.enabled}"
|
|
30
|
-
puts " Slack Webhook: #{config.slack_webhook_url.present? ? '[CONFIGURED]' : '[NOT SET]'}"
|
|
31
|
-
puts " Slack Channel: #{config.slack_channel}"
|
|
32
|
-
puts " Report Time: #{config.report_time}"
|
|
33
21
|
puts " Exception Limit: #{config.exception_limit}"
|
|
34
|
-
puts "
|
|
35
|
-
puts "
|
|
22
|
+
puts " Authorized Roles: #{config.authorized_roles.join(', ')}"
|
|
23
|
+
puts " Current User Method: #{config.current_user_method}"
|
|
24
|
+
puts " Custom Authorization: #{config.authorization_block.present? ? 'Yes' : 'No'}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "Test exception reporter"
|
|
28
|
+
task test_exceptions: :environment do
|
|
29
|
+
reporter = Newshound::ExceptionReporter.new
|
|
30
|
+
data = reporter.report
|
|
31
|
+
puts "Exception Report:"
|
|
32
|
+
puts " Total exceptions: #{data[:exceptions]&.length || 0}"
|
|
33
|
+
data[:exceptions]&.each_with_index do |ex, i|
|
|
34
|
+
puts " #{i + 1}. #{ex[:title]} - #{ex[:message]}"
|
|
35
|
+
end
|
|
36
36
|
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
else
|
|
50
|
-
Rails.logger.warn "Newshound: que-scheduler not found. Daily reports will need to be triggered manually."
|
|
38
|
+
desc "Test job reporter"
|
|
39
|
+
task test_jobs: :environment do
|
|
40
|
+
reporter = Newshound::QueReporter.new
|
|
41
|
+
data = reporter.report
|
|
42
|
+
puts "Job Queue Report:"
|
|
43
|
+
puts " Ready to run: #{data.dig(:queue_stats, :ready_to_run)}"
|
|
44
|
+
puts " Scheduled: #{data.dig(:queue_stats, :scheduled)}"
|
|
45
|
+
puts " Failed: #{data.dig(:queue_stats, :failed)}"
|
|
46
|
+
puts " Completed today: #{data.dig(:queue_stats, :completed_today)}"
|
|
51
47
|
end
|
|
52
48
|
end
|
|
53
49
|
end
|
|
54
50
|
|
|
55
51
|
config.after_initialize do
|
|
56
52
|
if Newshound.configuration.valid?
|
|
57
|
-
Rails.logger.info "Newshound initialized
|
|
53
|
+
Rails.logger.info "Newshound initialized - banner will be shown to authorized users"
|
|
58
54
|
else
|
|
59
|
-
Rails.logger.warn "Newshound is
|
|
55
|
+
Rails.logger.warn "Newshound is disabled"
|
|
60
56
|
end
|
|
61
57
|
end
|
|
62
58
|
end
|
data/lib/newshound/version.rb
CHANGED
data/lib/newshound.rb
CHANGED
|
@@ -4,9 +4,8 @@ require_relative "newshound/version"
|
|
|
4
4
|
require_relative "newshound/configuration"
|
|
5
5
|
require_relative "newshound/exception_reporter"
|
|
6
6
|
require_relative "newshound/que_reporter"
|
|
7
|
-
require_relative "newshound/
|
|
8
|
-
require_relative "newshound/
|
|
9
|
-
require_relative "newshound/scheduler"
|
|
7
|
+
require_relative "newshound/authorization"
|
|
8
|
+
require_relative "newshound/middleware/banner_injector"
|
|
10
9
|
require_relative "newshound/railtie" if defined?(Rails)
|
|
11
10
|
|
|
12
11
|
module Newshound
|
|
@@ -21,46 +20,9 @@ module Newshound
|
|
|
21
20
|
yield(configuration)
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
exception_report = ExceptionReporter.new.generate_report
|
|
28
|
-
que_report = QueReporter.new.generate_report
|
|
29
|
-
|
|
30
|
-
message = format_daily_report(exception_report, que_report)
|
|
31
|
-
slack_notifier.post(message)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def format_daily_report(exception_report, que_report)
|
|
37
|
-
{
|
|
38
|
-
blocks: [
|
|
39
|
-
{
|
|
40
|
-
type: "header",
|
|
41
|
-
text: {
|
|
42
|
-
type: "plain_text",
|
|
43
|
-
text: "🐕 Daily Newshound Report",
|
|
44
|
-
emoji: true
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
type: "section",
|
|
49
|
-
text: {
|
|
50
|
-
type: "mrkdwn",
|
|
51
|
-
text: "*Date:* #{Date.current.strftime('%B %d, %Y')}"
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
type: "divider"
|
|
56
|
-
},
|
|
57
|
-
*exception_report,
|
|
58
|
-
{
|
|
59
|
-
type: "divider"
|
|
60
|
-
},
|
|
61
|
-
*que_report
|
|
62
|
-
]
|
|
63
|
-
}
|
|
23
|
+
# Allow setting custom authorization logic
|
|
24
|
+
def authorize_with(&block)
|
|
25
|
+
configuration.authorize_with(&block)
|
|
64
26
|
end
|
|
65
27
|
end
|
|
66
28
|
end
|
data/newshound.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/newshound/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "newshound"
|
|
7
|
+
spec.version = Newshound::VERSION
|
|
8
|
+
spec.authors = ["salbanez"]
|
|
9
|
+
spec.email = ["salbanez@example.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Real-time web UI banner for monitoring Que jobs and exception tracking"
|
|
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"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
spec.files = Dir.chdir(__dir__) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
23
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
spec.bindir = "exe"
|
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
|
+
spec.require_paths = ["lib"]
|
|
29
|
+
|
|
30
|
+
# Runtime dependencies
|
|
31
|
+
spec.add_dependency "rails", ">= 6.0"
|
|
32
|
+
spec.add_dependency "que", ">= 1.0"
|
|
33
|
+
spec.add_dependency "exception-track", ">= 0.1"
|
|
34
|
+
end
|