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.
- checksums.yaml +4 -4
- data/README.md +2 -7
- data/lib/greenhat/accessors/disk.rb +58 -2
- data/lib/greenhat/accessors/gitlab.rb +75 -0
- data/lib/greenhat/accessors/memory.rb +10 -10
- data/lib/greenhat/accessors/process.rb +10 -1
- data/lib/greenhat/cli.rb +128 -57
- data/lib/greenhat/color.rb +27 -0
- data/lib/greenhat/logbot.rb +9 -9
- data/lib/greenhat/settings.rb +51 -3
- data/lib/greenhat/shell/args.rb +146 -0
- data/lib/greenhat/shell/cat.rb +25 -73
- data/lib/greenhat/shell/color_string.rb +43 -0
- data/lib/greenhat/shell/disk.rb +30 -42
- data/lib/greenhat/shell/faststats.rb +80 -61
- data/lib/greenhat/shell/filter_help.rb +143 -0
- data/lib/greenhat/shell/gitlab.rb +61 -2
- data/lib/greenhat/shell/help.rb +98 -15
- data/lib/greenhat/shell/list.rb +46 -0
- data/lib/greenhat/shell/log.rb +78 -203
- data/lib/greenhat/shell/page.rb +39 -0
- data/lib/greenhat/shell/process.rb +57 -2
- data/lib/greenhat/shell/report.rb +70 -60
- data/lib/greenhat/shell/shell_helper.rb +601 -0
- data/lib/greenhat/shell.rb +27 -13
- data/lib/greenhat/thing/file_types.rb +76 -8
- data/lib/greenhat/thing/formatters/json_shellwords.rb +0 -3
- data/lib/greenhat/thing/formatters/nginx.rb +44 -0
- data/lib/greenhat/thing/formatters/syslog.rb +39 -0
- data/lib/greenhat/thing/helpers.rb +4 -4
- data/lib/greenhat/thing/kind.rb +9 -2
- data/lib/greenhat/thing/spinner.rb +3 -3
- data/lib/greenhat/thing.rb +3 -3
- data/lib/greenhat/tty/columns.rb +44 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat.rb +15 -14
- metadata +30 -20
- data/lib/greenhat/shell/helper.rb +0 -514
data/lib/greenhat/shell.rb
CHANGED
@@ -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.
|
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'.
|
47
|
+
puts "GreenHat Debug Logging #{'Off'.pastel(:red)}"
|
46
48
|
nil
|
47
49
|
else
|
48
|
-
puts "Debug #{'On'.
|
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
|
-
|
80
|
+
Settings.cmd_history_clear
|
67
81
|
end
|
68
82
|
|
69
83
|
def self.history
|
70
|
-
|
71
|
-
puts "#{i.to_s.ljust(3).
|
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.
|
84
|
-
puts "#{'GreenHat'.
|
85
|
-
puts ' - https://gitlab.com/gitlab-com/support/toolbox/greenhat'.
|
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
|
-
#
|
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
|
-
'
|
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: :
|
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: :
|
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: :
|
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: :
|
721
|
+
format: :syslog,
|
654
722
|
log: true,
|
655
723
|
pattern: [
|
656
724
|
%r{log/messages}
|
@@ -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'.
|
9
|
-
kind&.to_s&.
|
10
|
-
type&.
|
11
|
-
name&.
|
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
|
|
data/lib/greenhat/thing/kind.rb
CHANGED
@@ -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.
|
70
|
-
puts "Use '#{'json'.
|
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.
|
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.
|
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').
|
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
|
data/lib/greenhat/thing.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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
|