greenhat 0.3.3 → 0.4.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/bin/greenhat +1 -4
- data/lib/greenhat/accessors/disk.rb +42 -3
- data/lib/greenhat/accessors/gitlab.rb +30 -1
- data/lib/greenhat/accessors/memory.rb +1 -1
- data/lib/greenhat/archive.rb +19 -8
- data/lib/greenhat/cli.rb +24 -126
- data/lib/greenhat/entrypoint.rb +170 -0
- data/lib/greenhat/host.rb +25 -37
- data/lib/greenhat/settings.rb +6 -0
- data/lib/greenhat/shell/args.rb +22 -9
- data/lib/greenhat/shell/faststats.rb +23 -3
- data/lib/greenhat/shell/field_helper.rb +1 -1
- data/lib/greenhat/shell/filter_help.rb +232 -9
- data/lib/greenhat/shell/log.rb +153 -9
- data/lib/greenhat/shell/markdown.rb +352 -0
- data/lib/greenhat/shell/old_search_helper.rb +54 -0
- data/lib/greenhat/shell/page.rb +1 -1
- data/lib/greenhat/shell/pipe.rb +31 -0
- data/lib/greenhat/shell/platform.rb +28 -0
- data/lib/greenhat/shell/report.rb +106 -25
- data/lib/greenhat/shell/shell_helper.rb +115 -106
- data/lib/greenhat/shell.rb +10 -3
- data/lib/greenhat/thing/file_types.rb +136 -8
- data/lib/greenhat/thing/formatters/json.rb +4 -0
- data/lib/greenhat/thing/formatters/kube_json.rb +36 -0
- data/lib/greenhat/thing/formatters/kube_nginx.rb +48 -0
- data/lib/greenhat/thing/formatters/kube_webservice.rb +51 -0
- data/lib/greenhat/thing/formatters/nginx.rb +6 -2
- data/lib/greenhat/thing/formatters/registry.rb +47 -0
- data/lib/greenhat/thing/formatters/time_space.rb +0 -16
- data/lib/greenhat/thing/helpers.rb +12 -0
- data/lib/greenhat/thing/kind.rb +5 -0
- data/lib/greenhat/thing.rb +11 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat/views/api.slim +55 -0
- data/lib/greenhat/views/chart.slim +42 -0
- data/lib/greenhat/views/chart_template.slim +31 -0
- data/lib/greenhat/views/chartkick.js +21 -0
- data/lib/greenhat/views/css.slim +47 -0
- data/lib/greenhat/views/gitaly.slim +53 -0
- data/lib/greenhat/views/headers.slim +16 -0
- data/lib/greenhat/views/index-old.slim +51 -0
- data/lib/greenhat/views/index.slim +14 -14
- data/lib/greenhat/views/info.slim +17 -18
- data/lib/greenhat/views/production.slim +55 -0
- data/lib/greenhat/views/sidekiq.slim +55 -0
- data/lib/greenhat/views/time.slim +63 -0
- data/lib/greenhat/views/workhorse.slim +16 -0
- data/lib/greenhat/web/api.rb +94 -0
- data/lib/greenhat/web/chartkick_shim.rb +14 -0
- data/lib/greenhat/web/faststats.rb +44 -0
- data/lib/greenhat/web/gitaly.rb +65 -0
- data/lib/greenhat/web/helpers.rb +198 -0
- data/lib/greenhat/web/production.rb +104 -0
- data/lib/greenhat/web/sidekiq.rb +73 -0
- data/lib/greenhat/web/stats_helpers.rb +74 -0
- data/lib/greenhat/web/time.rb +36 -0
- data/lib/greenhat/web/workhorse.rb +43 -0
- data/lib/greenhat/web.rb +63 -19
- data/lib/greenhat.rb +2 -0
- metadata +78 -5
@@ -0,0 +1,28 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# Common Helpers
|
3
|
+
module Platform
|
4
|
+
def self.platform
|
5
|
+
if @platform
|
6
|
+
@platform
|
7
|
+
else
|
8
|
+
require 'tty-platform'
|
9
|
+
@platform ||= TTY::Platform.new
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.open(url = 'http://localhost:4567/chart/time')
|
15
|
+
cmd = if platform.linux? || platform.unix?
|
16
|
+
'xdg-open'
|
17
|
+
elsif platform.mac?
|
18
|
+
'open'
|
19
|
+
end
|
20
|
+
|
21
|
+
# platform.windows? # => false
|
22
|
+
# platform.unix? # => true
|
23
|
+
# platform.linux? # => false
|
24
|
+
# platform.mac? # => true
|
25
|
+
system("#{cmd} '#{url}'")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -12,7 +12,11 @@ module GreenHat
|
|
12
12
|
Archive.all
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
output = archives.map { |x| x.report(flags) }.map(&:show).flatten
|
16
|
+
|
17
|
+
flags[:page] = true if flags.full && !flags.raw
|
18
|
+
|
19
|
+
ShellHelper.show(output, flags)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
@@ -23,14 +27,16 @@ module GreenHat
|
|
23
27
|
class Report
|
24
28
|
include ActionView::Helpers::NumberHelper
|
25
29
|
|
26
|
-
attr_accessor :archive, :host, :os_release, :selinux_status, :cpu, :uname,
|
30
|
+
attr_accessor :archive, :flags, :host, :os_release, :selinux_status, :cpu, :uname,
|
27
31
|
:timedatectl, :uptime, :meminfo, :gitlab_manifest, :gitlab_status,
|
28
|
-
:production_log, :api_log, :
|
32
|
+
:production_log, :api_log, :sidekiq_log,
|
33
|
+
:exceptions_log, :gitaly_log, :free_m, :disk_free
|
29
34
|
|
30
35
|
# Find Needed Files for Report
|
31
36
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
32
|
-
def initialize(archive)
|
37
|
+
def initialize(archive, flags)
|
33
38
|
self.archive = archive
|
39
|
+
self.flags = flags
|
34
40
|
self.host = archive.things.find { |x| x.name == 'hostname' }
|
35
41
|
self.os_release = archive.things.find { |x| x.name == 'etc/os-release' }
|
36
42
|
self.selinux_status = archive.things.find { |x| x.name == 'sestatus' }
|
@@ -44,7 +50,8 @@ module GreenHat
|
|
44
50
|
self.gitlab_status = archive.things.find { |x| x.name == 'gitlab_status' }
|
45
51
|
self.production_log = archive.things.find { |x| x.name == 'gitlab-rails/production_json.log' }
|
46
52
|
self.api_log = archive.things.find { |x| x.name == 'gitlab-rails/api_json.log' }
|
47
|
-
self.
|
53
|
+
self.exceptions_log = archive.things.find { |x| x.name == 'gitlab-rails/exceptions_json.log' }
|
54
|
+
self.gitaly_log = archive.things.find { |x| x.name == 'gitaly/current' }
|
48
55
|
self.sidekiq_log = archive.things.find { |x| x.name == 'sidekiq/current' }
|
49
56
|
self.disk_free = archive.things.find { |x| x.name == 'df_h' }
|
50
57
|
end
|
@@ -84,11 +91,16 @@ module GreenHat
|
|
84
91
|
output << 'GitLab'.pastel(:bright_yellow) if gitlab_manifest
|
85
92
|
output << gitlab_version if gitlab_manifest
|
86
93
|
output << gitlab_services if gitlab_status
|
87
|
-
output << title('Errors') if production_log || api_log ||
|
94
|
+
output << title('Errors') if production_log || api_log || sidekiq_log
|
88
95
|
output << production_errors if production_log
|
89
|
-
output <<
|
90
|
-
output << application_errors if application_log
|
96
|
+
output << application_errors if archive.thing?('gitlab-rails/application_json.log')
|
91
97
|
output << sidekiq_errors if sidekiq_log
|
98
|
+
output << api_errors if api_log
|
99
|
+
output << exception_errors if exceptions_log
|
100
|
+
output << gitaly_errors if gitaly_log
|
101
|
+
output << workhorse_errors if archive.thing?('gitlab-workhorse/current')
|
102
|
+
|
103
|
+
full(output) if flags.full
|
92
104
|
|
93
105
|
# Final Space / Return
|
94
106
|
output << ''
|
@@ -96,6 +108,52 @@ module GreenHat
|
|
96
108
|
end
|
97
109
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
98
110
|
|
111
|
+
def full(output)
|
112
|
+
output << ''
|
113
|
+
output << 'FastStats Top'
|
114
|
+
Shell::Faststats.top(['--raw'], true).each { |x| output << x } # Page Row Helper
|
115
|
+
output << ''
|
116
|
+
|
117
|
+
output << 'FastStats Errors'
|
118
|
+
Shell::Faststats.errors(['--raw'], true).each { |x| output << x } # Page Row Helper
|
119
|
+
output << ''
|
120
|
+
end
|
121
|
+
|
122
|
+
def exception_errors
|
123
|
+
count = exceptions_log.data.count
|
124
|
+
color = count.zero? ? :green : :red
|
125
|
+
|
126
|
+
[
|
127
|
+
title(' Exception', :bright_red, 18),
|
128
|
+
count.to_s.pastel(color)
|
129
|
+
].join
|
130
|
+
end
|
131
|
+
|
132
|
+
def workhorse_errors
|
133
|
+
results = ShellHelper.filter_internal([
|
134
|
+
'gitlab-workhorse/current',
|
135
|
+
'--level=error',
|
136
|
+
"--archive=#{archive.name}"
|
137
|
+
].join(' '))
|
138
|
+
|
139
|
+
color = results.count.zero? ? :green : :red
|
140
|
+
|
141
|
+
[
|
142
|
+
title(' Workhorse', :bright_red, 18),
|
143
|
+
results.count.to_s.pastel(color)
|
144
|
+
].join
|
145
|
+
end
|
146
|
+
|
147
|
+
def gitaly_errors
|
148
|
+
count = gitaly_log.data.count { |x| x.level == 'error' }
|
149
|
+
color = count.zero? ? :green : :red
|
150
|
+
|
151
|
+
[
|
152
|
+
title(' Gitaly', :bright_red, 18),
|
153
|
+
count.to_s.pastel(color)
|
154
|
+
].join
|
155
|
+
end
|
156
|
+
|
99
157
|
def production_errors
|
100
158
|
count = production_log.data.count { |x| x.status == 500 }
|
101
159
|
color = count.zero? ? :green : :red
|
@@ -117,7 +175,14 @@ module GreenHat
|
|
117
175
|
end
|
118
176
|
|
119
177
|
def application_errors
|
120
|
-
|
178
|
+
results = ShellHelper.filter_internal([
|
179
|
+
'gitlab-rails/application_json.log',
|
180
|
+
'--message!="Cannot obtain an exclusive lease"',
|
181
|
+
'--severity=error',
|
182
|
+
"--archive=#{archive.name}"
|
183
|
+
].join(' '))
|
184
|
+
|
185
|
+
count = results.count { |x| x&.severity == 'ERROR' }
|
121
186
|
color = count.zero? ? :green : :red
|
122
187
|
|
123
188
|
[
|
@@ -269,7 +334,7 @@ module GreenHat
|
|
269
334
|
title('Usage'),
|
270
335
|
' ['.pastel(:bright_black),
|
271
336
|
'='.pastel(:green) * (used / 2),
|
272
|
-
' ' * (50 - used / 2),
|
337
|
+
' ' * (50 - (used / 2)),
|
273
338
|
']'.pastel(:bright_black),
|
274
339
|
" #{100 - percent(free, total)}%".pastel(:green) # Inverse
|
275
340
|
].join
|
@@ -282,21 +347,37 @@ module GreenHat
|
|
282
347
|
|
283
348
|
formatted_mem = free_m.data.map { |x| GreenHat::Memory.memory_row x }
|
284
349
|
|
285
|
-
[
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
350
|
+
output = []
|
351
|
+
unless free.total.blank?
|
352
|
+
output << title('Total', :cyan, 14)
|
353
|
+
output << number_to_human_size(free.total.to_i * (1024**2))
|
354
|
+
output << "\n"
|
355
|
+
end
|
356
|
+
|
357
|
+
unless free.total.blank?
|
358
|
+
output << title('Used', :yellow, 14)
|
359
|
+
output << number_to_human_size(free.used.to_i * (1024**2))
|
360
|
+
output << "\n"
|
361
|
+
end
|
362
|
+
|
363
|
+
unless free.total.blank?
|
364
|
+
output << title('Free', :blue, 14)
|
365
|
+
output << number_to_human_size(free.free.to_i * (1024**2))
|
366
|
+
output << "\n"
|
367
|
+
end
|
368
|
+
|
369
|
+
unless free.total.blank?
|
370
|
+
output << title('Available', :green, 14)
|
371
|
+
output << number_to_human_size(free.available.to_i * (1024**2))
|
372
|
+
output << "\n"
|
373
|
+
end
|
374
|
+
|
375
|
+
output << "\n"
|
376
|
+
output << formatted_mem.map { |x| x.prepend ' ' * 2 }.join("\n")
|
377
|
+
|
378
|
+
output.join
|
379
|
+
rescue StandardError => e
|
380
|
+
LogBot.fatal('Memory', message: e.message, backtrace: e.backtrace.first)
|
300
381
|
end
|
301
382
|
|
302
383
|
def disks
|
@@ -55,12 +55,14 @@ module GreenHat
|
|
55
55
|
# Default Pager
|
56
56
|
TTY::Pager.page do |pager|
|
57
57
|
data.each do |entry|
|
58
|
-
output = entry_show(flags, entry)
|
58
|
+
output = "\n#{entry_show(flags, entry)}"
|
59
|
+
|
60
|
+
# output += "\n" if flags[:table_style] == 'basic'
|
59
61
|
|
60
62
|
# Breaks any intentional spaces
|
61
63
|
# next if output.blank?
|
62
64
|
|
63
|
-
pager.write(
|
65
|
+
pager.write(output) # write line to the pager
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
@@ -103,7 +105,8 @@ module GreenHat
|
|
103
105
|
StringColor.do(key, entry)
|
104
106
|
end
|
105
107
|
|
106
|
-
|
108
|
+
# Stats truncation handled separately
|
109
|
+
if flags[:truncate] && !flags[:stats]
|
107
110
|
entry_truncate(formatted_entry, flags[:truncate])
|
108
111
|
else
|
109
112
|
formatted_entry
|
@@ -125,10 +128,15 @@ module GreenHat
|
|
125
128
|
table = TTY::Table.new(header: entry.keys, rows: [entry], orientation: :vertical)
|
126
129
|
|
127
130
|
LogBot.debug('Rendering Entries') if ENV['DEBUG']
|
128
|
-
table.render(table_style, padding: [0, 1, 0, 1], multiline: true) do |renderer|
|
131
|
+
output = table.render(table_style, padding: [0, 1, 0, 1], multiline: true) do |renderer|
|
129
132
|
renderer.border.style = :cyan
|
130
133
|
end
|
131
134
|
|
135
|
+
# Line breaks for basic tables
|
136
|
+
output += "\n" if flags[:table_style] == 'basic'
|
137
|
+
|
138
|
+
output
|
139
|
+
|
132
140
|
# LogBot.debug('Finish Render Table') if ENV['DEBUG']
|
133
141
|
# Fall Back to Amazing Inspect
|
134
142
|
rescue StandardError => e
|
@@ -150,8 +158,21 @@ module GreenHat
|
|
150
158
|
format_table_entry(flags, val)
|
151
159
|
end
|
152
160
|
|
161
|
+
# Internal Query Helper
|
162
|
+
# query = 'gitlab-rails/application_json.log --message!="Cannot obtain an exclusive lease" --severity=error'
|
163
|
+
# ShellHelper.filter_internal(query)
|
164
|
+
def self.filter_internal(search = '')
|
165
|
+
files, flags, args = Args.parse(Shellwords.split(search))
|
166
|
+
flags[:combine] = true
|
167
|
+
|
168
|
+
# Default to everything
|
169
|
+
files = Thing.all.map(&:name) if files.empty?
|
170
|
+
|
171
|
+
ShellHelper.filter_start(files, flags, args)
|
172
|
+
end
|
173
|
+
|
153
174
|
# Main Entry Point for Filtering
|
154
|
-
def self.filter_start(files, flags, args)
|
175
|
+
def self.filter_start(files, flags = {}, args = {})
|
155
176
|
# Convert to Things
|
156
177
|
logs = ShellHelper.find_things(files, flags).select(&:processed?)
|
157
178
|
|
@@ -167,11 +188,17 @@ module GreenHat
|
|
167
188
|
|
168
189
|
# Include Total Count in Name
|
169
190
|
results = ShellHelper.filter(log.data, flags, args)
|
191
|
+
duration = calculate_duration(results)
|
192
|
+
|
170
193
|
title = [
|
171
194
|
log.friendly_name,
|
172
195
|
" #{results.count}".pastel(:bright_black)
|
196
|
+
|
173
197
|
]
|
174
198
|
|
199
|
+
# Append Duration
|
200
|
+
title.push(" #{duration.pastel(:cyan, :dim)}") unless duration.blank?
|
201
|
+
|
175
202
|
# Save unless empty
|
176
203
|
obj[title.join] = results unless results.count.zero?
|
177
204
|
|
@@ -180,6 +207,32 @@ module GreenHat
|
|
180
207
|
end
|
181
208
|
end
|
182
209
|
|
210
|
+
def self.calculate_duration(results)
|
211
|
+
# Skip for Pluck
|
212
|
+
only_with_time = results.select { |x| x.instance_of?(Hash) && x.key?(:time) }
|
213
|
+
|
214
|
+
# If slice is used ignore
|
215
|
+
return nil if only_with_time.empty?
|
216
|
+
|
217
|
+
sorted = only_with_time.map(&:time).sort
|
218
|
+
humanize_time(sorted.first, sorted.last)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Replace TimeDifference with https://stackoverflow.com/a/4136485/1678507
|
222
|
+
def self.humanize_time(time_start, time_end, increments = 2)
|
223
|
+
miliseconds = (time_end - time_start) * 1000
|
224
|
+
|
225
|
+
list = [[1000, :ms], [60, :s], [60, :m], [24, :h]].map do |count, name|
|
226
|
+
next unless miliseconds.positive?
|
227
|
+
|
228
|
+
miliseconds, n = miliseconds.divmod(count)
|
229
|
+
|
230
|
+
"#{n.to_i}#{name}" unless n.to_i.zero?
|
231
|
+
end
|
232
|
+
|
233
|
+
list.compact.reverse[0..increments - 1].join(' ')
|
234
|
+
end
|
235
|
+
|
183
236
|
# Filter Logic
|
184
237
|
# TODO: Simplify
|
185
238
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -189,7 +242,7 @@ module GreenHat
|
|
189
242
|
# Experimenting with deep clone
|
190
243
|
results = Marshal.load(Marshal.dump(data))
|
191
244
|
results.select! do |row|
|
192
|
-
args.send(flags.logic) do |arg|
|
245
|
+
args.send(flags.logic || :all?) do |arg|
|
193
246
|
filter_row_key(row, arg, flags)
|
194
247
|
end
|
195
248
|
end
|
@@ -255,7 +308,6 @@ module GreenHat
|
|
255
308
|
end
|
256
309
|
|
257
310
|
# Filter Start and End Times
|
258
|
-
# rubocop:disable Metrics/MethodLength
|
259
311
|
# TODO: This is a bit icky, simplify/dry
|
260
312
|
def self.filter_time(results, flags)
|
261
313
|
if flags.key?(:start)
|
@@ -292,7 +344,6 @@ module GreenHat
|
|
292
344
|
|
293
345
|
results
|
294
346
|
end
|
295
|
-
# rubocop:enable Metrics/MethodLength
|
296
347
|
|
297
348
|
def self.filter_except(results, except)
|
298
349
|
# Avoid Empty Results
|
@@ -370,6 +421,9 @@ module GreenHat
|
|
370
421
|
stats.map do |field|
|
371
422
|
occurrences = filter_count_occurrences(results, field, flags)
|
372
423
|
|
424
|
+
# Use Truncate For Long Keys
|
425
|
+
occurrences.transform_keys! { |key| key.to_s[0..flags[:truncate]] } if flags[:truncate]
|
426
|
+
|
373
427
|
# Total Occurences
|
374
428
|
total = occurrences.values.sum
|
375
429
|
|
@@ -387,13 +441,6 @@ module GreenHat
|
|
387
441
|
# Append Header / Total with field name
|
388
442
|
output.unshift([field.to_s.pastel(:bright_black), total])
|
389
443
|
|
390
|
-
# Use Truncate For Long Keys
|
391
|
-
if flags[:truncate]
|
392
|
-
output.map! do |key, value|
|
393
|
-
[key.to_s[0..flags[:truncate]], value]
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
444
|
# Format
|
398
445
|
output.to_h
|
399
446
|
end
|
@@ -433,48 +480,83 @@ module GreenHat
|
|
433
480
|
end
|
434
481
|
|
435
482
|
# Break out filter row logic into separate method
|
436
|
-
|
437
483
|
def self.filter_row_key(row, arg, flags)
|
438
484
|
# Ignore Other Logic if Field isn't even included / Full Text Searching
|
439
485
|
return false unless row.key?(arg[:field]) || arg[:field] == :text
|
440
486
|
|
441
487
|
# Sensitivity Check / Check for Match / Full Text Searching
|
442
|
-
|
443
|
-
|
444
|
-
else
|
445
|
-
filter_row_entry(row[arg.field].to_s, arg, flags)
|
446
|
-
end
|
488
|
+
search_data = arg[:field] == :text ? row : row[arg.field]
|
489
|
+
match = filter_row_entry(search_data.to_s, arg, flags)
|
447
490
|
|
448
491
|
# Pivot of off include vs exclude
|
449
492
|
if arg.bang
|
450
|
-
!
|
493
|
+
!match
|
451
494
|
else
|
452
|
-
|
495
|
+
match
|
453
496
|
end
|
454
497
|
end
|
455
498
|
|
456
499
|
# Field Partial / Case / Exact search
|
457
500
|
def self.filter_row_entry(entry, arg, flags)
|
458
501
|
# Exact Matching / Unless doing full text search
|
459
|
-
return entry
|
502
|
+
return entry == arg.value.to_s if flags.key?(:exact) && arg.field != :text
|
460
503
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
504
|
+
# Cast to String/Integer Helper
|
505
|
+
entry, value = filter_entry_cast(entry, arg, flags)
|
506
|
+
|
507
|
+
entry.send(arg.logic, value)
|
508
|
+
end
|
509
|
+
|
510
|
+
# Handle casting to strings or integers
|
511
|
+
def self.filter_entry_cast(entry, arg, flags)
|
512
|
+
# Cast to String
|
513
|
+
value = arg.value.to_s
|
514
|
+
|
515
|
+
case arg.logic
|
516
|
+
when :include?
|
517
|
+
|
518
|
+
# Exact Case argument
|
519
|
+
unless flags.key?(:case)
|
520
|
+
entry.downcase!
|
521
|
+
value.downcase!
|
522
|
+
end
|
523
|
+
when :>=, :<=
|
524
|
+
entry = entry.to_i if entry.numeric?
|
525
|
+
value = value.to_i if value&.numeric?
|
465
526
|
end
|
527
|
+
|
528
|
+
[entry, value]
|
529
|
+
end
|
530
|
+
|
531
|
+
def self.filter_entry_logic(entry, arg)
|
532
|
+
entry.send(arg.logic, arg.value)
|
466
533
|
end
|
467
534
|
|
468
535
|
# Total Count Helper
|
469
|
-
def self.total_count(results)
|
470
|
-
results.
|
536
|
+
def self.total_count(results, flags)
|
537
|
+
results.map do |k, v|
|
471
538
|
puts k
|
472
|
-
puts "Total: #{v.count.to_s.pastel(:blue)}"
|
539
|
+
# puts "Total: #{v.count.to_s.pastel(:blue)}"
|
540
|
+
# puts "Time Covered: #{calculate_duration(v).pastel(:cyan)}"
|
541
|
+
|
542
|
+
output = {}
|
543
|
+
output[:total] = v.count
|
544
|
+
output[:duration] = calculate_duration(v)
|
545
|
+
|
546
|
+
# Sort / Get first and Last
|
547
|
+
list = v.select(&:time).map(&:time)
|
548
|
+
unless list.blank?
|
549
|
+
output[:start] = list.first
|
550
|
+
output[:end] = list.last
|
551
|
+
end
|
552
|
+
|
553
|
+
puts render_table(output, flags)
|
554
|
+
|
473
555
|
puts
|
474
556
|
end
|
475
557
|
end
|
476
558
|
|
477
|
-
#
|
559
|
+
# Table Printer Helper
|
478
560
|
def self.fields_print(results)
|
479
561
|
results.each do |k, v|
|
480
562
|
puts k
|
@@ -538,7 +620,7 @@ module GreenHat
|
|
538
620
|
return file if file.instance_of?(Thing)
|
539
621
|
|
540
622
|
if flags.fuzzy_file_match
|
541
|
-
Thing.all.select { |x| x.name.include? file }
|
623
|
+
Thing.all.select { |x| x.name.include?(file) || x.type.include?(file) }
|
542
624
|
else
|
543
625
|
Thing.where name: file
|
544
626
|
end
|
@@ -550,62 +632,6 @@ module GreenHat
|
|
550
632
|
things
|
551
633
|
end
|
552
634
|
|
553
|
-
# Main Entry Point for Searching
|
554
|
-
# def self.search_start(log_list, filter_type, args, opts)
|
555
|
-
def self.search_start(files, flags, args)
|
556
|
-
# Convert to Things
|
557
|
-
logs = ShellHelper.find_things(files, flags)
|
558
|
-
|
559
|
-
logs.each_with_object({}) do |log, obj|
|
560
|
-
# Ignore Empty Results / No Thing
|
561
|
-
next if log&.data.blank?
|
562
|
-
|
563
|
-
obj[log.friendly_name] = ShellHelper.search(log.data, flags, args)
|
564
|
-
|
565
|
-
obj
|
566
|
-
end
|
567
|
-
end
|
568
|
-
|
569
|
-
# Generic Search Helper / String/Regex
|
570
|
-
def self.search(data, flags = {}, args = {})
|
571
|
-
results = data.clone.flatten.compact
|
572
|
-
results.select! do |row|
|
573
|
-
args.send(flags.logic) do |arg|
|
574
|
-
search_row(row, arg, flags)
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
# Strip Results if Slice is defined
|
579
|
-
results.map! { |row| row.slice(*flags[:slice]) } if flags[:slice]
|
580
|
-
|
581
|
-
# Strip Results if Except is defined
|
582
|
-
results.map! { |row| row.except(*flags[:except]) } if flags[:except]
|
583
|
-
|
584
|
-
# Remove Blank from either slice or except
|
585
|
-
results.reject!(&:empty?)
|
586
|
-
|
587
|
-
results
|
588
|
-
end
|
589
|
-
|
590
|
-
# Break out filter row logic into separate method
|
591
|
-
def self.search_row(row, arg, flags)
|
592
|
-
# Sensitivity Check / Check for Match
|
593
|
-
included = filter_row_entry(row.to_s, arg, flags)
|
594
|
-
|
595
|
-
# Pivot of off include vs exclude
|
596
|
-
if arg.bang
|
597
|
-
!included
|
598
|
-
else
|
599
|
-
included
|
600
|
-
end
|
601
|
-
end
|
602
|
-
|
603
|
-
# TODO: Remove?
|
604
|
-
# Color Reader Helper
|
605
|
-
# def self.pastel
|
606
|
-
# @pastel ||= Pastel.new
|
607
|
-
# end
|
608
|
-
|
609
635
|
# Number Helper
|
610
636
|
# https://gitlab.com/zedtux/human_size_to_number/-/blob/master/lib/human_size_to_number/helper.rb
|
611
637
|
def self.human_size_to_number(string)
|
@@ -627,23 +653,6 @@ module GreenHat
|
|
627
653
|
number.round
|
628
654
|
end
|
629
655
|
|
630
|
-
# TODO: Needed?
|
631
|
-
def self.filter_and(data, params = {})
|
632
|
-
result = data.clone.flatten.compact
|
633
|
-
params.each do |k, v|
|
634
|
-
result.select! do |row|
|
635
|
-
if row.key? k.to_sym
|
636
|
-
row[k.to_sym].include? v
|
637
|
-
else
|
638
|
-
false
|
639
|
-
end
|
640
|
-
end
|
641
|
-
next
|
642
|
-
end
|
643
|
-
|
644
|
-
result
|
645
|
-
end
|
646
|
-
|
647
656
|
# General Helper for `show`
|
648
657
|
def self.common_opts
|
649
658
|
puts 'Common Options'.pastel(:blue)
|
data/lib/greenhat/shell.rb
CHANGED
@@ -7,6 +7,13 @@ module GreenHat
|
|
7
7
|
# rubocop:enable Lint/Debugger
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.web
|
11
|
+
# Load Required Files
|
12
|
+
require 'greenhat/web'
|
13
|
+
|
14
|
+
GreenHat::Web.toggle
|
15
|
+
end
|
16
|
+
|
10
17
|
def self.df
|
11
18
|
Disk.df
|
12
19
|
end
|
@@ -23,12 +30,12 @@ module GreenHat
|
|
23
30
|
Memory.free
|
24
31
|
end
|
25
32
|
|
26
|
-
def self.load_local
|
27
|
-
return false
|
33
|
+
def self.load_local(prompt = true)
|
34
|
+
return false if prompt && !TTY::Prompt.new.yes?('Load local Omnibus GitLab Instance files?')
|
28
35
|
|
29
36
|
archive_path = "#{$TMP}/#{Time.now.to_i}_local"
|
30
37
|
Dir.mkdir(archive_path)
|
31
|
-
|
38
|
+
|
32
39
|
archive = Archive.new(name: archive_path, path: archive_path)
|
33
40
|
|
34
41
|
file_list = Dir['/var/log/gitlab/*/current'] + Dir['/var/log/gitlab/*/*.log']
|