greenhat 0.1.4 → 0.3.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -7
  3. data/lib/greenhat/accessors/disk.rb +58 -2
  4. data/lib/greenhat/accessors/gitlab.rb +75 -0
  5. data/lib/greenhat/accessors/memory.rb +10 -10
  6. data/lib/greenhat/accessors/process.rb +10 -1
  7. data/lib/greenhat/cli.rb +128 -57
  8. data/lib/greenhat/color.rb +27 -0
  9. data/lib/greenhat/logbot.rb +9 -9
  10. data/lib/greenhat/settings.rb +51 -3
  11. data/lib/greenhat/shell/args.rb +146 -0
  12. data/lib/greenhat/shell/cat.rb +25 -73
  13. data/lib/greenhat/shell/color_string.rb +43 -0
  14. data/lib/greenhat/shell/disk.rb +30 -42
  15. data/lib/greenhat/shell/faststats.rb +80 -61
  16. data/lib/greenhat/shell/filter_help.rb +143 -0
  17. data/lib/greenhat/shell/gitlab.rb +61 -2
  18. data/lib/greenhat/shell/help.rb +98 -15
  19. data/lib/greenhat/shell/list.rb +46 -0
  20. data/lib/greenhat/shell/log.rb +78 -203
  21. data/lib/greenhat/shell/page.rb +39 -0
  22. data/lib/greenhat/shell/process.rb +57 -2
  23. data/lib/greenhat/shell/report.rb +70 -60
  24. data/lib/greenhat/shell/shell_helper.rb +601 -0
  25. data/lib/greenhat/shell.rb +27 -13
  26. data/lib/greenhat/thing/file_types.rb +76 -8
  27. data/lib/greenhat/thing/formatters/json_shellwords.rb +0 -3
  28. data/lib/greenhat/thing/formatters/nginx.rb +44 -0
  29. data/lib/greenhat/thing/formatters/syslog.rb +39 -0
  30. data/lib/greenhat/thing/helpers.rb +4 -4
  31. data/lib/greenhat/thing/kind.rb +9 -2
  32. data/lib/greenhat/thing/spinner.rb +3 -3
  33. data/lib/greenhat/thing.rb +3 -3
  34. data/lib/greenhat/tty/columns.rb +44 -0
  35. data/lib/greenhat/version.rb +1 -1
  36. data/lib/greenhat.rb +15 -14
  37. metadata +30 -20
  38. data/lib/greenhat/shell/helper.rb +0 -514
@@ -8,60 +8,48 @@ module GreenHat
8
8
  Cli.help
9
9
  end
10
10
 
11
- # Easy Show All
12
- def self.df
13
- ShellHelper.file_output GreenHat::Disk.df
11
+ def self.help
12
+ puts "\u2500".pastel(:cyan) * 22
13
+ puts "#{'Disk'.pastel(:yellow)} - Storage Helper"
14
+ puts "\u2500".pastel(:cyan) * 22
15
+
16
+ ShellHelper.common_opts
17
+
18
+ puts 'Command Summary'.pastel(:blue)
19
+ puts ' df'.pastel(:green)
20
+ puts " Raw #{'df'.pastel(:cyan)} output"
21
+ puts
22
+ puts ' free'.pastel(:green)
23
+ puts ' Formatted / Bar Output'
24
+ puts
14
25
  end
15
26
 
16
- # rubocop:disable Metrics/MethodLength,Metrics/BlockLength
17
- def self.free
18
- GreenHat::Disk.df.each do |file|
19
- # Reject TMPFS
20
- puts file.friendly_name
21
- disks = file.data.sort_by { |x| x.use.to_i }.reverse.reject { |x| x.filesystem.include? 'tmpfs' }
27
+ # Easy Show All
28
+ def self.df(raw = {})
29
+ # Extract Args
30
+ files_list, flags, _args = Args.parse(raw)
22
31
 
23
- # pad_mount = GreenHat::Disk.max_padding(disks, :mounted_on)
24
- # pad_size = GreenHat::Disk.max_padding(disks, :size)
25
- # pad_used = GreenHat::Disk.max_padding(disks, :used)
26
- # pad_avail = GreenHat::Disk.max_padding(disks, :avail)
32
+ # Collect Files
33
+ files = ShellHelper.files(files_list, GreenHat::Disk.df, flags)
27
34
 
28
- pad_mount, pad_size, pad_used, pad_avail = GreenHat::Disk.padding(disks)
35
+ # Output
36
+ ShellHelper.file_output(files, flags)
37
+ end
29
38
 
30
- # Headers
31
- puts [
32
- 'Mount'.ljust(pad_mount).colorize(:blue),
33
- 'Size'.ljust(pad_size).colorize(:magenta),
34
- 'Used'.ljust(pad_used).colorize(:cyan),
35
- 'Avail'.ljust(pad_avail).colorize(:white),
36
- '% Use'.ljust(pad_avail).colorize(:green)
37
- ].join
39
+ def self.free(raw = {})
40
+ # Extract Args
41
+ files_list, flags, _args = Args.parse(raw)
38
42
 
39
- # Table Summary
40
- disks.map do |disk|
41
- # Pretty Disk Use
42
- use = [
43
- disk.use.rjust(5).ljust(5).colorize(:green),
44
- ' ['.colorize(:blue),
45
- ('=' * (disk.use.to_i / 2)).colorize(:green),
46
- ' ' * (50 - disk.use.to_i / 2),
47
- ']'.colorize(:blue)
48
- ].join
43
+ # Collect Files
44
+ files = ShellHelper.files(files_list, GreenHat::Disk.df, flags)
49
45
 
50
- # Whole Thing
51
- puts [
52
- disk.mounted_on.ljust(pad_mount).colorize(:blue),
53
- disk[:size].to_s.ljust(pad_size).colorize(:magenta),
54
- disk.used.to_s.ljust(pad_used).colorize(:cyan),
55
- disk.avail.to_s.ljust(pad_avail).colorize(:white),
56
- use
57
- ].join
58
- end
46
+ files.each do |file|
47
+ puts GreenHat::Disk.format_output(file, true)
59
48
 
60
49
  # File End Loop / Break
61
50
  puts
62
51
  end
63
52
  end
64
- # rubocop:enable Metrics/MethodLength,Metrics/BlockLength
65
53
  # ------------------------------------------------------------------------
66
54
  end
67
55
  end
@@ -5,47 +5,65 @@ module GreenHat
5
5
  module Faststats
6
6
  # rubocop:disable Metrics/MethodLength)
7
7
  def self.help
8
- puts "\u2500".colorize(:cyan) * 25
9
- puts "Gimme #{'Performance Stats'.colorize(:yellow)}"
10
- puts "\u2500".colorize(:cyan) * 25
8
+ puts "\u2500".pastel(:cyan) * 25
9
+ puts "Gimme #{'Performance Stats'.pastel(:yellow)}"
10
+ puts "\u2500".pastel(:cyan) * 25
11
11
 
12
- puts 'General'.colorize(:blue)
13
- puts " Any double dash arguments (e.g. #{'--color-output'.colorize(:green)}) are passed directly to fast-stats"
14
- puts " See #{'`fast-stats --help`'.colorize(:light_black)} for all available options"
12
+ puts 'General'.pastel(:blue)
13
+ puts " Any double dash arguments (e.g. #{'--color-output'.pastel(:green)}) are passed directly to fast-stats"
14
+ puts " See #{'`fast-stats --help`'.pastel(:bright_black)} for all available options"
15
15
  puts
16
16
 
17
- puts 'Common Options'.colorize(:blue)
18
- puts ' --raw'.colorize(:green)
17
+ puts 'Common Options'.pastel(:blue)
18
+ puts ' --raw'.pastel(:green)
19
19
  puts ' Do not use less/paging'
20
- puts ' --display'.colorize(:green)
21
- puts ' Show percentage of totals and/or actual durations (value, perc, both, default: both)'
22
- puts ' --sort'.colorize(:green)
20
+ puts ' --search'.pastel(:green)
21
+ puts ' Case-insensitive search of controller/method/worker field'
22
+ puts ' --sort'.pastel(:green)
23
23
  puts ' count,fail,max,median,min,p95,p99,rps,score'
24
- puts ' --limit'.colorize(:green)
24
+ puts ' --limit'.pastel(:green)
25
25
  puts ' The number of rows to print'
26
- puts ' --verbose'.colorize(:green)
26
+ puts ' --verbose'.pastel(:green)
27
27
  puts ' Prints the component details of the maximum, P99, P95, and median events by total duration for each'
28
28
  puts
29
29
 
30
- puts 'Commands'.colorize(:blue)
31
- puts 'ls'.colorize(:green)
30
+ puts 'Commands'.pastel(:blue)
31
+ puts 'ls'.pastel(:green)
32
32
  puts ' List available files'
33
33
  puts ' Options'
34
34
  puts ' -a, --all, show all files including source'
35
35
  puts
36
36
 
37
- puts '<file names+>'.colorize(:green)
37
+ puts '<file names+>'.pastel(:green)
38
38
  puts ' Print any file names'
39
39
  puts ' Ex: `gitaly/current`'
40
40
  puts ' Ex: `gitlab-rails/api_json.log gitlab-rails/production_json.log --raw`'
41
41
  puts
42
42
 
43
- puts 'top'.colorize(:green)
43
+ puts 'top'.pastel(:green)
44
44
  puts ' Print a summary of top items in a category'
45
45
  puts
46
46
 
47
- puts 'errors'.colorize(:green)
47
+ puts 'errors'.pastel(:green)
48
48
  puts ' Show summary of errors captured in log'
49
+ puts
50
+
51
+ puts 'Examples'.pastel(:blue)
52
+ puts ' Default'.pastel(:bright_white)
53
+ puts ' gitaly/current'
54
+ puts ' --raw gitlab-rails/production_json.log'
55
+ puts ' gitlab-rails/api_json.log --sort=count'
56
+ puts ' --search=pipeline sidekiq/current'
57
+ puts
58
+
59
+ puts ' Top'.pastel(:bright_white)
60
+ puts ' top gitaly/current'
61
+ puts ' top --limit=5 sidekiq/current'
62
+ puts
63
+
64
+ puts ' Errors'.pastel(:bright_white)
65
+ puts ' errors gitaly/current'
66
+ puts ' errors gitaly/current --no-border'
49
67
  end
50
68
  # rubocop:enable Metrics/MethodLength)
51
69
 
@@ -67,7 +85,7 @@ module GreenHat
67
85
  if all
68
86
  puts "- #{log.friendly_name}"
69
87
  else
70
- puts "- #{log.name.colorize(:yellow)}"
88
+ puts "- #{log.name.pastel(:yellow)}"
71
89
  end
72
90
  end
73
91
  end
@@ -77,18 +95,10 @@ module GreenHat
77
95
  end
78
96
 
79
97
  # Vanilla Fast Stats
80
- def self.default(file_list, _other = nil)
81
- # Extract Args
82
- file_list, opts, args = ShellHelper.param_parse(file_list)
83
-
84
- cmd = opts.map { |opt| "--#{opt.field}=#{opt.value}" }.join(' ')
85
- cmd += args.keys.map { |arg| "--#{arg}" }.join(' ')
98
+ def self.default(raw, _other = nil)
99
+ files, flags, cmd = ShellHelper::Faststats.parse(raw)
86
100
 
87
- # Prepare List
88
- file_list = ShellHelper.prepare_list(file_list, ShellHelper::Faststats.things)
89
-
90
- # Convert to Things
91
- files = ShellHelper.find_things(file_list)
101
+ LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
92
102
 
93
103
  results = ShellHelper.file_process(files) do |file|
94
104
  [
@@ -98,7 +108,7 @@ module GreenHat
98
108
  ]
99
109
  end
100
110
 
101
- ShellHelper.show(results.flatten, args)
111
+ ShellHelper.show(results.flatten, flags)
102
112
  end
103
113
 
104
114
  # ========================================================================
@@ -110,21 +120,10 @@ module GreenHat
110
120
  # --limit=X
111
121
  # --sort=count,fail,max,median,min,p95,p99,rps,score
112
122
  # ========================================================================
113
- def self.top(log_list)
114
- # Extract Args
115
- log_list, opts, args = ShellHelper.param_parse(log_list)
116
-
117
- # Default to color output
118
- args['color-output'] ||= true
119
-
120
- cmd = opts.map { |opt| "--#{opt.field}=#{opt.value}" }.join(' ')
121
- cmd += args.keys.map { |arg| "--#{arg}" }.join(' ')
122
-
123
- # Prepare Log List
124
- log_list = ShellHelper.prepare_list(log_list, ShellHelper::Faststats.things)
123
+ def self.top(raw)
124
+ files, flags, cmd = ShellHelper::Faststats.parse(raw)
125
125
 
126
- # Convert to Things
127
- files = ShellHelper.find_things(log_list)
126
+ LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
128
127
 
129
128
  results = ShellHelper.file_process(files) do |file|
130
129
  [
@@ -134,28 +133,19 @@ module GreenHat
134
133
  ]
135
134
  end
136
135
 
137
- ShellHelper.show(results.flatten, args)
136
+ ShellHelper.show(results.flatten, flags)
138
137
  end
139
138
  # ========================================================================
140
139
 
141
140
  # ========================================================================
142
141
  # ===== [ Fast Stats - Errors ] ====================
143
142
  # ========================================================================
144
- def self.errors(log_list)
145
- # Extract Args
146
- log_list, opts, args = ShellHelper.param_parse(log_list)
143
+ def self.errors(raw)
144
+ # Add Color Output
145
+ raw.push '--color-output'
146
+ files, flags, cmd = ShellHelper::Faststats.parse(raw)
147
147
 
148
- # Default to color output
149
- args['color-output'] ||= true
150
-
151
- cmd = opts.map { |opt| "--#{opt.field}=#{opt.value}" }.join(' ')
152
- cmd += args.keys.map { |arg| "--#{arg}" }.join(' ')
153
-
154
- # Prepare Log List
155
- log_list = ShellHelper.prepare_list(log_list, ShellHelper::Faststats.things)
156
-
157
- # Convert to Things
158
- files = ShellHelper.find_things(log_list)
148
+ LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
159
149
 
160
150
  results = ShellHelper.file_process(files) do |file|
161
151
  [
@@ -165,7 +155,7 @@ module GreenHat
165
155
  ]
166
156
  end
167
157
 
168
- ShellHelper.show(results.flatten, args)
158
+ ShellHelper.show(results.flatten, flags)
169
159
  end
170
160
  # ========================================================================
171
161
  end
@@ -176,6 +166,35 @@ module GreenHat
176
166
  module ShellHelper
177
167
  # Hide from Commands
178
168
  module Faststats
169
+ # Default Settings from arg parse that won't work
170
+ def self.invalid_settings
171
+ %i[page round truncate logic fuzzy_file_match]
172
+ end
173
+
174
+ def self.parse(raw)
175
+ file_list, flags, args = Args.parse(raw, invalid_settings)
176
+ cmd = args.map { |opt| "--#{opt.field}=#{opt.value}" }.join(' ')
177
+ cmd += flags.map do |flag, value|
178
+ # Don't Include Raw
179
+ next if flag == :raw
180
+
181
+ case value
182
+ when true then "--#{flag}"
183
+ when Array then "--#{flag}=#{value.join}"
184
+ else
185
+ "--#{flag}=#{value}"
186
+ end
187
+ end.join(' ')
188
+
189
+ # Prepare Log List
190
+ file_list = ShellHelper.prepare_list(file_list, ShellHelper::Faststats.things, flags)
191
+
192
+ # Convert to Things
193
+ files = ShellHelper.find_things(file_list)
194
+
195
+ [files, flags, cmd]
196
+ end
197
+
179
198
  def self.files
180
199
  %w[
181
200
  production_json
@@ -0,0 +1,143 @@
1
+ module GreenHat
2
+ # CLI Helper
3
+ module ShellHelper
4
+ # Unify Filter / Filter Help
5
+ module Filter
6
+ # rubocop:disable Metrics/MethodLength
7
+ def self.help
8
+ puts "\u2500".pastel(:cyan) * 20
9
+ puts 'Filter'.pastel(:yellow)
10
+ puts "\u2500".pastel(:cyan) * 20
11
+
12
+ puts 'Options'.pastel(:blue)
13
+ puts '--raw'.pastel(:green)
14
+ puts ' Do not use less/paging'
15
+ puts
16
+
17
+ puts '--page'.pastel(:green)
18
+ puts ' Specifically enable or disable paging'
19
+ puts ' E.g. --page (default to true), --page=true, --page=false'
20
+ puts
21
+
22
+ puts '--round'.pastel(:green)
23
+ puts ' Attempt to round all integers. Default: 2.'
24
+ puts ' E.g. --round, --round=3, --round=0'
25
+ puts
26
+
27
+ puts '--limit'.pastel(:green)
28
+ puts ' Limit total output lines. Disabled by default. Default without value is based on screen height'
29
+ puts ' E.g. --limit, --limit=5'
30
+ puts
31
+
32
+ puts '--json'.pastel(:green)
33
+ puts ' Print output back into JSON'
34
+ puts
35
+
36
+ puts '--or'.pastel(:green)
37
+ puts ' Filters will use OR instead of AND (all match vs any match)'
38
+ puts
39
+
40
+ puts '--total'.pastel(:green)
41
+ puts ' Print only total count of matching entries'
42
+ puts
43
+
44
+ puts '--slice'.pastel(:green)
45
+ puts ' Extract specific fields from entries (slice multiple with comma)'
46
+ puts ' Ex: --slice=path or --slice=path,params'
47
+ puts
48
+
49
+ puts '--except'.pastel(:green)
50
+ puts ' Exclude specific fields (except multiple with comma)'
51
+ puts ' Ex: --except=params --except=params,path'
52
+ puts
53
+
54
+ puts '--exists'.pastel(:green)
55
+ puts ' Ensure field exists regardless of contents'
56
+ puts ' Ex: --exists=params --exists=params,path'
57
+ puts
58
+
59
+ puts '--stats'.pastel(:green)
60
+ puts ' Order/Count occurrances by field'
61
+ puts ' Ex: --stats=params --except=params,path'
62
+ puts
63
+
64
+ puts '--uniq'.pastel(:green)
65
+ puts ' Show unique values only'
66
+ puts ' Ex: --uniq=params --uniq=params,path'
67
+ puts
68
+
69
+ puts '--pluck'.pastel(:green)
70
+ puts ' Extract values from entries'
71
+ puts ' Ex: --pluck=params --pluck=params,path'
72
+ puts
73
+
74
+ puts '--archive'.pastel(:green)
75
+ puts ' Limit to specific archvie name (partial matching /inclusive). Matching SOS tar.gz name'
76
+ puts ' Ex: --archive=dev-gitlab_20210622154626, --archive=202106,202107'
77
+ puts
78
+
79
+ puts '--sort'.pastel(:green)
80
+ puts ' Sort by multiple fields'
81
+ puts ' Ex: --sort=duration_s,db_duration_s'
82
+ puts
83
+
84
+ puts '--reverse'.pastel(:green)
85
+ puts ' Reverse all results'
86
+ puts ' Ex: --reverse'
87
+ puts
88
+
89
+ puts '--combine'.pastel(:green)
90
+ puts ' Omit archive identifier dividers. Useful with sort or time filters'
91
+ puts ' Ex: --combine'
92
+ puts
93
+
94
+ puts '--case'.pastel(:green)
95
+ puts ' Exact case match. Defaults to case insensitive'
96
+ puts ' Ex: --case; --name=Jon, --name=jane --case'
97
+ puts
98
+
99
+ puts '--exact'.pastel(:green)
100
+ puts ' Exact parameter/value match. Defaults to partial match'
101
+ puts ' Ex: --field=CommonPartial --exact'
102
+ puts
103
+
104
+ puts '--start'.pastel(:green)
105
+ puts ' Show events after specified time. Filtered by the `time` field'
106
+ puts ' Use with `--end` for between selections'
107
+ puts ' Ex: log filter --start="2021-06-22 14:44 UTC" --end="2021-06-22 14:45 UTC"'
108
+ puts
109
+
110
+ puts '--end'.pastel(:green)
111
+ puts ' Show events before specified time. Filtered by the `time` field'
112
+ puts ' Use with `--start` for between selections'
113
+ puts ' Ex: log filter --end="2021-06-22"'
114
+ puts
115
+
116
+ puts '--truncate'.pastel(:green)
117
+ puts ' Truncate field length. On by default (4 rows). Performance issues!'
118
+ puts ' Disable with --truncate=0'.pastel(:bright_red)
119
+ puts ' Ex: --truncate=200, --truncate=2048"'
120
+ puts
121
+
122
+ puts 'Field Searching'.pastel(:blue)
123
+ puts ' --[key]=[value]'
124
+ puts ' Search in key for value'
125
+ puts ' Example: --path=mirror/pull'
126
+ puts
127
+
128
+ puts 'Search specific logs'.pastel(:blue)
129
+ puts ' Any non dash parameters will be the log list to search from'
130
+ puts " Ex: log filter --path=api sidekiq/current (hint: use `#{'ls'.pastel(:yellow)}` for log names"
131
+ puts
132
+
133
+ puts 'Example Queries'.pastel(:blue)
134
+ puts " Also see #{'examples'.pastel(:bright_blue)} for even more examples"
135
+ puts ' log filter --class=BuildFinishedWorker sidekiq/current --slice=time,message'
136
+ puts ' log filter gitlab-rails/api_json.log --slice=ua --uniq=ua --ua=gitlab-runner'
137
+
138
+ puts
139
+ end
140
+ # rubocop:enable Metrics/MethodLength
141
+ end
142
+ end
143
+ end