greenhat 0.5.1 → 0.6.1

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/greenhat/archive.rb +2 -0
  3. data/lib/greenhat/cli.rb +12 -2
  4. data/lib/greenhat/entrypoint.rb +36 -33
  5. data/lib/greenhat/logbot.rb +1 -1
  6. data/lib/greenhat/paper/flag_helper.rb +18 -0
  7. data/lib/greenhat/paper/paper_helper.rb +118 -0
  8. data/lib/greenhat/paper.rb +34 -0
  9. data/lib/greenhat/reports/builder.rb +98 -0
  10. data/lib/greenhat/reports/helpers.rb +101 -0
  11. data/lib/greenhat/reports/internal_methods.rb +156 -0
  12. data/lib/greenhat/reports/reports/errors.rb +49 -0
  13. data/lib/greenhat/reports/reports/faststats.rb +42 -0
  14. data/lib/greenhat/reports/reports/full.rb +143 -0
  15. data/lib/greenhat/reports/runner.rb +58 -0
  16. data/lib/greenhat/reports/shared.rb +37 -0
  17. data/lib/greenhat/reports/shell_helper.rb +34 -0
  18. data/lib/greenhat/reports.rb +79 -0
  19. data/lib/greenhat/settings.rb +6 -1
  20. data/lib/greenhat/shell/args.rb +9 -9
  21. data/lib/greenhat/shell/color_string.rb +1 -1
  22. data/lib/greenhat/shell/faststats.rb +24 -5
  23. data/lib/greenhat/shell/field_helper.rb +1 -1
  24. data/lib/greenhat/shell/filter_help.rb +36 -189
  25. data/lib/greenhat/shell/log.rb +18 -14
  26. data/lib/greenhat/shell/markdown.rb +355 -352
  27. data/lib/greenhat/shell/process.rb +11 -5
  28. data/lib/greenhat/shell/query.rb +183 -27
  29. data/lib/greenhat/shell/report.rb +415 -412
  30. data/lib/greenhat/shell/reports.rb +41 -0
  31. data/lib/greenhat/shell/shell_helper.rb +92 -34
  32. data/lib/greenhat/shell.rb +13 -2
  33. data/lib/greenhat/thing/file_types.rb +14 -0
  34. data/lib/greenhat/thing/formatters/clean_raw.rb +1 -1
  35. data/lib/greenhat/thing/formatters/runner_log.rb +70 -0
  36. data/lib/greenhat/thing/formatters/time_json.rb +12 -1
  37. data/lib/greenhat/thing/kind.rb +1 -1
  38. data/lib/greenhat/version.rb +1 -1
  39. data/lib/greenhat.rb +6 -8
  40. metadata +31 -4
  41. data/lib/greenhat/pry_helpers.rb +0 -51
  42. data/lib/greenhat/thing/super_log.rb +0 -1
@@ -2,198 +2,22 @@ module GreenHat
2
2
  # CLI Helper
3
3
  module ShellHelper
4
4
  # Unify Filter / Filter Help
5
- # rubocop:disable Metrics/MethodLength,Layout/LineLength
5
+ # rubocop:disable Metrics/MethodLength,Layout/LineLength,Metrics/ModuleLength
6
6
  module Filter
7
7
  def self.help(args = '')
8
- if args.blank?
9
- help_index.values.map { |x| x.push '' }
10
- else
11
- list = help_index.select do |k, _v|
12
- k.to_s.include? args
13
- end
8
+ output = if args.blank?
9
+ help_index.values.map { |x| x.push '' }
10
+ else
11
+ list = help_index.select do |k, _v|
12
+ k.to_s.include? args
13
+ end
14
14
 
15
- list.values
16
- end
15
+ list.values
16
+ end
17
17
 
18
- # .map { |x| x.join("\n") }.join("\n\n")
18
+ output.flatten(2)
19
19
  end
20
20
 
21
- # TODO: Confirm Remove
22
- # def self.legacy
23
- # puts "\u2500".pastel(:cyan) * 20
24
- # puts 'Filter'.pastel(:yellow)
25
- # puts "\u2500".pastel(:cyan) * 20
26
-
27
- # puts 'Options'.pastel(:blue)
28
- # puts '--raw'.pastel(:green)
29
- # puts ' Disable formatting and page/less'
30
- # puts
31
-
32
- # puts '--page'.pastel(:green)
33
- # puts ' Specifically enable or disable paging'
34
- # puts ' E.g. --page (default to true), --page=true, --page=false'
35
- # puts
36
-
37
- # puts '--round'.pastel(:green)
38
- # puts ' Attempt to round all integers. Default: 2.'
39
- # puts ' E.g. --round, --round=3, --round=0'
40
- # puts
41
-
42
- # puts '--limit'.pastel(:green)
43
- # puts ' Limit total output lines. Disabled by default. Default without value is based on screen height'
44
- # puts ' E.g. --limit, --limit=5'
45
- # puts
46
-
47
- # puts '--json'.pastel(:green)
48
- # puts ' Print output back into JSON'
49
- # puts
50
-
51
- # puts '--or'.pastel(:green)
52
- # puts ' Filters will use OR instead of AND (all match vs any match)'
53
- # puts
54
-
55
- # puts '--total'.pastel(:green)
56
- # puts ' Show total count, duration, start/end time for matching entries'
57
- # puts
58
-
59
- # puts '--fields'.pastel(:green)
60
- # puts ' Print only Available fields for selected files'
61
- # puts
62
-
63
- # puts '--slice'.pastel(:green)
64
- # puts ' Extract specific fields from entries (slice multiple with comma)'
65
- # puts ' Ex: --slice=path or --slice=path,params'
66
- # puts
67
-
68
- # puts '--except'.pastel(:green)
69
- # puts ' Exclude specific fields (except multiple with comma)'
70
- # puts ' Ex: --except=params --except=params,path'
71
- # puts
72
-
73
- # puts '--exists'.pastel(:green)
74
- # puts ' Ensure field exists regardless of contents'
75
- # puts ' Ex: --exists=params --exists=params,path'
76
- # puts
77
-
78
- # puts '--stats'.pastel(:green)
79
- # puts ' Order/Count occurrances by field. Combine with `truncate` for key names'
80
- # puts ' Ex: --stats=params --except=params,path'
81
- # puts
82
-
83
- # puts '--uniq'.pastel(:green)
84
- # puts ' Show unique values only'
85
- # puts ' Ex: --uniq=params --uniq=params,path'
86
- # puts
87
-
88
- # puts '--pluck'.pastel(:green)
89
- # puts ' Extract values from entries'
90
- # puts ' Ex: --pluck=params --pluck=params,path'
91
- # puts
92
-
93
- # puts '--archive'.pastel(:green)
94
- # puts ' Limit to specific archvie name (partial matching /inclusive). Matching SOS tar.gz name'
95
- # puts ' Ex: --archive=dev-gitlab_20210622154626, --archive=202106,202107'
96
- # puts
97
-
98
- # puts '--sort'.pastel(:green)
99
- # puts ' Sort by multiple fields'
100
- # puts ' Ex: --sort=duration_s,db_duration_s'
101
- # puts
102
-
103
- # puts '--reverse'.pastel(:green)
104
- # puts ' Reverse all results'
105
- # puts ' Ex: --reverse'
106
- # puts
107
-
108
- # puts '--combine'.pastel(:green)
109
- # puts ' Omit archive identifier dividers. Useful with sort or time filters'
110
- # puts ' Ex: --combine'
111
- # puts
112
-
113
- # puts '--case'.pastel(:green)
114
- # puts ' Exact case match. Defaults to case insensitive'
115
- # puts ' Ex: --case; --name=Jon, --name=jane --case'
116
- # puts
117
-
118
- # puts '--exact'.pastel(:green)
119
- # puts ' Exact parameter/value match. Defaults to partial match'
120
- # puts ' Ex: --field=CommonPartial --exact'
121
- # puts
122
-
123
- # puts '--start'.pastel(:green)
124
- # puts ' Show events after specified time. Filtered by the `time` field'
125
- # puts ' Use with `--end` for between selections'
126
- # puts ' Ex: log filter --start="2021-06-22 14:44 UTC" --end="2021-06-22 14:45 UTC"'
127
- # puts
128
-
129
- # puts '--end'.pastel(:green)
130
- # puts ' Show events before specified time. Filtered by the `time` field'
131
- # puts ' Use with `--start` for between selections'
132
- # puts ' Ex: log filter --end="2021-06-22"'
133
- # puts
134
-
135
- # puts '--time_zone'.pastel(:green)
136
- # puts ' Manipulate the `time` field into a specific timezone'
137
- # puts ' Ex: log filter --time_zone=EDT'
138
- # puts
139
-
140
- # puts '--text'.pastel(:green)
141
- # puts ' Full entry text searching (slow)'
142
- # puts ' --text="anything here"'
143
- # puts
144
-
145
- # puts '--table_style'.pastel(:green)
146
- # puts ' Renderer used for formatted output. basic, ascii, or unicode(default)'
147
- # puts ' Ex: log filter --table_style=base'
148
- # puts
149
-
150
- # puts '--truncate'.pastel(:green)
151
- # puts ' Truncate field length. On by default (4 rows). Performance issues!'
152
- # puts ' Disable with --truncate=0'.pastel(:bright_red)
153
- # puts ' Ex: --truncate=200, --truncate=2048"'
154
- # puts
155
-
156
- # puts 'Search specific logs'.pastel(:blue)
157
- # puts ' Any non dash parameters will be the log list to search from'
158
- # puts " Ex: log filter --path=api sidekiq/current (hint: use `#{'ls'.pastel(:yellow)}` for log names"
159
- # puts
160
-
161
- # puts 'General (Field) Searching'.pastel(:blue)
162
- # puts " There are different ways filter within specific keys/fields within log. The baseline is #{'--[key]=[value]'.pastel(:green)}"
163
- # puts ' This will, by default, select any entries with any partial match (case insensitive) of [value] in the entry [key]'
164
- # puts ' Example: --path=mirror/pull'
165
- # puts
166
-
167
- # puts " You can modify logic with params like: #{'case'.pastel(:green)}, #{'exact'.pastel(:green)}"
168
- # puts ' Ex Case turn on case sensitivity, exact will change from the inclusive to only exact matching.'
169
- # puts
170
-
171
- # puts " You can also use multiple #{'--[key]=[value]'.pastel(:green)} to narrow down, or combine it with #{'or'.pastel(:green)} to be more inclusive"
172
- # puts ' Ex nginx/gitlab_access.log --http_user_agent=gitlab-runner --path=/api/v4/jobs/request'
173
- # puts ' This will look through the access logs for anything that is a runner (user agent) and hitting the request endpoint'
174
- # puts
175
-
176
- # puts " You can also modify whether a field search excluded or a integer (and technically string) comparison by changing the operator: #{'(!= >= <=)'.pastel(:green)}"
177
- # puts ' Ex "nginx/gitlab_access.log --http_user_agent=gitlab-runner --http_user_agent!=13.12.0" will exclude any entries with 13.12.0/13.12 runners'
178
- # puts ' Ex "sidekiq/current --duration_s>=5 --class!=LdapSyncWorker" Duration over 5 that is not an ldap job'
179
- # puts
180
-
181
- # puts 'Pipe to Shell'.pastel(:blue)
182
- # puts ' This is very experimental! The idea is to take all the output from the search and allow a pipe into a traditional shell command.'
183
- # puts ' Due to the arg parsing its not a straight send to the terminal. You may need to escape quotes.'
184
- # puts ' Order is relevant, no arguments after the pipe'
185
- # puts
186
- # puts ' <files> <params> | grep path'
187
- # puts
188
-
189
- # puts 'Example Queries'.pastel(:blue)
190
- # puts " Also see #{'examples'.pastel(:bright_blue)} for even more examples"
191
- # puts ' log filter --class=BuildFinishedWorker sidekiq/current --slice=time,message'
192
- # puts ' log filter gitlab-rails/api_json.log --slice=ua --uniq=ua --ua=gitlab-runner'
193
-
194
- # puts
195
- # end
196
-
197
21
  def self.help_index
198
22
  {
199
23
  title: [
@@ -238,7 +62,8 @@ module GreenHat
238
62
 
239
63
  total: [
240
64
  '--total'.pastel(:green),
241
- ' Show total count, duration, start/end time for matching entries'
65
+ ' Show total count, duration, start/end time for matching entries',
66
+ ' Add `simple` to only return counts. e.g. --total=simple'
242
67
  ],
243
68
 
244
69
  fields: [
@@ -250,14 +75,20 @@ module GreenHat
250
75
  '--slice'.pastel(:green),
251
76
  ' Extract specific fields from entries (slice multiple with comma)',
252
77
  ' Ex: --slice=path or --slice=path,params'
253
-
254
78
  ],
255
79
 
256
80
  except: [
257
81
  '--except'.pastel(:green),
258
82
  ' Exclude specific fields (except multiple with comma)',
259
83
  ' Ex: --except=params --except=params,path'
84
+ ],
260
85
 
86
+ transform: [
87
+ '--transform'.pastel(:green),
88
+ ' Copy key to another key within results. Useful for queries that require (timestamp => time)',
89
+ ' Available Transforms, to_i, default is to copy',
90
+ ' Ex: --transform=timestamp,time',
91
+ ' --transform=cpu,cpu,to_i'
261
92
  ],
262
93
 
263
94
  exists: [
@@ -371,6 +202,22 @@ module GreenHat
371
202
  ' Ex: --truncate=200, --truncate=2048"'
372
203
  ],
373
204
 
205
+ interval: [
206
+ '--interval'.pastel(:green),
207
+ ' Split results down into a interval (based on the time field)',
208
+ ' Example Params: 5m, 1d, 3h, "30 minutes" (chronic duration)',
209
+ ' Ex: --interval=15m, --interval=1h"'
210
+ ],
211
+
212
+ percentile: [
213
+ '--percentile'.pastel(:green),
214
+ ' Stats breakdown on any integer value within the results. No params',
215
+ ' Best when combined with slice/round to limit/filter results',
216
+ ' No parameters, Returns 99,95,mean,min,max and entry count',
217
+ ' Ex: --percentile --round --slice=field',
218
+ ' Query: gitlab-rails/api_json.log --percentile --round=2 --slice=cpu_s'
219
+ ],
220
+
374
221
  field_search: [
375
222
  'General (Field) Searching'.pastel(:blue),
376
223
  " There are different ways filter within specific keys/fields within log. The baseline is #{'--[key]=[value]'.pastel(:green)}",
@@ -412,7 +259,7 @@ module GreenHat
412
259
 
413
260
  }
414
261
  end
415
- # rubocop:enable Metrics/MethodLength,Layout/LineLength
262
+ # rubocop:enable Metrics/MethodLength,Layout/LineLength,Metrics/ModuleLength
416
263
  end
417
264
  end
418
265
  end
@@ -4,7 +4,6 @@ module GreenHat
4
4
  # Logs
5
5
  # rubocop:disable Metrics/ModuleLength
6
6
  module Log
7
- extend Spinner # TODO: DEBUGGING REMOVE
8
7
  def self.auto_complete(list, word)
9
8
  # Argument Parsing
10
9
  files, flags, _args = Args.parse(list)
@@ -79,11 +78,12 @@ module GreenHat
79
78
 
80
79
  def self.filter_help(raw = {})
81
80
  args, flags, _args = Args.parse(raw)
81
+
82
82
  ShellHelper.show(ShellHelper::Filter.help(args.first), flags)
83
83
  end
84
84
 
85
85
  def self.ls(args = [])
86
- ShellHelper::List.list(args, Thing.list)
86
+ ShellHelper::List.list(args, ShellHelper::Log.list)
87
87
  end
88
88
 
89
89
  def self.show(raw = {})
@@ -106,7 +106,7 @@ module GreenHat
106
106
  end
107
107
 
108
108
  name = if raw.empty?
109
- Cli.prompt.ask('Log/name to save the results to? '.pastel(:yellow))
109
+ Cli.prompt.ask('Log entry to save the results to? '.pastel(:yellow))
110
110
  else
111
111
  raw.first
112
112
  end
@@ -139,7 +139,7 @@ module GreenHat
139
139
  end
140
140
 
141
141
  name = if raw.empty?
142
- Cli.prompt.ask('Log/name to save the results to? '.pastel(:yellow))
142
+ Cli.prompt.ask('Filename to save the results to? '.pastel(:yellow))
143
143
  else
144
144
  raw.first
145
145
  end
@@ -205,16 +205,10 @@ module GreenHat
205
205
  files, flags, args = Args.parse(raw)
206
206
 
207
207
  # Prepare Log List
208
- files = ShellHelper.prepare_list(files)
208
+ files = ShellHelper.prepare_list(files, ShellHelper::Log.list)
209
209
 
210
210
  results = Query.start(files, flags, args)
211
211
 
212
- # Skip and Print Total if set
213
- if flags[:total]
214
- ShellHelper.total_count(results, flags)
215
- return true
216
- end
217
-
218
212
  # Skip and Print Total if set
219
213
  if flags[:fields]
220
214
  ShellHelper.fields_print(results)
@@ -222,14 +216,15 @@ module GreenHat
222
216
  end
223
217
 
224
218
  # Check Search Results
225
- if results.instance_of?(Hash) && results.values.flatten.empty?
219
+ if results.empty?
226
220
  puts 'No results'.pastel(:red)
227
221
  ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
228
222
  elsif flags[:pipe]
229
223
  Pipe.show(results, flags[:pipe])
230
224
  else
225
+ # Allow for array / multiple table outputs
231
226
  # This causes the key 'colorized' output to also be included
232
- ShellHelper.show(results.to_a.compact.flatten, flags)
227
+ ShellHelper.show(results, flags)
233
228
  end
234
229
  rescue StandardError => e
235
230
  LogBot.fatal('Filter', message: e.message)
@@ -275,6 +270,10 @@ module GreenHat
275
270
  puts 'Show workhorse duration/URI. Filter by duration bounds'.pastel(:bright_green)
276
271
  puts 'gitlab-workhorse/current --duration_ms>=30000 --duration_ms<=45000 --slice=duration_ms,uri'
277
272
  puts
273
+
274
+ puts 'Show runner statistics'.pastel(:bright_green)
275
+ puts 'gitlab-rails/api_json.log --path=/api/v4/jobs/request --percentile --round=2'
276
+ puts
278
277
  end
279
278
  # rubocop:enable Layout/LineLength
280
279
 
@@ -286,7 +285,7 @@ module GreenHat
286
285
  files_list, flags, args = Args.parse(raw)
287
286
 
288
287
  # Prepare Log List
289
- files = ShellHelper.prepare_list(files_list)
288
+ files = ShellHelper.prepare_list(files_list, ShellHelper::Log.list)
290
289
 
291
290
  results = ShellHelper.search_start(files, flags, args)
292
291
 
@@ -387,6 +386,11 @@ module GreenHat
387
386
  puts "No matching files found for pattern #{files.to_s.pastel(:yellow)}"
388
387
  puts "See #{'ls'.pastel(:blue)} for available files"
389
388
  end
389
+
390
+ # Limit to Log Files
391
+ def self.list
392
+ Thing.all.select(&:log)
393
+ end
390
394
  end
391
395
 
392
396
  # --------