greenhat 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/lib/greenhat/accessors/disk.rb +1 -1
- data/lib/greenhat/archive.rb +2 -0
- data/lib/greenhat/cli.rb +12 -2
- data/lib/greenhat/entrypoint.rb +36 -33
- data/lib/greenhat/host.rb +1 -1
- data/lib/greenhat/logbot.rb +1 -1
- data/lib/greenhat/paper/flag_helper.rb +18 -0
- data/lib/greenhat/paper/paper_helper.rb +118 -0
- data/lib/greenhat/paper.rb +34 -0
- data/lib/greenhat/reports/builder.rb +98 -0
- data/lib/greenhat/reports/helpers.rb +101 -0
- data/lib/greenhat/reports/internal_methods.rb +156 -0
- data/lib/greenhat/reports/reports/errors.rb +51 -0
- data/lib/greenhat/reports/reports/faststats.rb +42 -0
- data/lib/greenhat/reports/reports/full.rb +143 -0
- data/lib/greenhat/reports/runner.rb +58 -0
- data/lib/greenhat/reports/shared.rb +37 -0
- data/lib/greenhat/reports/shell_helper.rb +34 -0
- data/lib/greenhat/reports.rb +79 -0
- data/lib/greenhat/settings.rb +6 -1
- data/lib/greenhat/shell/args.rb +9 -9
- data/lib/greenhat/shell/color_string.rb +1 -1
- data/lib/greenhat/shell/faststats.rb +24 -5
- data/lib/greenhat/shell/field_helper.rb +1 -1
- data/lib/greenhat/shell/filter_help.rb +36 -189
- data/lib/greenhat/shell/log.rb +28 -16
- data/lib/greenhat/shell/markdown.rb +355 -352
- data/lib/greenhat/shell/process.rb +11 -5
- data/lib/greenhat/shell/query.rb +184 -28
- data/lib/greenhat/shell/report.rb +415 -412
- data/lib/greenhat/shell/reports.rb +41 -0
- data/lib/greenhat/shell/shell_helper.rb +172 -117
- data/lib/greenhat/shell.rb +13 -2
- data/lib/greenhat/thing/file_types.rb +38 -2
- data/lib/greenhat/thing/formatters/clean_raw.rb +1 -1
- data/lib/greenhat/thing/formatters/exporters.rb +48 -0
- data/lib/greenhat/thing/formatters/identify_db.rb +32 -0
- data/lib/greenhat/thing/formatters/runner_log.rb +70 -0
- data/lib/greenhat/thing/formatters/table.rb +15 -1
- data/lib/greenhat/thing/formatters/time_json.rb +12 -1
- data/lib/greenhat/thing/kind.rb +1 -1
- data/lib/greenhat/thing.rb +1 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat.rb +6 -8
- metadata +33 -4
- data/lib/greenhat/pry_helpers.rb +0 -51
- data/lib/greenhat/thing/super_log.rb +0 -1
@@ -0,0 +1,156 @@
|
|
1
|
+
# GreenHat Namespace
|
2
|
+
module GreenHat
|
3
|
+
# Reports Parent Class
|
4
|
+
module Reports
|
5
|
+
# Method Helper Module
|
6
|
+
module InternalMethods
|
7
|
+
# Archive Header Printer
|
8
|
+
def archive_header(color = :blue)
|
9
|
+
puts archive.friendly_name.pastel(color)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Header Printer
|
13
|
+
def header(text, color = :bright_yellow, bold = :bold)
|
14
|
+
puts text.pastel(color, bold)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raw Print
|
18
|
+
def cat(name, show_output, block)
|
19
|
+
thing = archive.thing? name
|
20
|
+
return unless thing
|
21
|
+
|
22
|
+
output = instance_exec(thing.raw_full, &block)
|
23
|
+
show output if show_output
|
24
|
+
end
|
25
|
+
|
26
|
+
# Parsed Print
|
27
|
+
def info(name, show_output, block)
|
28
|
+
thing = archive.thing? name
|
29
|
+
return unless thing
|
30
|
+
|
31
|
+
output = instance_exec(thing.data, &block)
|
32
|
+
show output if show_output
|
33
|
+
end
|
34
|
+
|
35
|
+
# Help
|
36
|
+
def help(block)
|
37
|
+
instance_exec(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Log Query
|
41
|
+
def query(query, show_output, block)
|
42
|
+
files, query_flags, query_args = GreenHat::Args.parse(Shellwords.split(query))
|
43
|
+
query_flags[:archive] = [archive.name] # Limit query to archive
|
44
|
+
query_flags[:combine] = true
|
45
|
+
|
46
|
+
# Default to everything
|
47
|
+
files = archive.things if files.empty?
|
48
|
+
|
49
|
+
results = Query.start(files, query_flags, query_args)
|
50
|
+
|
51
|
+
# Print and Exit of No Block / Show
|
52
|
+
return show(results) if block.nil? && show_output
|
53
|
+
|
54
|
+
output = instance_exec(results, &block)
|
55
|
+
show output if show_output
|
56
|
+
end
|
57
|
+
|
58
|
+
# Log Query / Assume Format
|
59
|
+
def query_format(query, show_output, block)
|
60
|
+
files, query_flags, query_args = GreenHat::Args.parse(Shellwords.split(query))
|
61
|
+
query_flags[:archive] = [archive.name] # Limit query to archive
|
62
|
+
query_flags[:combine] = true
|
63
|
+
|
64
|
+
# Default to everything
|
65
|
+
query_flags = archive.things if files.empty?
|
66
|
+
|
67
|
+
# Filter
|
68
|
+
results = GreenHat::Query.start(files, query_flags, query_args)
|
69
|
+
|
70
|
+
# Print and Exit of No Block / Show
|
71
|
+
return show(results) if block.nil? && show_output
|
72
|
+
|
73
|
+
block_output = instance_exec(results, &block)
|
74
|
+
show block_output if show_output
|
75
|
+
end
|
76
|
+
|
77
|
+
def faststats(raw, subcmd)
|
78
|
+
return true unless TTY::Which.exist? 'fast-stats'
|
79
|
+
|
80
|
+
files, _flags, cmd = ShellHelper::Faststats.parse(Shellwords.split(raw))
|
81
|
+
|
82
|
+
results = ShellHelper.file_process(files) do |file|
|
83
|
+
output = `fast-stats #{subcmd} #{cmd} #{file.file} 2>&1`
|
84
|
+
result = $CHILD_STATUS.success?
|
85
|
+
|
86
|
+
next unless result
|
87
|
+
|
88
|
+
[
|
89
|
+
file.name.pastel(:green),
|
90
|
+
output.split("\n"),
|
91
|
+
"\n"
|
92
|
+
]
|
93
|
+
end
|
94
|
+
|
95
|
+
show results.compact.flatten
|
96
|
+
end
|
97
|
+
|
98
|
+
# TODO
|
99
|
+
# results = GreenHat::ShellHelper::Faststats.run(thing, 'top') # JSON FORMAT
|
100
|
+
|
101
|
+
# Paper Render Helper
|
102
|
+
def show(value)
|
103
|
+
if value.instance_of?(Array)
|
104
|
+
value.each do |x|
|
105
|
+
output.push GreenHat::Paper.new(data: x, flags: flags).render
|
106
|
+
end
|
107
|
+
else
|
108
|
+
output.push GreenHat::Paper.new(data: value, flags: flags).render
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Line Break Helper
|
113
|
+
def br(_ = nil)
|
114
|
+
puts
|
115
|
+
end
|
116
|
+
|
117
|
+
# Store for potential Paginated Response
|
118
|
+
def puts(text = '')
|
119
|
+
output.push text
|
120
|
+
end
|
121
|
+
|
122
|
+
# Accessor Helper
|
123
|
+
def archive
|
124
|
+
archive
|
125
|
+
end
|
126
|
+
|
127
|
+
def gitlab_version
|
128
|
+
thing = archive.thing? 'gitlab/version-manifest.json'
|
129
|
+
return unless thing
|
130
|
+
|
131
|
+
puts "#{'GitLab Version'.pastel(:cyan)}: #{thing.data.build_version}"
|
132
|
+
end
|
133
|
+
|
134
|
+
# ==============================================================================
|
135
|
+
# General Helpers
|
136
|
+
# ==============================================================================
|
137
|
+
# Indentation Helper
|
138
|
+
def indent(text, indent_value = 2)
|
139
|
+
if indent_value.zero?
|
140
|
+
text
|
141
|
+
else
|
142
|
+
"#{' ' * indent_value}#{text}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def percent(value, total)
|
147
|
+
((value / total.to_f) * 100).round
|
148
|
+
end
|
149
|
+
|
150
|
+
# Number Helper
|
151
|
+
def human_size_to_number(value)
|
152
|
+
GreenHat::ShellHelper.human_size_to_number value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
archive_header
|
2
|
+
|
3
|
+
help do
|
4
|
+
header 'Error Reports'
|
5
|
+
puts 'This will collect errors from the exceptions, production, application, api, workhorse, and sidekiq logs'
|
6
|
+
puts 'Without arguments it will count and unique the error messages'
|
7
|
+
br
|
8
|
+
puts indent("#{'--verbose'.pastel(:green)} Print all of the error messages")
|
9
|
+
puts indent("#{'--filter'.pastel(:green)} Filter Error messages")
|
10
|
+
puts indent('Ex: --filter=exception,production'.pastel(:cyan), 4)
|
11
|
+
puts indent('Ex: --filter!=api'.pastel(:cyan), 4)
|
12
|
+
end
|
13
|
+
|
14
|
+
entries = [
|
15
|
+
{ header: 'Exceptions', base: 'gitlab-rails/exceptions_json.log', stats: 'exception.message,exception.class' },
|
16
|
+
{ header: 'Production', base: 'gitlab-rails/production_json.log --status=500 ',
|
17
|
+
stats: 'exception.message,exception.class' },
|
18
|
+
{
|
19
|
+
header: 'Application',
|
20
|
+
base: 'gitlab-rails/application_json.log --message!="Cannot obtain an exclusive lease" --severity=error',
|
21
|
+
stats: 'message'
|
22
|
+
},
|
23
|
+
{ header: 'Workhorse', base: 'gitlab-workhorse/current --level=error', stats: 'error' },
|
24
|
+
{ header: 'Sidekiq', base: 'sidekiq/current --severity=error', stats: 'message' },
|
25
|
+
{ header: 'API', base: 'gitlab-rails/api_json.log --severity=error',
|
26
|
+
stats: 'exception.class,exception.message,status' },
|
27
|
+
{ header: 'Gitaly', base: 'gitaly/current --level=error --truncate=99', stats: 'error' }
|
28
|
+
]
|
29
|
+
|
30
|
+
# Filter Logic
|
31
|
+
filters = args_select(:filter)
|
32
|
+
unless filters.empty?
|
33
|
+
entries.select! do |entry|
|
34
|
+
filters.any? do |filter|
|
35
|
+
!filter.bang if filter.value.split(',').any? { |x| entry.header.downcase.include? x }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return output
|
41
|
+
entries.each do |entry|
|
42
|
+
query_string = flags[:verbose] ? entry.base : entry.base + " --stats=#{entry.stats}"
|
43
|
+
query(query_string, false) do |results|
|
44
|
+
next if results.empty?
|
45
|
+
next if !flags[:verbose] && results.map(&:values).map(&:first).sum.zero?
|
46
|
+
|
47
|
+
header entry.header
|
48
|
+
|
49
|
+
show results
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
archive_header
|
2
|
+
|
3
|
+
help do
|
4
|
+
header 'FastStats'
|
5
|
+
puts 'Run against all the things'
|
6
|
+
br
|
7
|
+
puts indent("#{'--filter'.pastel(:green)} Filter for specific files")
|
8
|
+
puts indent('Ex: --filter=gitaly,production'.pastel(:cyan), 4)
|
9
|
+
puts indent('Ex: --filter!=api'.pastel(:cyan), 4)
|
10
|
+
br
|
11
|
+
puts indent("#{'--top'.pastel(:green)} switch to `fast-stats top [filename]`")
|
12
|
+
puts indent("#{'--errors'.pastel(:green)} switch to `fast-stats errors [filename]`")
|
13
|
+
br
|
14
|
+
puts indent("#{'--all'.pastel(:green)} to attempt to faststats everything")
|
15
|
+
br
|
16
|
+
puts 'Combine all the args: `faststats --filter=sidekiq --top --errors`'
|
17
|
+
end
|
18
|
+
|
19
|
+
cmds = []
|
20
|
+
cmds.push 'top' if flags.top
|
21
|
+
cmds.push 'errors' if flags.errors
|
22
|
+
cmds.push nil if cmds.empty? # Assume Default
|
23
|
+
|
24
|
+
filters = args_select(:filter).flat_map { |x| x.value.split(',') }
|
25
|
+
|
26
|
+
if filters.empty?
|
27
|
+
# Add Defaults
|
28
|
+
filters = [
|
29
|
+
'gitaly/current',
|
30
|
+
'gitlab-rails/api_json.log',
|
31
|
+
'gitlab-rails/production_json.log',
|
32
|
+
'sidekiq/current'
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
filters = ['*'] if flags.all
|
37
|
+
|
38
|
+
filters.each do |filter|
|
39
|
+
cmds.each do |cmd|
|
40
|
+
faststats filter, cmd
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
quiet!
|
2
|
+
archive_header
|
3
|
+
header 'OS'
|
4
|
+
|
5
|
+
cat 'hostname' do |data|
|
6
|
+
indent "#{'Hostname:'.pastel(:cyan)} #{data.join}"
|
7
|
+
end
|
8
|
+
|
9
|
+
info 'etc/os-release' do |data|
|
10
|
+
ident = "[#{data.ID}] ".pastel(:bright_black)
|
11
|
+
pretty_name = data.PRETTY_NAME
|
12
|
+
" #{'Distro'.pastel(:cyan)} #{ident} #{pretty_name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
cat 'uname' do |data|
|
16
|
+
value, build = data.first.split[2].split('-')
|
17
|
+
build = "(#{build})".pastel(:bright_black)
|
18
|
+
" #{'Kernel'.pastel(:cyan)} #{value} #{build}"
|
19
|
+
end
|
20
|
+
|
21
|
+
cat 'uptime' do |data|
|
22
|
+
init = data.join.split(', load average').first.strip.split('up ', 2).last
|
23
|
+
" #{'Uptime'.pastel(:cyan)} #{init}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Load Average
|
27
|
+
info 'lscpu' do |data|
|
28
|
+
uptime = archive.thing? 'uptime'
|
29
|
+
return unless uptime
|
30
|
+
|
31
|
+
cpu_count = data['CPU(s)'].to_i
|
32
|
+
intervals = uptime.data.first.split('load average: ', 2).last.split(', ').map(&:to_f)
|
33
|
+
|
34
|
+
intervals_text = intervals.map do |interval|
|
35
|
+
value = percent(interval, cpu_count)
|
36
|
+
color = value > 100 ? :red : :green
|
37
|
+
[
|
38
|
+
interval,
|
39
|
+
' (',
|
40
|
+
"#{value}%".pastel(color),
|
41
|
+
')'
|
42
|
+
].join
|
43
|
+
end
|
44
|
+
|
45
|
+
" #{'LoadAvg'.pastel(:cyan)} #{"[CPU #{cpu_count}] ".pastel(:bright_white)} #{intervals_text.join(', ')}"
|
46
|
+
end
|
47
|
+
|
48
|
+
br
|
49
|
+
header 'Memory'
|
50
|
+
|
51
|
+
info('meminfo') do |data|
|
52
|
+
total = human_size_to_number(data['MemTotal'])
|
53
|
+
free = human_size_to_number(data['MemFree'])
|
54
|
+
used = percent((total - free), total)
|
55
|
+
|
56
|
+
[
|
57
|
+
' ',
|
58
|
+
ljust('Usage', 13, :yellow),
|
59
|
+
'['.pastel(:bright_black),
|
60
|
+
'='.pastel(:green) * (used / 2),
|
61
|
+
' ' * (50 - (used / 2)),
|
62
|
+
']'.pastel(:bright_black),
|
63
|
+
" #{100 - percent(free, total)}%".pastel(:green) # Inverse
|
64
|
+
].join
|
65
|
+
end
|
66
|
+
|
67
|
+
info('free_m', false) do |data|
|
68
|
+
free = data.first
|
69
|
+
|
70
|
+
unless free.total.blank?
|
71
|
+
size = number_to_human_size(free.total.to_i * (1024**2))
|
72
|
+
puts " #{ljust('Total', 12, :cyan)} #{size}"
|
73
|
+
end
|
74
|
+
|
75
|
+
unless free.used.blank?
|
76
|
+
size = number_to_human_size(free.used.to_i * (1024**2))
|
77
|
+
|
78
|
+
puts " #{ljust('Used', 12, :yellow)} #{size}"
|
79
|
+
end
|
80
|
+
|
81
|
+
unless free.free.blank?
|
82
|
+
size = number_to_human_size(free.free.to_i * (1024**2))
|
83
|
+
puts " #{ljust('Free', 12, :blue)} #{size}"
|
84
|
+
end
|
85
|
+
|
86
|
+
unless free.available.blank?
|
87
|
+
size = number_to_human_size(free.available.to_i * (1024**2))
|
88
|
+
puts " #{ljust('Available', 12, :green)} #{size}"
|
89
|
+
end
|
90
|
+
|
91
|
+
br
|
92
|
+
data.map { |x| GreenHat::Memory.memory_row x }.each do |row|
|
93
|
+
puts indent(row)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
br
|
98
|
+
header 'GitLab'
|
99
|
+
info 'gitlab/version-manifest.json' do |data|
|
100
|
+
indent("#{'Version'.pastel(:cyan)}: #{data.build_version}")
|
101
|
+
end
|
102
|
+
|
103
|
+
info 'gitlab_status' do
|
104
|
+
indent(GreenHat::GitLab.services(archive, 3), 3)
|
105
|
+
end
|
106
|
+
|
107
|
+
br
|
108
|
+
puts indent('Errors'.pastel(:cyan))
|
109
|
+
|
110
|
+
query 'gitlab-rails/production_json.log --status=500' do |data|
|
111
|
+
color = data.count.zero? ? :green : :red
|
112
|
+
indent("#{ljust('Production:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
113
|
+
end
|
114
|
+
|
115
|
+
query 'gitlab-rails/application_json.log --message!="Cannot obtain an exclusive lease" --severity=error' do |data|
|
116
|
+
color = data.count.zero? ? :green : :red
|
117
|
+
indent("#{ljust('Application:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
118
|
+
end
|
119
|
+
|
120
|
+
query 'sidekiq/current --severity=error' do |data|
|
121
|
+
color = data.count.zero? ? :green : :red
|
122
|
+
indent("#{ljust('Sidekiq:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
123
|
+
end
|
124
|
+
|
125
|
+
query 'gitlab-rails/api_json.log --status=500' do |data|
|
126
|
+
color = data.count.zero? ? :green : :red
|
127
|
+
indent("#{ljust('API:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
128
|
+
end
|
129
|
+
|
130
|
+
query 'gitaly/current --level=error' do |data|
|
131
|
+
color = data.count.zero? ? :green : :red
|
132
|
+
indent("#{ljust('Gitaly:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
133
|
+
end
|
134
|
+
|
135
|
+
query 'gitlab-workhorse/current --level=error' do |data|
|
136
|
+
color = data.count.zero? ? :green : :red
|
137
|
+
indent("#{ljust('Workhorse:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
138
|
+
end
|
139
|
+
|
140
|
+
query 'gitlab-rails/exceptions_json.log' do |data|
|
141
|
+
color = data.count.zero? ? :green : :red
|
142
|
+
indent("#{ljust('Exceptions:', 14, :magenta)} #{data.count.to_s.pastel(color)}", 4)
|
143
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# GreenHat Namespace
|
2
|
+
module GreenHat
|
3
|
+
# Reports NameSpace
|
4
|
+
module Reports
|
5
|
+
# This guy actually runs the reports
|
6
|
+
class Runner
|
7
|
+
include ActionView::Helpers::DateHelper
|
8
|
+
include ActionView::Helpers::NumberHelper
|
9
|
+
|
10
|
+
include InternalMethods
|
11
|
+
include Shared
|
12
|
+
attr_accessor :store, :archive, :flags, :args, :output
|
13
|
+
|
14
|
+
# Make Pry Easier
|
15
|
+
def inspect
|
16
|
+
"#<Runner archive: '#{archive}'>"
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(archive:, store:, flags:, args:)
|
20
|
+
self.store = store
|
21
|
+
self.archive = archive
|
22
|
+
self.flags = flags
|
23
|
+
self.args = args
|
24
|
+
self.output = []
|
25
|
+
|
26
|
+
# Don't render paper new lines
|
27
|
+
# flags[:skip_new_line] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Main Entrypoint for Triggering Reports Run
|
31
|
+
def run!
|
32
|
+
if flags.help
|
33
|
+
# Check for Help Flag
|
34
|
+
help_flag = store.find { |x| x.first == :help }
|
35
|
+
help_flag ? run_entry(help_flag) : puts('No Help :(')
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
|
39
|
+
store.each do |entry|
|
40
|
+
next if entry.first == :help # Skip if no flags
|
41
|
+
|
42
|
+
run_entry(entry)
|
43
|
+
end
|
44
|
+
|
45
|
+
puts
|
46
|
+
rescue StandardError => e
|
47
|
+
puts e.message
|
48
|
+
puts e.backtrace
|
49
|
+
end
|
50
|
+
|
51
|
+
# Helper to evaluate Entry
|
52
|
+
def run_entry(entry)
|
53
|
+
method = entry[0]
|
54
|
+
send(method, *entry[1..])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# GreenHat Namespace
|
2
|
+
module GreenHat
|
3
|
+
# Reports Parent Class
|
4
|
+
module Reports
|
5
|
+
# Method Helper Module
|
6
|
+
module Shared
|
7
|
+
# Indentation Helper
|
8
|
+
def indent(text, indent_value = 2)
|
9
|
+
if indent_value.zero?
|
10
|
+
text
|
11
|
+
else
|
12
|
+
"#{' ' * indent_value}#{text}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def percent(value, total)
|
17
|
+
((value / total.to_f) * 100).round
|
18
|
+
end
|
19
|
+
|
20
|
+
# Justify Text Helper / With Color!
|
21
|
+
def ljust(text, value = 14, color = nil)
|
22
|
+
color ? text.ljust(value).pastel(color) : text.ljust(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Number Helper
|
26
|
+
def human_size_to_number(value)
|
27
|
+
GreenHat::ShellHelper.human_size_to_number value
|
28
|
+
end
|
29
|
+
|
30
|
+
# Helper to filter arg selection
|
31
|
+
def args_select(field)
|
32
|
+
args.select { |x| x.field == field.to_sym }
|
33
|
+
end
|
34
|
+
# -=-=-=-=-=-
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GreenHat
|
2
|
+
module ShellHelper
|
3
|
+
# Log Helpers
|
4
|
+
module Reports
|
5
|
+
# Make Running more consistent
|
6
|
+
def self.run(file:, args:, flags:)
|
7
|
+
report = GreenHat::Reports::Builder.new(file: file, args: args, flags: flags)
|
8
|
+
output = Archive.all.map do |archive|
|
9
|
+
runner = GreenHat::Reports::Runner.new(
|
10
|
+
archive: archive,
|
11
|
+
store: report.store.clone,
|
12
|
+
flags: flags,
|
13
|
+
args: args
|
14
|
+
)
|
15
|
+
|
16
|
+
runner.run!
|
17
|
+
|
18
|
+
runner
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check for Pagination
|
22
|
+
flags[:page] = ENV['GREENHAT_PAGE'] == 'true' if ENV['GREENHAT_PAGE']
|
23
|
+
|
24
|
+
ShellHelper.show(output.flat_map(&:output), flags)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Collect everything from Built-in and local reports
|
28
|
+
def self.list
|
29
|
+
path = "#{File.dirname(__FILE__)}/reports"
|
30
|
+
Dir["#{path}/*.rb"] + Dir["#{GreenHat::Settings.reports_dir}/*.rb"]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'greenhat'
|
2
|
+
require 'greenhat/reports/internal_methods'
|
3
|
+
require 'greenhat/reports/helpers'
|
4
|
+
require 'greenhat/reports/runner'
|
5
|
+
|
6
|
+
GreenHat::Cli.quiet!
|
7
|
+
|
8
|
+
# GreenHat Namespace
|
9
|
+
module GreenHat
|
10
|
+
# Reports Parent Class
|
11
|
+
module Reports
|
12
|
+
# Method Storing
|
13
|
+
def self.store
|
14
|
+
@store ||= []
|
15
|
+
|
16
|
+
@store
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.output
|
20
|
+
@output ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adding Methods
|
24
|
+
def self.add(*params)
|
25
|
+
store.push params
|
26
|
+
end
|
27
|
+
|
28
|
+
# Main Entrypoint for Triggering Reports Run
|
29
|
+
def self.run!
|
30
|
+
_list, flags, args = Args.parse(ARGV)
|
31
|
+
|
32
|
+
output = Archive.all.map do |archive|
|
33
|
+
runner = GreenHat::Reports::Runner.new(
|
34
|
+
archive: archive,
|
35
|
+
store: store.clone,
|
36
|
+
flags: flags,
|
37
|
+
args: args
|
38
|
+
)
|
39
|
+
|
40
|
+
runner.run!
|
41
|
+
|
42
|
+
break if flags.help # Only Run Once
|
43
|
+
|
44
|
+
runner
|
45
|
+
end
|
46
|
+
|
47
|
+
# Check for Pagination
|
48
|
+
flags[:page] = ENV['GREENHAT_PAGE'] == 'true' if ENV['GREENHAT_PAGE']
|
49
|
+
|
50
|
+
ShellHelper.show(output.flat_map(&:output), flags)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.archive_run(archive)
|
54
|
+
store.each do |entry|
|
55
|
+
method = entry[0]
|
56
|
+
# Skip anything for Shim'd Puts
|
57
|
+
if method == :puts
|
58
|
+
send(method, *entry[1..])
|
59
|
+
else
|
60
|
+
send(method, archive, *entry[1..])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
rescue StandardError => e
|
64
|
+
puts e.message
|
65
|
+
puts e.backtrace
|
66
|
+
end
|
67
|
+
# ==
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
at_exit do
|
72
|
+
Dir.mktmpdir('greenhat-sauce') do |tmp|
|
73
|
+
$TMP = tmp
|
74
|
+
$STDOUT_CLONE = $stdout.clone
|
75
|
+
ENV['GREENHAT_REPORT'] = 'true' # Flag to allow skipping of different entypoints
|
76
|
+
GreenHat::Entrypoint.start(ARGV, false, false)
|
77
|
+
GreenHat::Reports.run!
|
78
|
+
end
|
79
|
+
end
|
data/lib/greenhat/settings.rb
CHANGED
@@ -83,6 +83,7 @@ module GreenHat
|
|
83
83
|
|
84
84
|
def self.start
|
85
85
|
Dir.mkdir dir unless Dir.exist? dir
|
86
|
+
Dir.mkdir reports_dir unless Dir.exist? reports_dir
|
86
87
|
|
87
88
|
# Load User Settings
|
88
89
|
settings_load
|
@@ -92,7 +93,11 @@ module GreenHat
|
|
92
93
|
end
|
93
94
|
|
94
95
|
def self.dir
|
95
|
-
"#{
|
96
|
+
"#{Dir.home}/.greenhat"
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.reports_dir
|
100
|
+
"#{dir}/reports"
|
96
101
|
end
|
97
102
|
|
98
103
|
# ----------------------------------
|
data/lib/greenhat/shell/args.rb
CHANGED
@@ -70,11 +70,18 @@ module GreenHat
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
# Arguments that Accept multiple options / Comma Delimted
|
74
|
+
def self.arg_special_split
|
75
|
+
%i[
|
76
|
+
slice except uniq pluck sort archive stats exists transform
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
73
80
|
# Flags Anything that isn't sent as a key/filter
|
74
81
|
def self.arg_to_flag_list
|
75
82
|
%i[
|
76
|
-
archive end except exists json limit pluck reverse round slice sort start
|
77
|
-
stats truncate uniq page time_zone table_style
|
83
|
+
archive end except exists json limit pluck reverse round slice sort start total
|
84
|
+
stats truncate uniq page time_zone table_style percentile interval percentile transform
|
78
85
|
]
|
79
86
|
end
|
80
87
|
|
@@ -136,13 +143,6 @@ module GreenHat
|
|
136
143
|
end
|
137
144
|
end
|
138
145
|
|
139
|
-
# Arguments that Accept multiple options / Comma Delimted
|
140
|
-
def self.arg_special_split
|
141
|
-
%i[
|
142
|
-
slice except uniq pluck sort archive stats exists
|
143
|
-
]
|
144
|
-
end
|
145
|
-
|
146
146
|
# Arg Defaults
|
147
147
|
def self.flag_arg_defaults(field)
|
148
148
|
case field
|
@@ -3,7 +3,7 @@ module GreenHat
|
|
3
3
|
# Helper to colorize and make outtput easier to read
|
4
4
|
module StringColor
|
5
5
|
def self.do(key, entry)
|
6
|
-
LogBot.debug('Unknown Format', entry.class) if ENV
|
6
|
+
LogBot.debug('Unknown Format', entry.class) if ENV.fetch('DEBUG', nil) && !entry.instance_of?(String)
|
7
7
|
|
8
8
|
# Other Helpful colorizers
|
9
9
|
if pastel?(key)
|