greenhat 0.1.5 → 0.3.2

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/lib/greenhat/accessors/disk.rb +58 -2
  3. data/lib/greenhat/accessors/gitlab.rb +75 -0
  4. data/lib/greenhat/accessors/memory.rb +10 -10
  5. data/lib/greenhat/accessors/process.rb +10 -1
  6. data/lib/greenhat/cli.rb +148 -63
  7. data/lib/greenhat/color.rb +27 -0
  8. data/lib/greenhat/logbot.rb +9 -9
  9. data/lib/greenhat/settings.rb +51 -3
  10. data/lib/greenhat/shell/args.rb +146 -0
  11. data/lib/greenhat/shell/cat.rb +25 -73
  12. data/lib/greenhat/shell/color_string.rb +43 -0
  13. data/lib/greenhat/shell/disk.rb +30 -42
  14. data/lib/greenhat/shell/faststats.rb +104 -58
  15. data/lib/greenhat/shell/field_helper.rb +75 -0
  16. data/lib/greenhat/shell/filter_help.rb +162 -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 +115 -209
  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 +654 -0
  25. data/lib/greenhat/shell.rb +27 -13
  26. data/lib/greenhat/thing/file_types.rb +54 -7
  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 +25 -3
  34. data/lib/greenhat/tty/columns.rb +44 -0
  35. data/lib/greenhat/version.rb +1 -1
  36. data/lib/greenhat.rb +16 -14
  37. metadata +42 -17
  38. data/lib/greenhat/shell/helper.rb +0 -541
@@ -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
@@ -43,9 +43,16 @@ module GreenHat
43
43
  /dmesg/
44
44
  ]
45
45
  },
46
- 'log/syslog' => {
46
+ 'repmgrd/current' => {
47
47
  format: :bracket_log,
48
48
  log: true,
49
+ pattern: [
50
+ %r{repmgrd/current}
51
+ ]
52
+ },
53
+ 'log/syslog' => {
54
+ format: :syslog,
55
+ log: true,
49
56
  pattern: [
50
57
  %r{log/syslog}
51
58
  ]
@@ -95,6 +102,20 @@ module GreenHat
95
102
  %r{consul/current}
96
103
  ]
97
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
+ },
98
119
  'pgbouncer/current' => {
99
120
  format: :time_space,
100
121
  log: true,
@@ -179,6 +200,13 @@ module GreenHat
179
200
  %r{logrotate/current}
180
201
  ]
181
202
  },
203
+ 'gitlab-rails/grpc.log' => {
204
+ format: :raw,
205
+ log: true,
206
+ pattern: [
207
+ %r{gitlab-rails/grpc.log}
208
+ ]
209
+ },
182
210
  'gitlab-rails/api_json.log' => {
183
211
  format: :api_json,
184
212
  log: true,
@@ -301,15 +329,22 @@ module GreenHat
301
329
  /mount/
302
330
  ]
303
331
  },
332
+ 'nginx/current' => {
333
+ format: :time_space,
334
+ log: true,
335
+ pattern: [
336
+ %r{nginx/current}
337
+ ]
338
+ },
304
339
  'nginx/gitlab_pages_access.log' => {
305
- format: :raw,
340
+ format: :nginx,
306
341
  log: true,
307
342
  pattern: [
308
343
  %r{nginx/gitlab_pages_access.log}
309
344
  ]
310
345
  },
311
346
  'nginx/gitlab_access.log' => {
312
- format: :raw,
347
+ format: :nginx,
313
348
  log: true,
314
349
  pattern: [
315
350
  %r{nginx/gitlab_access.log}
@@ -449,7 +484,13 @@ module GreenHat
449
484
  %r{redis/config},
450
485
  %r{redis-exporter/config},
451
486
  %r{registry/config},
452
- %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}
453
494
  ]
454
495
  },
455
496
  'redis/current' => {
@@ -460,7 +501,6 @@ module GreenHat
460
501
  %r{redis/@.*}
461
502
  ]
462
503
  },
463
-
464
504
  'nginx/gitlab_error.log' => {
465
505
  format: :time_space,
466
506
  log: true,
@@ -468,6 +508,13 @@ module GreenHat
468
508
  %r{nginx/gitlab_error.log}
469
509
  ]
470
510
  },
511
+ 'nginx/error.log' => {
512
+ format: :raw,
513
+ log: false,
514
+ pattern: [
515
+ %r{nginx/error.log}
516
+ ]
517
+ },
471
518
  'nginx/gitlab_registry_error.log' => {
472
519
  format: :time_space,
473
520
  log: true,
@@ -489,7 +536,7 @@ module GreenHat
489
536
  ]
490
537
  },
491
538
  'nginx/gitlab_registry_access.log' => {
492
- format: :raw,
539
+ format: :nginx,
493
540
  log: true,
494
541
  pattern: [
495
542
  %r{nginx/gitlab_registry_access.log}
@@ -671,7 +718,7 @@ module GreenHat
671
718
  ]
672
719
  },
673
720
  'log/messages' => {
674
- format: :raw,
721
+ format: :syslog,
675
722
  log: true,
676
723
  pattern: [
677
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 Layout/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 Layout/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)}' or '#{'raw'.colorize(:cyan)}' if there are no matches (see file_types.rb)"
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
@@ -26,9 +26,10 @@ class Thing < Teron
26
26
  field :parsed # Flag for Parsing
27
27
  field :result # Processed Data
28
28
  field :raw_result # Flag for reading raw data
29
+ field :result_fields # All available fields
29
30
 
30
31
  def friendly_name
31
- "#{archive.friendly_name.colorize(:blue)} #{name.colorize(:green)} #{id.colorize(:black)}"
32
+ "#{archive.friendly_name.pastel(:blue)} #{name.pastel(:green)}"
32
33
  end
33
34
 
34
35
  def setup
@@ -49,6 +50,13 @@ class Thing < Teron
49
50
  result
50
51
  end
51
52
 
53
+ # Processor
54
+ def fields
55
+ process unless parsed
56
+
57
+ result_fields
58
+ end
59
+
52
60
  def raw
53
61
  raw_read if raw_result.nil?
54
62
 
@@ -66,7 +74,7 @@ class Thing < Teron
66
74
  end
67
75
 
68
76
  def raw_read
69
- spin_start("Read #{name.colorize(:blue)} #{size.colorize(:light_black)}")
77
+ spin_start("Read #{name.pastel(:blue)} #{size.pastel(:bright_black)}")
70
78
  self.raw_result = File.read(file).split("\n")
71
79
  rescue StandardError => e
72
80
  LogBot.fatal('Raw Read', message: e.message, backtrace: e.backtrace.first)
@@ -103,7 +111,7 @@ class Thing < Teron
103
111
  raw_read if raw_result.nil?
104
112
 
105
113
  if methods.include? formatter
106
- spin_start("Parse #{name.colorize(:blue)} #{kind.to_s.colorize(:light_black)} ")
114
+ spin_start("Parse #{name.pastel(:blue)} #{kind.to_s.pastel(:bright_black)} ")
107
115
  begin
108
116
  send(formatter)
109
117
  rescue StandardError => e
@@ -116,6 +124,20 @@ class Thing < Teron
116
124
 
117
125
  self.parsed = true
118
126
 
127
+ self.result_fields = field_processing
128
+
119
129
  save!
120
130
  end
131
+
132
+ def field_processing
133
+ if data.instance_of?(Array)
134
+ data.select { |x| x.instance_of?(Hash) }.map(&:keys).flatten.uniq
135
+ else
136
+ []
137
+ end
138
+ rescue StandardError => e
139
+ LogBot.fatal('Process', message: e.message, backtrace: e.backtrace.first)
140
+
141
+ []
142
+ end
121
143
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Table
5
+ # A module for calculating table data column widths
6
+ #
7
+ # Used by {Table} to manage column sizing.
8
+ #
9
+ # @api private
10
+ module Columns
11
+ # Converts column widths to array format or infers default widths
12
+ #
13
+ # @param [TTY::Table] table
14
+ #
15
+ # @param [Array, Numeric, NilClass] column_widths
16
+ #
17
+ # @return [Array[Integer]]
18
+ #
19
+ # @api public
20
+ def widths_from(table, column_widths = nil)
21
+ case column_widths
22
+ when Array
23
+ assert_widths(column_widths, table.columns_size)
24
+ Array(column_widths).map(&:to_i)
25
+ when Numeric
26
+ Array.new(table.columns_size, column_widths)
27
+ when NilClass
28
+ # THE SHIM! Strings that are too large fail to render correctly to do an empty result
29
+ # Set the maximum table width to half the screen size. Can't be full size due to the table headers
30
+ LogBot.debug('TTY Column Width') if ENV['DEBUG']
31
+
32
+ # TODO: Check Empty Results
33
+ return [0] if table.data.empty?
34
+
35
+ extract_widths(table.data).map { |x| x >= TTY::Screen.width ? (TTY::Screen.width * 3 / 4) : x }
36
+
37
+ else
38
+ raise TypeError, 'Invalid type for column widths'
39
+ end
40
+ end
41
+ module_function :widths_from
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module GreenHat
2
- VERSION = '0.1.5'.freeze
2
+ VERSION = '0.3.2'.freeze
3
3
  end
data/lib/greenhat.rb CHANGED
@@ -1,27 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'action_view'
4
+ require 'active_support'
5
+ require 'active_support/core_ext'
6
+ require 'amazing_print'
4
7
  require 'benchmark'
8
+ require 'dotenv'
5
9
  require 'find'
6
- require 'tty-prompt'
7
- require 'tty-spinner'
8
- require 'tty-table'
9
- require 'tty-pager'
10
- require 'tty-cursor'
11
- require 'tty-reader'
12
10
  require 'hash_dot'
13
11
  require 'oj'
14
- require 'slim'
15
- require 'active_support'
16
- require 'active_support/core_ext'
12
+ require 'pastel'
17
13
  require 'pry'
18
- require 'amazing_print'
19
- require 'colorize'
14
+ require 'require_all'
20
15
  require 'semantic'
16
+ require 'slim'
17
+ require 'tty-cursor'
18
+ require 'tty-pager'
21
19
  require 'tty-progressbar'
22
- require 'require_all'
20
+ require 'tty-prompt'
21
+ require 'tty-reader'
22
+ require 'tty-spinner'
23
+ require 'tty-table'
24
+ require 'tty-which'
23
25
  require 'warning'
24
- require 'dotenv'
25
26
 
26
27
  # Custom Gem
27
28
  require 'teron'
@@ -49,6 +50,7 @@ require 'greenhat/archive'
49
50
  require 'greenhat/host'
50
51
  require 'greenhat/logbot'
51
52
  require 'greenhat/settings'
53
+ require 'greenhat/color'
52
54
 
53
55
  # Formatters - Loads Required Files Automatically
54
56
  require 'greenhat/thing/super_log'
@@ -65,7 +67,6 @@ require 'greenhat/thing'
65
67
  require 'greenhat/shell'
66
68
 
67
69
  # TODO: Confirm
68
- # require 'greenhat/thing/log_format'
69
70
  # require 'greenhat/host'
70
71
  # require 'greenhat/web'
71
72
 
@@ -76,5 +77,6 @@ require 'greenhat/pry_helpers'
76
77
  require 'greenhat/tty/line'
77
78
  require 'greenhat/tty/reader'
78
79
  require 'greenhat/tty/custom_line'
80
+ require 'greenhat/tty/columns'
79
81
 
80
82
  Warning.ignore(/The table size exceeds the currently set width/)