greenhat 0.3.1 → 0.3.5

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: cf89eef7afeef6861dde013e8cc7992a92d1c9f4dca79ca0a438913f6d9a7a89
4
- data.tar.gz: eed033653f4723f19962f5643ac02c71d9f950f97aa4a68375cc3174152e5513
3
+ metadata.gz: 6ff63bc1345ac9a27d3fa6263fc3a68e9c851aa30f2b3bf58cdee484ce142cbb
4
+ data.tar.gz: a150c0d19b954883ef2372280b78a89606a5e9039944b794289c9541c3548ed3
5
5
  SHA512:
6
- metadata.gz: 90c1a58ef0334bd864480ad422957758850ecacd39bc85db1fd47233192e09bda768e15331dc179d8860f4842aed58fafb439f4f9499ff22d1c25e3ebf8bff74
7
- data.tar.gz: aea2b938e6b1a5956d7811084b1ab725cf41f2d0766affffed696755ac497cc41a67ebfc562ce516ce448ebb983e6e504a493e772348fd536f1e5c711954f612
6
+ metadata.gz: 7011298d19ac200f7ea4bd10686642ac30911cbd509eb7dd0152a29b88f4dedd942803fdbd4198a9374e868d060cdf7f3458860c407210d0aa4e5a3e812d63e9
7
+ data.tar.gz: 8a7cdc716bd4c7f6edddfae2488593f2ec17908203218df57d542057753973528262ff96d1b9986b7c02ec4a08f33a740e0ba162e32752c75725c2c2a60affb5
@@ -79,5 +79,46 @@ module GreenHat
79
79
  output
80
80
  end
81
81
  # rubocop:enable Metrics/MethodLength
82
+
83
+ # Unified Output Handler
84
+ def self.markdown_format(file, name = false, limit = nil, filter = %w[tmpfs loop])
85
+ output = []
86
+
87
+ output << file.friendly_name if name
88
+
89
+ # Reject TMPFS
90
+ disks = file.data.sort_by { |x| x.use.to_i }.reverse
91
+
92
+ # Filter
93
+ disks.reject! { |x| filter.any? { |y| x.filesystem.include? y } }
94
+
95
+ disks = disks[0..limit - 1] if limit
96
+
97
+ pad_mount, pad_size, pad_used, pad_avail = GreenHat::Disk.padding(disks)
98
+
99
+ # Headers
100
+ output << [
101
+ 'Mount'.ljust(pad_mount),
102
+ 'Size'.ljust(pad_size),
103
+ 'Used'.ljust(pad_used),
104
+ 'Avail'.ljust(pad_avail),
105
+ '% Use'.ljust(pad_avail)
106
+ ].join
107
+
108
+ # Table Summary
109
+ disks.map do |disk|
110
+ # Whole Thing
111
+ output << [
112
+ disk.mounted_on.ljust(pad_mount),
113
+ disk[:size].to_s.ljust(pad_size),
114
+ disk.used.to_s.ljust(pad_used),
115
+ disk.avail.to_s.ljust(pad_avail),
116
+ disk.use.rjust(5).ljust(5)
117
+ ].join
118
+ end
119
+
120
+ output
121
+ end
122
+ # =
82
123
  end
83
124
  end
@@ -71,5 +71,31 @@ module GreenHat
71
71
 
72
72
  table.render(:unicode, padding: [0, 1, 0, 1], indent: indent)
73
73
  end
74
+
75
+ def self.services_markdown(archive)
76
+ # manifest = archive.things.find { |x| x.type == 'gitlab/version-manifest.json' }
77
+ gitlab_status = archive.things.find { |x| x.name == 'gitlab_status' }
78
+
79
+ list = gitlab_status.data.keys.sort.map do |service|
80
+ status = gitlab_status.data.dig(service, 0, :status) == 'run' ? '↑' : '!'
81
+
82
+ "#{service}#{status}"
83
+ end
84
+
85
+ # Keep Alphabetical Sort
86
+ groups = list.each_slice((list.size / 3.to_f).round).to_a
87
+
88
+ table = TTY::Table.new do |t|
89
+ loop do
90
+ break if groups.all?(&:empty?)
91
+
92
+ t << groups.map(&:shift)
93
+ end
94
+ end
95
+
96
+ "```\n#{table.render(:basic)}\n```"
97
+ end
98
+
99
+ # ==
74
100
  end
75
101
  end
@@ -6,7 +6,7 @@ module GreenHat
6
6
  end
7
7
 
8
8
  def self.percentage(used, total)
9
- return 0 if used.to_i.zero?
9
+ return 0 if used.to_i.zero? || total.to_i.zero?
10
10
 
11
11
  # Show at least one bar if below 1%
12
12
  [1, ((used.to_i / total.to_f).round(1) * 100).round].max
@@ -105,4 +105,8 @@ class Archive < Teron
105
105
  def report
106
106
  GreenHat::Report.new(self)
107
107
  end
108
+
109
+ def report_markdown
110
+ GreenHat::ReportMarkdown.new(self)
111
+ end
108
112
  end
data/lib/greenhat/cli.rb CHANGED
@@ -65,7 +65,9 @@ module GreenHat
65
65
  # Auto Complete
66
66
  # =========================================================
67
67
  def self.auto
68
- word = reader.line.word
68
+ word = @list.last
69
+ # This is being weird with auto complete
70
+ # word = reader.line.word
69
71
 
70
72
  if word.blank?
71
73
  help
@@ -74,6 +76,10 @@ module GreenHat
74
76
  end
75
77
  end
76
78
 
79
+ def self.file_matches(word)
80
+ files.select { |x| x[/^#{Regexp.escape(word)}/] }
81
+ end
82
+
77
83
  def self.auto_match(matches, word)
78
84
  matches.select! { |x| x[/^#{Regexp.escape(word)}/] }
79
85
 
@@ -88,11 +94,14 @@ module GreenHat
88
94
  elsif matches.count > 1
89
95
  puts matches.join("\t").pastel(:bright_green)
90
96
 
91
- # No other Matches
92
- else
93
- file_matches = files.select { |x| x[/^#{Regexp.escape(word)}/] }
94
- auto_files(file_matches, word) unless file_matches.empty?
97
+ # General Filename Matching
98
+ elsif !file_matches(word).empty?
99
+ auto_files(file_matches(word), word)
95
100
 
101
+ # Submodule Autocompletion
102
+ elsif current_methods.include?('auto_complete')
103
+ update_text = current_location.auto_complete(@list, word)
104
+ auto_update(update_text, word) unless update_text.blank?
96
105
  end
97
106
  end
98
107
 
@@ -237,13 +246,17 @@ module GreenHat
237
246
  @list.any? { |x| x.include?(cmd) } && current_methods.include?('default')
238
247
  end
239
248
 
249
+ def self.current_commands
250
+ current_location.methods(false).map(&:to_s).sort - %w[auto_complete]
251
+ end
252
+
240
253
  # General Helper
241
254
  def self.help(long = true)
242
255
  if current_location.methods(false).count.zero?
243
256
  puts 'No Commands'.pastel(:red)
244
257
  else
245
258
  puts 'Commands: '
246
- current_location.methods(false).map(&:to_s).sort.each do |item|
259
+ current_commands.each do |item|
247
260
  next if %w[default help].any? { |x| x == item }
248
261
 
249
262
  puts "=> #{item.to_s.pastel(:blue)}"
@@ -340,6 +353,7 @@ module GreenHat
340
353
  puts
341
354
  puts 'Usage'.pastel(:yellow)
342
355
  puts ' greenhat <sos-archive.tgz> <sos-archive2.tgz> '
356
+ puts ' greenhat <sos-archive.tgz> -q --command=df'
343
357
  puts
344
358
 
345
359
  puts 'Options'.pastel(:yellow)
@@ -406,6 +420,7 @@ module GreenHat
406
420
 
407
421
  # CTL Tails need to be parsed for new 'things'
408
422
  Thing.where(kind: :gitlab_tail)&.map(&:process)
423
+ Thing.where(kind: :kube_webservice)&.map(&:process)
409
424
 
410
425
  Thing.all.each(&:process) if flags?(%i[load l], flags)
411
426
  end
@@ -70,8 +70,8 @@ module GreenHat
70
70
  # Flags Anything that isn't sent as a key/filter
71
71
  def self.arg_to_flag_list
72
72
  %i[
73
- archive end except exists json limit pluck reverse round slice sort start stats
74
- truncate uniq page
73
+ archive end except exists json limit pluck reverse round slice sort start
74
+ stats truncate uniq page time_zone table_style
75
75
  ]
76
76
  end
77
77
 
@@ -67,8 +67,20 @@ module GreenHat
67
67
  end
68
68
  # rubocop:enable Metrics/MethodLength)
69
69
 
70
+ def self.faststats_installation
71
+ puts "#{'Unable to find'.pastel(:red)} #{'fast-stats'.pastel(:blue)}"
72
+ puts ' Release Downloads here'
73
+ puts ' - https://gitlab.com/gitlab-com/support/toolbox/fast-stats/-/releases'.pastel(:yellow)
74
+ puts ''
75
+ end
76
+
70
77
  # List Files Helpers
71
78
  def self.list(args = [])
79
+ unless TTY::Which.exist? 'fast-stats'
80
+ faststats_installation
81
+ return false
82
+ end
83
+
72
84
  all = false
73
85
  all = true if args.include?('-a') || args.include?('--all')
74
86
 
@@ -96,6 +108,11 @@ module GreenHat
96
108
 
97
109
  # Vanilla Fast Stats
98
110
  def self.default(raw, _other = nil)
111
+ unless TTY::Which.exist? 'fast-stats'
112
+ faststats_installation
113
+ return false
114
+ end
115
+
99
116
  files, flags, cmd = ShellHelper::Faststats.parse(raw)
100
117
 
101
118
  LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
@@ -121,6 +138,11 @@ module GreenHat
121
138
  # --sort=count,fail,max,median,min,p95,p99,rps,score
122
139
  # ========================================================================
123
140
  def self.top(raw)
141
+ unless TTY::Which.exist? 'fast-stats'
142
+ faststats_installation
143
+ return false
144
+ end
145
+
124
146
  files, flags, cmd = ShellHelper::Faststats.parse(raw)
125
147
 
126
148
  LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
@@ -141,6 +163,11 @@ module GreenHat
141
163
  # ===== [ Fast Stats - Errors ] ====================
142
164
  # ========================================================================
143
165
  def self.errors(raw)
166
+ unless TTY::Which.exist? 'fast-stats'
167
+ faststats_installation
168
+ return false
169
+ end
170
+
144
171
  # Add Color Output
145
172
  raw.push '--color-output'
146
173
  files, flags, cmd = ShellHelper::Faststats.parse(raw)
@@ -0,0 +1,75 @@
1
+ module GreenHat
2
+ # Common Helpers
3
+ module FieldHelper
4
+ def self.fields_find(files, word, flags = {})
5
+ fields = ShellHelper.find_things(files, flags).map(&:fields).flatten.uniq
6
+
7
+ if word.blank?
8
+ puts 'Possible Fields:'.pastel(:bright_blue)
9
+ puts ShellHelper.field_table(fields)
10
+
11
+ return [] # Empty Result
12
+ end
13
+
14
+ list_select(fields, word)
15
+ end
16
+
17
+ def self.list_select(list, word)
18
+ list.select! { |x| x[/^#{Regexp.escape(word)}/] }
19
+ end
20
+
21
+ def self.filter_flags(word)
22
+ if word.blank?
23
+ puts 'Filter Options:'.pastel(:bright_blue)
24
+ puts ShellHelper.field_table(filter_opts, 6)
25
+ puts
26
+
27
+ return []
28
+ end
29
+
30
+ list_select(filter_opts, word)
31
+ end
32
+
33
+ def self.filter_opts
34
+ %w[
35
+ archive case combine end exact except exists json limit or page pluck
36
+ raw reverse round slice sort start stats table_style text time_zone
37
+ total truncate uniq
38
+ ]
39
+ end
40
+
41
+ def self.filter_auto_completes
42
+ %w[
43
+ except exists pluck slice sort stats uniq
44
+ ]
45
+ end
46
+
47
+ def self.field_auto_complete?(word)
48
+ return false if word.blank?
49
+
50
+ filter_auto_completes.include? word.split('=', 2).first
51
+ end
52
+
53
+ def self.field_auto_complete(word, files, flags = {})
54
+ # Prevent weird dupes
55
+ return nil if word[-1] == ','
56
+
57
+ # Command Manipulation
58
+ cmd, fields = word.split('=', 2)
59
+ complete = fields.split(',')[0..-2]
60
+ auto = fields.split(',').last
61
+
62
+ # Field Finder
63
+ matches = fields_find(files, auto, flags)
64
+
65
+ if matches.count == 1
66
+ "--#{cmd}=#{(complete + matches).join(',')}"
67
+ elsif matches.count > 1
68
+ puts "#{'Field Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
69
+
70
+ list = [Cli.common_substr(matches.map(&:to_s))]
71
+ "--#{cmd}=#{(complete + list).join(',')}"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -2,8 +2,8 @@ module GreenHat
2
2
  # CLI Helper
3
3
  module ShellHelper
4
4
  # Unify Filter / Filter Help
5
+ # rubocop:disable Metrics/MethodLength,Metrics/ModuleLength
5
6
  module Filter
6
- # rubocop:disable Metrics/MethodLength
7
7
  def self.help
8
8
  puts "\u2500".pastel(:cyan) * 20
9
9
  puts 'Filter'.pastel(:yellow)
@@ -11,7 +11,7 @@ module GreenHat
11
11
 
12
12
  puts 'Options'.pastel(:blue)
13
13
  puts '--raw'.pastel(:green)
14
- puts ' Do not use less/paging'
14
+ puts ' Disable formatting and page/less'
15
15
  puts
16
16
 
17
17
  puts '--page'.pastel(:green)
@@ -41,6 +41,10 @@ module GreenHat
41
41
  puts ' Print only total count of matching entries'
42
42
  puts
43
43
 
44
+ puts '--fields'.pastel(:green)
45
+ puts ' Print only Available fields for selected files'
46
+ puts
47
+
44
48
  puts '--slice'.pastel(:green)
45
49
  puts ' Extract specific fields from entries (slice multiple with comma)'
46
50
  puts ' Ex: --slice=path or --slice=path,params'
@@ -57,7 +61,7 @@ module GreenHat
57
61
  puts
58
62
 
59
63
  puts '--stats'.pastel(:green)
60
- puts ' Order/Count occurrances by field'
64
+ puts ' Order/Count occurrances by field. Combine with `truncate` for key names'
61
65
  puts ' Ex: --stats=params --except=params,path'
62
66
  puts
63
67
 
@@ -113,6 +117,21 @@ module GreenHat
113
117
  puts ' Ex: log filter --end="2021-06-22"'
114
118
  puts
115
119
 
120
+ puts '--time_zone'.pastel(:green)
121
+ puts ' Manipulate the `time` field into a specific timezone'
122
+ puts ' Ex: log filter --time_zone=EDT'
123
+ puts
124
+
125
+ puts '--text'.pastel(:green)
126
+ puts ' Full entry text searching (slow)'
127
+ puts ' --text="anything here"'
128
+ puts
129
+
130
+ puts '--table_style'.pastel(:green)
131
+ puts ' Renderer used for formatted output. basic, ascii, or unicode(default)'
132
+ puts ' Ex: log filter --table_style=base'
133
+ puts
134
+
116
135
  puts '--truncate'.pastel(:green)
117
136
  puts ' Truncate field length. On by default (4 rows). Performance issues!'
118
137
  puts ' Disable with --truncate=0'.pastel(:bright_red)
@@ -137,7 +156,208 @@ module GreenHat
137
156
 
138
157
  puts
139
158
  end
140
- # rubocop:enable Metrics/MethodLength
159
+
160
+ def self.help_index
161
+ {
162
+ title: [
163
+ "\u2500".pastel(:cyan) * 20,
164
+ 'Filter'.pastel(:yellow),
165
+ "\u2500".pastel(:cyan) * 20
166
+ ],
167
+ options: [
168
+ 'Options'.pastel(:blue)
169
+ ],
170
+
171
+ raw: [
172
+ '--raw'.pastel(:green),
173
+ ' Disable formatting and page/less'
174
+ ],
175
+
176
+ page: [
177
+ '--page'.pastel(:green),
178
+ ' Specifically enable or disable paging',
179
+ ' E.g. --page (default to true), --page=true, --page=false'
180
+ ],
181
+
182
+ round: ['--round'.pastel(:green),
183
+ ' Attempt to round all integers. Default: 2.',
184
+ ' E.g. --round, --round=3, --round=0'],
185
+
186
+ limit: [
187
+
188
+ '--limit'.pastel(:green),
189
+ ' Limit total output lines. Disabled by default. Default without value is based on screen height',
190
+ ' E.g. --limit, --limit=5'
191
+ ],
192
+
193
+ json: [
194
+ '--json'.pastel(:green),
195
+ ' Print output back into JSON'
196
+ ],
197
+
198
+ or: [
199
+ '--or'.pastel(:green),
200
+ ' Filters will use OR instead of AND (all match vs any match)'
201
+ ],
202
+
203
+ total: [
204
+ '--total'.pastel(:green),
205
+ ' Print only total count of matching entries'
206
+ ],
207
+
208
+ fields: [
209
+ '--fields'.pastel(:green),
210
+ ' Print only Available fields for selected files'
211
+ ],
212
+
213
+ slice: [
214
+ '--slice'.pastel(:green),
215
+ ' Extract specific fields from entries (slice multiple with comma)',
216
+ ' Ex: --slice=path or --slice=path,params'
217
+
218
+ ],
219
+
220
+ except: [
221
+ '--except'.pastel(:green),
222
+ ' Exclude specific fields (except multiple with comma)',
223
+ ' Ex: --except=params --except=params,path'
224
+
225
+ ],
226
+
227
+ exists: [
228
+ '--exists'.pastel(:green),
229
+ ' Ensure field exists regardless of contents',
230
+ ' Ex: --exists=params --exists=params,path'
231
+
232
+ ],
233
+
234
+ stats: [
235
+ '--stats'.pastel(:green),
236
+ ' Order/Count occurrances by field. Combine with `truncate` for key names',
237
+ ' Ex: --stats=params --except=params,path'
238
+
239
+ ],
240
+
241
+ uniq: [
242
+ '--uniq'.pastel(:green),
243
+ ' Show unique values only',
244
+ ' Ex: --uniq=params --uniq=params,path'
245
+
246
+ ],
247
+
248
+ pluck: [
249
+ '--pluck'.pastel(:green),
250
+ ' Extract values from entries',
251
+ ' Ex: --pluck=params --pluck=params,path'
252
+
253
+ ],
254
+
255
+ archive: [
256
+ '--archive'.pastel(:green),
257
+ ' Limit to specific archvie name (partial matching /inclusive). Matching SOS tar.gz name',
258
+ ' Ex: --archive=dev-gitlab_20210622154626, --archive=202106,202107'
259
+
260
+ ],
261
+
262
+ sort: [
263
+ '--sort'.pastel(:green),
264
+ ' Sort by multiple fields',
265
+ ' Ex: --sort=duration_s,db_duration_s'
266
+
267
+ ],
268
+
269
+ reverse: [
270
+ '--reverse'.pastel(:green),
271
+ ' Reverse all results',
272
+ ' Ex: --reverse'
273
+
274
+ ],
275
+
276
+ combine: [
277
+ '--combine'.pastel(:green),
278
+ ' Omit archive identifier dividers. Useful with sort or time filters',
279
+ ' Ex: --combine'
280
+
281
+ ],
282
+
283
+ case: [
284
+ '--case'.pastel(:green),
285
+ ' Exact case match. Defaults to case insensitive',
286
+ ' Ex: --case; --name=Jon, --name=jane --case'
287
+
288
+ ],
289
+
290
+ exact: [
291
+ '--exact'.pastel(:green),
292
+ ' Exact parameter/value match. Defaults to partial match',
293
+ ' Ex: --field=CommonPartial --exact'
294
+
295
+ ],
296
+
297
+ start: [
298
+ '--start'.pastel(:green),
299
+ ' Show events after specified time. Filtered by the `time` field',
300
+ ' Use with `--end` for between selections',
301
+ ' Ex: log filter --start="2021-06-22 14:44 UTC" --end="2021-06-22 14:45 UTC"'
302
+
303
+ ],
304
+
305
+ end: [
306
+ '--end'.pastel(:green),
307
+ ' Show events before specified time. Filtered by the `time` field',
308
+ ' Use with `--start` for between selections',
309
+ ' Ex: log filter --end="2021-06-22"'
310
+ ],
311
+
312
+ time_zone: [
313
+ '--time_zone'.pastel(:green),
314
+ ' Manipulate the `time` field into a specific timezone',
315
+ ' Ex: log filter --time_zone=EDT'
316
+
317
+ ],
318
+
319
+ text: [
320
+ '--text'.pastel(:green),
321
+ ' Full entry text searching (slow)',
322
+ ' --text="anything here"'
323
+ ],
324
+
325
+ table_style: [
326
+ '--table_style'.pastel(:green),
327
+ ' Renderer used for formatted output. basic, ascii, or unicode(default)',
328
+ ' Ex: log filter --table_style=base'
329
+ ],
330
+
331
+ truncate: [
332
+ '--truncate'.pastel(:green),
333
+ ' Truncate field length. On by default (4 rows). Performance issues!',
334
+ ' Disable with --truncate=0'.pastel(:bright_red),
335
+ ' Ex: --truncate=200, --truncate=2048"'
336
+ ],
337
+
338
+ field: [
339
+ 'Field Searching'.pastel(:blue),
340
+ ' --[key]=[value]',
341
+ ' Search in key for value',
342
+ ' Example: --path=mirror/pull'
343
+ ],
344
+
345
+ ls: [
346
+ 'Search specific logs'.pastel(:blue),
347
+ ' Any non dash parameters will be the log list to search from',
348
+ " Ex: log filter --path=api sidekiq/current (hint: use `#{'ls'.pastel(:yellow)}` for log names"
349
+ ],
350
+
351
+ examples: [
352
+ 'Example Queries'.pastel(:blue),
353
+ " Also see #{'examples'.pastel(:bright_blue)} for even more examples",
354
+ ' log filter --class=BuildFinishedWorker sidekiq/current --slice=time,message',
355
+ ' log filter gitlab-rails/api_json.log --slice=ua --uniq=ua --ua=gitlab-runner'
356
+ ]
357
+
358
+ }
359
+ end
360
+ # rubocop:enable Metrics/MethodLength,Metrics/ModuleLength
141
361
  end
142
362
  end
143
363
  end
@@ -3,6 +3,41 @@ module GreenHat
3
3
  module Shell
4
4
  # Logs
5
5
  module Log
6
+ def self.auto_complete(list, word)
7
+ # Argument Parsing
8
+ files, flags, _args = Args.parse(list)
9
+
10
+ # Don't try to autocomplete anything else
11
+ return nil unless word =~ /^-/
12
+
13
+ # Clean Up
14
+ word.delete!('-')
15
+ matches = FieldHelper.filter_flags(word)
16
+
17
+ if matches.count == 1
18
+ "--#{matches.first}"
19
+ elsif matches.count > 1
20
+ puts "#{'Filter Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
21
+ "--#{Cli.common_substr(matches)}"
22
+ # -----------------------------------
23
+ # TODO: Fix Icky Double Nesting
24
+ elsif files.count.nonzero?
25
+ matches = FieldHelper.fields_find(files, word, flags)
26
+
27
+ return nil if matches.nil?
28
+
29
+ if matches.count == 1
30
+ "--#{matches.first}"
31
+ elsif matches.count > 1
32
+ puts "#{'Field Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
33
+ "--#{Cli.common_substr(matches.map(&:to_s))}"
34
+ elsif FieldHelper.field_auto_complete?(word)
35
+ FieldHelper.field_auto_complete(word, files, flags)
36
+ end
37
+ # -----------------------------------
38
+ end
39
+ end
40
+
6
41
  def self.help
7
42
  puts "\u2500".pastel(:cyan) * 20
8
43
  puts "#{'Logs'.pastel(:yellow)} find stuff"
@@ -12,6 +47,7 @@ module GreenHat
12
47
  puts ' filter'.pastel(:green)
13
48
  puts " Primary way for log searching within greenhat. See #{'filter_help'.pastel(:blue)}"
14
49
  puts ' Time, round, slice/except, and/or, stats, uniq, sort'
50
+ puts " #{'filter_help'.pastel(:blue)} supports filtering Ex: #{'filter_help stats'.pastel(:blue)}"
15
51
  puts
16
52
 
17
53
  puts ' show'.pastel(:green)
@@ -27,8 +63,16 @@ module GreenHat
27
63
  puts "See #{'examples'.pastel(:bright_blue)} for query examples"
28
64
  end
29
65
 
30
- def self.filter_help
31
- ShellHelper::Filter.help
66
+ def self.filter_help(args = {})
67
+ if args.empty?
68
+ ShellHelper::Filter.help
69
+ else
70
+ list = ShellHelper::Filter.help_index.select do |k, _v|
71
+ k.to_s.include? args.first
72
+ end
73
+
74
+ puts list.values.map { |x| x.join("\n") }.join("\n\n")
75
+ end
32
76
  end
33
77
 
34
78
  def self.ls(args = [])
@@ -73,6 +117,12 @@ module GreenHat
73
117
  return true
74
118
  end
75
119
 
120
+ # Skip and Print Total if set
121
+ if flags[:fields]
122
+ ShellHelper.fields_print(results)
123
+ return true
124
+ end
125
+
76
126
  # Check Search Results
77
127
  if results.instance_of?(Hash) && results.values.flatten.empty?
78
128
  puts 'No results'.pastel(:red)