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
@@ -2,15 +2,17 @@ module GreenHat
2
2
  # Root Level Shell
3
3
  module Shell
4
4
  def self.pry
5
+ # rubocop:disable Lint/Debugger
5
6
  binding.pry
7
+ # rubocop:enable Lint/Debugger
6
8
  end
7
9
 
8
10
  def self.df
9
11
  Disk.df
10
12
  end
11
13
 
12
- def self.ps
13
- Process.ps
14
+ def self.ps(raw = {})
15
+ Process.ps raw
14
16
  end
15
17
 
16
18
  def self.netstat
@@ -34,7 +36,7 @@ module GreenHat
34
36
  file_list.each do |file|
35
37
  next if File.size(file).zero?
36
38
 
37
- puts "- Loading #{file.colorize(:green)}"
39
+ puts "- Loading #{file.pastel(:green)}"
38
40
 
39
41
  archive.things_create(file: file).setup
40
42
  end
@@ -42,14 +44,26 @@ module GreenHat
42
44
 
43
45
  def self.debug
44
46
  ENV['DEBUG'] = if ENV['DEBUG']
45
- puts "Debug #{'Off'.colorize(:red)}"
47
+ puts "GreenHat Debug Logging #{'Off'.pastel(:red)}"
46
48
  nil
47
49
  else
48
- puts "Debug #{'On'.colorize(:green)}"
50
+ puts "GreenHat Debug Logging #{'On'.pastel(:green)}"
49
51
  'true'
50
52
  end
51
53
  end
52
54
 
55
+ def self.quiet
56
+ Cli.quiet!
57
+
58
+ if Cli.quiet
59
+ puts "GreenHat Quiet Logging #{'Off'.pastel(:red)}"
60
+ nil
61
+ else
62
+ puts "GreenHat Quiet Logging #{'On'.pastel(:green)}"
63
+ 'true'
64
+ end
65
+ end
66
+
53
67
  def self.uptime
54
68
  Shell::Cat.default ['uptime']
55
69
  end
@@ -63,26 +77,26 @@ module GreenHat
63
77
  end
64
78
 
65
79
  def self.history_clear
66
- File.write(GreenHat::Cli.history_file, "\n")
80
+ Settings.cmd_history_clear
67
81
  end
68
82
 
69
83
  def self.history
70
- File.read(GreenHat::Cli.history_file).split("\n").each_with_index do |line, i|
71
- puts "#{i.to_s.ljust(3).colorize(:magenta)} #{line}"
84
+ Settings.cmd_history_clean.each_with_index do |line, i|
85
+ puts "#{i.to_s.ljust(3).pastel(:magenta)} #{line}"
72
86
  end
73
87
  end
74
88
 
75
89
  def self.ls
76
- GreenHat::Cli.help
90
+ GreenHat::Cli.help(false)
77
91
  end
78
92
 
79
93
  def self.ll
80
- GreenHat::Cli.help
94
+ GreenHat::Cli.help(false)
81
95
  end
82
96
 
83
- def self.about
84
- puts "#{'GreenHat'.colorize(:green)}: #{GreenHat::VERSION.colorize(:blue)}"
85
- puts ' - https://gitlab.com/gitlab-com/support/toolbox/greenhat'.colorize(:cyan)
97
+ def self.version
98
+ puts "#{'GreenHat'.pastel(:green)}: #{GreenHat::VERSION.pastel(:blue)}"
99
+ puts ' - https://gitlab.com/gitlab-com/support/toolbox/greenhat'.pastel(:cyan)
86
100
  end
87
101
  end
88
102
  end
@@ -1,5 +1,19 @@
1
1
  module GreenHat
2
- # Overall Type Parsing
2
+ # -------------------------------------
3
+ # File Types - Overall Type Parsing!
4
+ # -------------------------------------
5
+ # --- Adding a new File ----
6
+ # Duplicate one of the blocks and then update the name and pattern/regex to identify it
7
+ #
8
+ # The 'key' or 'name' is used to generically identify a type of file to be used in other collection tools.
9
+ # - Looking for errors in `gitlab-workhorse/current` will also include any rotated files via `gitlab-workhorse/@.*`
10
+ #
11
+ # Formatters: See `thing/formmaters` for the different kinds of formatters
12
+ # - `json` for plain json
13
+ # - `raw` to ignore/just read (e.g. for cat)
14
+ #
15
+ # log true/false to be included in the log/filter fields
16
+
3
17
  # rubocop:disable Metrics/MethodLength, Metrics/ModuleLength
4
18
  module FileTypes
5
19
  def types
@@ -29,9 +43,16 @@ module GreenHat
29
43
  /dmesg/
30
44
  ]
31
45
  },
32
- 'log/syslog' => {
46
+ 'repmgrd/current' => {
33
47
  format: :bracket_log,
34
48
  log: true,
49
+ pattern: [
50
+ %r{repmgrd/current}
51
+ ]
52
+ },
53
+ 'log/syslog' => {
54
+ format: :syslog,
55
+ log: true,
35
56
  pattern: [
36
57
  %r{log/syslog}
37
58
  ]
@@ -81,6 +102,20 @@ module GreenHat
81
102
  %r{consul/current}
82
103
  ]
83
104
  },
105
+ 'sentinel/current' => {
106
+ format: :time_space,
107
+ log: true,
108
+ pattern: [
109
+ %r{sentinel/current}
110
+ ]
111
+ },
112
+ 'consul/failover_pgbouncer.log' => {
113
+ format: :raw,
114
+ log: true,
115
+ pattern: [
116
+ %r{consul/failover_pgbouncer.log}
117
+ ]
118
+ },
84
119
  'pgbouncer/current' => {
85
120
  format: :time_space,
86
121
  log: true,
@@ -109,6 +144,13 @@ module GreenHat
109
144
  %r{gitaly/gitaly_ruby_json.log}
110
145
  ]
111
146
  },
147
+ 'gitaly/gitaly_lfs_smudge.log' => {
148
+ format: :json,
149
+ log: true,
150
+ pattern: [
151
+ %r{gitaly/gitaly_lfs_smudge.log}
152
+ ]
153
+ },
112
154
  'gitlab_status' => {
113
155
  format: :gitlab_status,
114
156
  pattern: [
@@ -158,6 +200,13 @@ module GreenHat
158
200
  %r{logrotate/current}
159
201
  ]
160
202
  },
203
+ 'gitlab-rails/grpc.log' => {
204
+ format: :raw,
205
+ log: true,
206
+ pattern: [
207
+ %r{gitlab-rails/grpc.log}
208
+ ]
209
+ },
161
210
  'gitlab-rails/api_json.log' => {
162
211
  format: :api_json,
163
212
  log: true,
@@ -280,15 +329,22 @@ module GreenHat
280
329
  /mount/
281
330
  ]
282
331
  },
332
+ 'nginx/current' => {
333
+ format: :time_space,
334
+ log: true,
335
+ pattern: [
336
+ %r{nginx/current}
337
+ ]
338
+ },
283
339
  'nginx/gitlab_pages_access.log' => {
284
- format: :raw,
340
+ format: :nginx,
285
341
  log: true,
286
342
  pattern: [
287
343
  %r{nginx/gitlab_pages_access.log}
288
344
  ]
289
345
  },
290
346
  'nginx/gitlab_access.log' => {
291
- format: :raw,
347
+ format: :nginx,
292
348
  log: true,
293
349
  pattern: [
294
350
  %r{nginx/gitlab_access.log}
@@ -428,7 +484,13 @@ module GreenHat
428
484
  %r{redis/config},
429
485
  %r{redis-exporter/config},
430
486
  %r{registry/config},
431
- %r{sidekiq/config}
487
+ %r{sidekiq/config},
488
+ %r{pgbouncer/config},
489
+ %r{pgbouncer-exporter/config},
490
+ %r{repmgrd/config},
491
+ %r{sentinel/config},
492
+ %r{consul/config},
493
+ %r{mailroom/current}
432
494
  ]
433
495
  },
434
496
  'redis/current' => {
@@ -439,7 +501,6 @@ module GreenHat
439
501
  %r{redis/@.*}
440
502
  ]
441
503
  },
442
-
443
504
  'nginx/gitlab_error.log' => {
444
505
  format: :time_space,
445
506
  log: true,
@@ -447,6 +508,13 @@ module GreenHat
447
508
  %r{nginx/gitlab_error.log}
448
509
  ]
449
510
  },
511
+ 'nginx/error.log' => {
512
+ format: :raw,
513
+ log: false,
514
+ pattern: [
515
+ %r{nginx/error.log}
516
+ ]
517
+ },
450
518
  'nginx/gitlab_registry_error.log' => {
451
519
  format: :time_space,
452
520
  log: true,
@@ -468,7 +536,7 @@ module GreenHat
468
536
  ]
469
537
  },
470
538
  'nginx/gitlab_registry_access.log' => {
471
- format: :raw,
539
+ format: :nginx,
472
540
  log: true,
473
541
  pattern: [
474
542
  %r{nginx/gitlab_registry_access.log}
@@ -650,7 +718,7 @@ module GreenHat
650
718
  ]
651
719
  },
652
720
  'log/messages' => {
653
- format: :raw,
721
+ format: :syslog,
654
722
  log: true,
655
723
  pattern: [
656
724
  %r{log/messages}
@@ -18,9 +18,6 @@ module GreenHat
18
18
 
19
19
  result.sort.to_h
20
20
  rescue StandardError => e
21
- binding.pry
22
- # TODO: Background Logger?
23
- e.message
24
21
  LogBot.warn('JSON Parse', e.message)
25
22
  next
26
23
  end
@@ -0,0 +1,44 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters
7
+ # ==========================================================================
8
+ def format_nginx
9
+ self.result = raw.map do |row|
10
+ ip, _sym, remote_user, rest = row.split(' ', 4)
11
+
12
+ time, rest = rest.split(']', 2)
13
+ time = Time.strptime(time, '[%d/%b/%Y:%H:%M:%S %z')
14
+
15
+ verb, status, bytes, http_referer, http_user_agent, gzip_ratio = Shellwords.split(rest)
16
+
17
+ method, path, http_version = verb.split
18
+
19
+ {
20
+ remote_addr: ip,
21
+ remote_user: remote_user,
22
+ method: method,
23
+ path: path,
24
+ status: status,
25
+ bytes: bytes,
26
+ http_version: http_version,
27
+ http_referer: http_referer,
28
+ http_user_agent: http_user_agent,
29
+ gzip_ratio: gzip_ratio,
30
+ time: time
31
+ }
32
+ end
33
+
34
+ :ok
35
+ end
36
+
37
+ # rubocop:disable Metrics/LineLength
38
+ # NGINX Conf: /var/opt/gitlab/nginx/conf/nginx.conf
39
+ # log_format gitlab_access '$remote_addr - $remote_user [$time_local] "$request_method $filtered_request_uri $server_protocol" $status $body_bytes_sent "$filtered_http_referer" "$http_user_agent" $gzip_ratio';
40
+ # rubocop:enable Metrics/LineLength
41
+
42
+ # ==========================================================================
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for bracket logs (dmesg, sos)
6
+ def format_syslog
7
+ self.result = raw.map do |row|
8
+ next if row.empty? || row == "\n"
9
+
10
+ format_syslog_row(row)
11
+ end
12
+
13
+ result.compact!
14
+ end
15
+
16
+ # Split / Parse Time
17
+ # TODO: Better sys log parsing? Cannot find ready-made regex/ruby parser
18
+ def format_syslog_row(row)
19
+ month, day, time, device, service, message = row.split(' ', 6)
20
+ service.gsub!(':', '')
21
+ pid = service.match(/\[(.*?)\]/)&.captures&.first
22
+
23
+ {
24
+ time: format_time_parse("#{month} #{day} #{time}"),
25
+ device: device,
26
+ service: service,
27
+ message: message,
28
+ pid: pid
29
+ }
30
+
31
+ # Return everything incase of error
32
+ rescue StandardError => e
33
+ LogBot.warn('SysLog Parse', e.message)
34
+ {
35
+ message: row
36
+ }
37
+ end
38
+ end
39
+ end
@@ -5,10 +5,10 @@ module GreenHat
5
5
  # Console Helper
6
6
  def inspect
7
7
  [
8
- 'Thing'.colorize(:light_black),
9
- kind&.to_s&.colorize(:blue),
10
- type&.colorize(:light_yellow),
11
- name&.colorize(:cyan)
8
+ 'Thing'.pastel(:bright_black),
9
+ kind&.to_s&.pastel(:blue),
10
+ type&.pastel(:bright_yellow),
11
+ name&.pastel(:cyan)
12
12
  ].compact.join(' ')
13
13
  end
14
14
 
@@ -52,7 +52,9 @@ module GreenHat
52
52
 
53
53
  # rubocop:disable Style/SymbolProc
54
54
  def prompt_for_kind
55
+ # rubocop:disable Lint/Debugger
55
56
  binding.pry if ENV['DEBUG']
57
+ # rubocop:enable Lint/Debugger
56
58
 
57
59
  # Default to everything
58
60
  prompt_list = types.clone
@@ -61,13 +63,18 @@ module GreenHat
61
63
  json = check_oj_parse?(first_line)
62
64
 
63
65
  if json
66
+ if Settings.assume_json?
67
+ self.type = 'json'
68
+ return true
69
+ end
70
+
64
71
  prompt_list.select! do |_k, v|
65
72
  v.to_s.include? 'json'
66
73
  end
67
74
  end
68
75
 
69
- puts "Unable to determine file type for #{name.colorize(:yellow)}"
70
- puts "Use '#{'json'.colorize(:cyan)}' and '#{'raw'.colorize(:cyan)}' if you cannot find any matches"
76
+ puts "Unable to determine file type for #{name.pastel(:yellow)}"
77
+ puts "Use '#{'json'.pastel(:cyan)}' or '#{'raw'.pastel(:cyan)}' if there are no matches (see file_types.rb)"
71
78
 
72
79
  option = prompt.select('Wat is this?', prompt_list.keys.sort_by(&:length), filter: true)
73
80
 
@@ -7,7 +7,7 @@ module GreenHat
7
7
 
8
8
  @spin_time = Time.now
9
9
  @spinner = TTY::Spinner.new(
10
- "#{time.colorize(:light_black)} - [:spinner] :title", hide_cursor: true, success_mark: '✔'.colorize(:green)
10
+ "#{time.pastel(:bright_black)} - [:spinner] :title", hide_cursor: true, success_mark: '✔'.pastel(:green)
11
11
  )
12
12
  @spinner.update(title: title)
13
13
 
@@ -25,7 +25,7 @@ module GreenHat
25
25
  title_update = if spin_end.blank?
26
26
  title
27
27
  else
28
- "#{title} (#{spin_end.colorize(:blue)})"
28
+ "#{title} (#{spin_end.pastel(:blue)})"
29
29
  end
30
30
 
31
31
  @spinner.update(title: title_update)
@@ -33,7 +33,7 @@ module GreenHat
33
33
  end
34
34
 
35
35
  def time
36
- Time.now.strftime('%I:%M:%S').colorize(:light_black)
36
+ Time.now.strftime('%I:%M:%S').pastel(:bright_black)
37
37
  end
38
38
 
39
39
  # Replace TimeDifference with https://stackoverflow.com/a/4136485/1678507
@@ -28,7 +28,7 @@ class Thing < Teron
28
28
  field :raw_result # Flag for reading raw data
29
29
 
30
30
  def friendly_name
31
- "#{archive.friendly_name.colorize(:blue)} #{name.colorize(:green)} #{id.colorize(:black)}"
31
+ "#{archive.friendly_name.pastel(:blue)} #{name.pastel(:green)}"
32
32
  end
33
33
 
34
34
  def setup
@@ -66,7 +66,7 @@ class Thing < Teron
66
66
  end
67
67
 
68
68
  def raw_read
69
- spin_start("Read #{name.colorize(:blue)} #{size.colorize(:light_black)}")
69
+ spin_start("Read #{name.pastel(:blue)} #{size.pastel(:bright_black)}")
70
70
  self.raw_result = File.read(file).split("\n")
71
71
  rescue StandardError => e
72
72
  LogBot.fatal('Raw Read', message: e.message, backtrace: e.backtrace.first)
@@ -103,7 +103,7 @@ class Thing < Teron
103
103
  raw_read if raw_result.nil?
104
104
 
105
105
  if methods.include? formatter
106
- spin_start("Parse #{name.colorize(:blue)} #{kind.to_s.colorize(:light_black)} ")
106
+ spin_start("Parse #{name.pastel(:blue)} #{kind.to_s.pastel(:bright_black)} ")
107
107
  begin
108
108
  send(formatter)
109
109
  rescue StandardError => e