greenhat 0.1.4

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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +64 -0
  3. data/bin/greenhat +12 -0
  4. data/lib/greenhat.rb +80 -0
  5. data/lib/greenhat/accessors/disk.rb +27 -0
  6. data/lib/greenhat/accessors/logs/production.rb +41 -0
  7. data/lib/greenhat/accessors/logs/sidekiq.rb +41 -0
  8. data/lib/greenhat/accessors/memory.rb +46 -0
  9. data/lib/greenhat/accessors/network.rb +8 -0
  10. data/lib/greenhat/accessors/process.rb +8 -0
  11. data/lib/greenhat/archive.rb +108 -0
  12. data/lib/greenhat/cli.rb +448 -0
  13. data/lib/greenhat/host.rb +182 -0
  14. data/lib/greenhat/logbot.rb +86 -0
  15. data/lib/greenhat/pry_helpers.rb +51 -0
  16. data/lib/greenhat/settings.rb +51 -0
  17. data/lib/greenhat/shell.rb +92 -0
  18. data/lib/greenhat/shell/cat.rb +125 -0
  19. data/lib/greenhat/shell/disk.rb +68 -0
  20. data/lib/greenhat/shell/faststats.rb +195 -0
  21. data/lib/greenhat/shell/gitlab.rb +45 -0
  22. data/lib/greenhat/shell/help.rb +15 -0
  23. data/lib/greenhat/shell/helper.rb +514 -0
  24. data/lib/greenhat/shell/log.rb +344 -0
  25. data/lib/greenhat/shell/memory.rb +31 -0
  26. data/lib/greenhat/shell/network.rb +12 -0
  27. data/lib/greenhat/shell/process.rb +12 -0
  28. data/lib/greenhat/shell/report.rb +319 -0
  29. data/lib/greenhat/thing.rb +121 -0
  30. data/lib/greenhat/thing/file_types.rb +705 -0
  31. data/lib/greenhat/thing/formatters/api_json.rb +34 -0
  32. data/lib/greenhat/thing/formatters/bracket_log.rb +44 -0
  33. data/lib/greenhat/thing/formatters/clean_raw.rb +23 -0
  34. data/lib/greenhat/thing/formatters/colon_split_strip.rb +12 -0
  35. data/lib/greenhat/thing/formatters/dotenv.rb +10 -0
  36. data/lib/greenhat/thing/formatters/format.rb +12 -0
  37. data/lib/greenhat/thing/formatters/free_m.rb +29 -0
  38. data/lib/greenhat/thing/formatters/gitlab_ctl_tail.rb +51 -0
  39. data/lib/greenhat/thing/formatters/gitlab_status.rb +26 -0
  40. data/lib/greenhat/thing/formatters/json.rb +63 -0
  41. data/lib/greenhat/thing/formatters/json_shellwords.rb +44 -0
  42. data/lib/greenhat/thing/formatters/multiline_json.rb +10 -0
  43. data/lib/greenhat/thing/formatters/raw.rb +18 -0
  44. data/lib/greenhat/thing/formatters/shellwords.rb +23 -0
  45. data/lib/greenhat/thing/formatters/table.rb +26 -0
  46. data/lib/greenhat/thing/formatters/time_json.rb +21 -0
  47. data/lib/greenhat/thing/formatters/time_shellwords.rb +28 -0
  48. data/lib/greenhat/thing/formatters/time_space.rb +36 -0
  49. data/lib/greenhat/thing/helpers.rb +71 -0
  50. data/lib/greenhat/thing/history.rb +51 -0
  51. data/lib/greenhat/thing/info_format.rb +193 -0
  52. data/lib/greenhat/thing/kind.rb +97 -0
  53. data/lib/greenhat/thing/spinner.rb +52 -0
  54. data/lib/greenhat/thing/super_log.rb +102 -0
  55. data/lib/greenhat/tty/custom_line.rb +29 -0
  56. data/lib/greenhat/tty/line.rb +326 -0
  57. data/lib/greenhat/tty/reader.rb +110 -0
  58. data/lib/greenhat/version.rb +3 -0
  59. data/lib/greenhat/views/css.slim +126 -0
  60. data/lib/greenhat/views/disk_free.slim +18 -0
  61. data/lib/greenhat/views/index.slim +51 -0
  62. data/lib/greenhat/views/info.slim +39 -0
  63. data/lib/greenhat/views/manifest.slim +22 -0
  64. data/lib/greenhat/views/memory.slim +18 -0
  65. data/lib/greenhat/views/netstat.slim +20 -0
  66. data/lib/greenhat/views/process.slim +21 -0
  67. data/lib/greenhat/views/systemctl.slim +40 -0
  68. data/lib/greenhat/views/ulimit.slim +15 -0
  69. data/lib/greenhat/web.rb +46 -0
  70. metadata +476 -0
@@ -0,0 +1,34 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters
7
+ # ==========================================================================
8
+ # Primarily for gitlab-rails/api_json.log
9
+ def format_api_json
10
+ self.result = raw.map do |row|
11
+ result = Oj.load row
12
+
13
+ # Parsing Time
14
+ format_json_traverse result
15
+
16
+ flatten_hash(result).sort.to_h
17
+ rescue StandardError => e
18
+ # TODO: Background Logger?
19
+ e.message
20
+ LogBot.warn('JSON Parse', e.message)
21
+ next
22
+ end
23
+
24
+ :ok
25
+ end
26
+
27
+ def flatten_hash(param, prefix = nil)
28
+ param.each_pair.reduce({}) do |a, (k, v)|
29
+ v.is_a?(Hash) ? a.merge(flatten_hash(v, "#{prefix}#{k}.")) : a.merge("#{prefix}#{k}".to_sym => v)
30
+ end
31
+ end
32
+ # ==========================================================================
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for bracket logs (dmesg, sos)
6
+ def format_bracket_log
7
+ self.result = raw.map do |row|
8
+ next if row.empty? || row == "\n"
9
+
10
+ result = {}
11
+ time, output = row.split(']', 2)
12
+ result[:time] = Time.parse time.split('[', 2).last.strip
13
+
14
+ if output.include? ': '
15
+ category, raw = output.split(': ', 2)
16
+ result[:category] = category.strip
17
+
18
+ result.merge! dmesg_split(raw) if raw.include? '='
19
+
20
+ result[:message] = raw.strip
21
+ else
22
+ result[:message] = output
23
+ end
24
+
25
+ result
26
+ rescue StandardError => e
27
+ # TODO: Background logger
28
+ LogBot.fatal('dmesg', "Unable to Parse, #{row}:#{e.message}")
29
+ end
30
+
31
+ self.result.compact!
32
+ end
33
+
34
+ def dmesg_split(raw)
35
+ Shellwords.split(raw).each_with_object({}) do |x, h|
36
+ key, value = x.split('=')
37
+ next if value.nil?
38
+
39
+ h[key] = value.numeric? ? value.to_f : value
40
+ h[key] = 0.0 if h[key].numeric? && h[key].zero?
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Remove Comments / Empty Lines
6
+ def format_clean_raw
7
+ staging = raw.clone
8
+
9
+ # Empty
10
+ staging.reject!(&:empty?)
11
+
12
+ # Commented
13
+ staging.reject! { |x| x =~ /#.*$/ }
14
+
15
+ self.result = if staging.empty?
16
+ raw
17
+ else
18
+ staging
19
+ end
20
+ end
21
+ end
22
+ # ----------------------------------------
23
+ end
@@ -0,0 +1,12 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for single json blobs in entire file
6
+ def format_colon_split_strip
7
+ self.result = raw.map do |row|
8
+ row.split(':', 2).map(&:strip)
9
+ end.to_h
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for Dmesg
6
+ def format_dotenv
7
+ self.result = Dotenv::Parser.new(raw.join("\n")).call
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module GreenHat
2
+ # Formatter
3
+ module Formatters
4
+ def log_format
5
+ self.result = send(SuperLog.type?(path)) if log_type
6
+ end
7
+
8
+ def log_type
9
+ SuperLog.type?(path)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Get Split Memory Table
6
+ def format_free_m
7
+ # Headers to Readable Symbol
8
+ headers = raw.first.split(' ', 6).map(&:downcase).map do |x|
9
+ x.gsub(/\s+/, '_').gsub(/[^0-9A-Za-z_]/, '')
10
+ end.map(&:to_sym)
11
+
12
+ # Add Kind
13
+ headers.unshift(:kind)
14
+
15
+ final = []
16
+
17
+ # Put fields into a Hash based on Location/Key
18
+ raw[1..].map(&:split).each do |row|
19
+ result = {}
20
+ row.each_with_index do |detail, i|
21
+ result[headers[i]] = detail.split(':').first
22
+ end
23
+ final.push result
24
+ end
25
+
26
+ self.result = final
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,51 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Gitlab Tail Formatter
7
+ # ==========================================================================
8
+ def format_gitlab_tail
9
+ # Revert to raw for cats
10
+ self.kind = :raw
11
+
12
+ output = {}
13
+ current_log = nil
14
+
15
+ raw.each do |line|
16
+ next if line.blank?
17
+
18
+ if line.include? '==>'
19
+ current_log = /==> (.+?) <==/.match(line).captures.first
20
+ else
21
+ output[current_log] ||= []
22
+ output[current_log].push line
23
+ end
24
+ end
25
+
26
+ # Remove Empty Entries
27
+ output.reject { |_k, v| v.empty? }
28
+
29
+ # Root Dir
30
+ root_dir = "#{$TMP}/#{name}"
31
+ Dir.mkdir(root_dir)
32
+
33
+ # Write Files / Create Things
34
+ output.each do |k, v|
35
+ file_name = k.gsub('/var/log/gitlab/', '')
36
+
37
+ dir = "#{root_dir}/#{file_name.split('/').first}"
38
+ Dir.mkdir(dir) unless File.exist?(dir)
39
+
40
+ File.write("#{root_dir}/#{file_name}", v.join("\n"))
41
+
42
+ # Thing Setup
43
+ archive.things_create(file: "#{root_dir}/#{file_name}").setup
44
+ end
45
+
46
+ # Link
47
+ self.result = raw
48
+ end
49
+ # ==========================================================================
50
+ end
51
+ end
@@ -0,0 +1,26 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Remove Comments / Empty Lines
6
+ def format_gitlab_status
7
+ final = {}
8
+ raw.each do |row|
9
+ list = row.split('; ').map do |entry|
10
+ status, service, pid_uptime = entry.split(': ')
11
+
12
+ {
13
+ status: status,
14
+ name: service,
15
+ pid_uptime: pid_uptime
16
+ }
17
+ end
18
+
19
+ final[list.first.name] = list
20
+ end
21
+
22
+ self.result = final
23
+ end
24
+ end
25
+ # ----------------------------------------
26
+ end
@@ -0,0 +1,63 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters
7
+ # Fallback to String
8
+ # ==========================================================================
9
+ def format_json
10
+ self.result = raw.map do |row|
11
+ result = begin
12
+ Oj.load row
13
+ rescue EncodingError
14
+ { message: row }
15
+ end
16
+
17
+ # Parsing Time
18
+ format_json_traverse result
19
+
20
+ result.sort.to_h
21
+ rescue StandardError => e
22
+ # TODO: Background Logger?
23
+ e.message
24
+ LogBot.warn('JSON Parse', e.message)
25
+ next
26
+ end
27
+
28
+ :ok
29
+ end
30
+ # ==========================================================================
31
+
32
+ # Recursively Navigate
33
+ def format_json_traverse(result)
34
+ format_json_time(result)
35
+
36
+ result.each do |_key, value|
37
+ next unless value.instance_of? Hash
38
+
39
+ format_json_traverse(value)
40
+ end
41
+ end
42
+
43
+ # Check for Common Fields
44
+ def format_json_time(result)
45
+ result.time = format_time_parse(result.time) if result.key? :time
46
+ result.created_at = format_time_parse(result.created_at) if result.key? :created_at
47
+ result.enqueued_at = format_time_parse(result.enqueued_at) if result.key? :enqueued_at
48
+ rescue StandardError => e
49
+ LogBot.warn('JSON Time Parse', e.message)
50
+ true
51
+ end
52
+
53
+ # Handle Epoch Timestamps as well as string timestamps
54
+ def format_time_parse(time)
55
+ if time.numeric?
56
+ Time.at time
57
+ else
58
+ Time.parse time
59
+ end
60
+ end
61
+ # ---
62
+ end
63
+ end
@@ -0,0 +1,44 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters
7
+ # ==========================================================================
8
+ def format_json_shell
9
+ self.result = raw.map do |row|
10
+ result = begin
11
+ Oj.load row
12
+ rescue EncodingError
13
+ json_shellwords_fallback row
14
+ end
15
+
16
+ # Parsing Time
17
+ format_json_traverse result
18
+
19
+ result.sort.to_h
20
+ rescue StandardError => e
21
+ binding.pry
22
+ # TODO: Background Logger?
23
+ e.message
24
+ LogBot.warn('JSON Parse', e.message)
25
+ next
26
+ end
27
+
28
+ :ok
29
+ end
30
+
31
+ def json_shellwords_fallback(row)
32
+ result = Shellwords.split(row).each_with_object({}) do |x, h|
33
+ key, value = x.split('=')
34
+ next if value.nil?
35
+
36
+ h[key] = value.numeric? ? value.to_f : value
37
+ end
38
+ result.time = Time.parse result.time if result.key? 'time'
39
+
40
+ result
41
+ end
42
+ # ==========================================================================
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for single json blobs in entire file
6
+ def format_multiline_json
7
+ self.result = Oj.load raw.join
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters Not Handled
7
+ # ==========================================================================
8
+ def mia
9
+ # TODO: Background Logger
10
+ LogBot.warn('Log Format', "No Formatter for #{name}::#{path}")
11
+ end
12
+
13
+ def format_raw
14
+ self.result = raw
15
+ end
16
+ # ==========================================================================
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters Not Handled
7
+ # ==========================================================================
8
+ def format_shellwords
9
+ self.result = raw.map do |row|
10
+ result = Shellwords.split(row).each_with_object({}) do |x, h|
11
+ key, value = x.split('=')
12
+ next if value.nil?
13
+
14
+ h[key] = value.numeric? ? value.to_f : value
15
+ end
16
+ result.time = Time.parse result.time if result.key? 'time'
17
+
18
+ result
19
+ end
20
+ end
21
+ # ==========================================================================
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Formatters for Dmesg
6
+ def format_table
7
+ # Headers to Readable Symbol
8
+ headers = raw.first.split(' ', 6).map(&:downcase).map do |x|
9
+ x.gsub(/\s+/, '_').gsub(/[^0-9A-Za-z_]/, '')
10
+ end.map(&:to_sym)
11
+
12
+ final = []
13
+
14
+ # Put fields into a Hash based on Location/Key
15
+ raw[1..].map(&:split).each do |row|
16
+ result = {}
17
+ row.each_with_index do |detail, i|
18
+ result[headers[i]] = detail
19
+ end
20
+ final.push result
21
+ end
22
+
23
+ self.result = final
24
+ end
25
+ end
26
+ end