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,52 @@
1
+ module GreenHat
2
+ # Info Formatter
3
+ module Spinner
4
+ def spin_start(title)
5
+ # Ignore when Quiet is Set
6
+ return true if Cli.quiet
7
+
8
+ @spin_time = Time.now
9
+ @spinner = TTY::Spinner.new(
10
+ "#{time.colorize(:light_black)} - [:spinner] :title", hide_cursor: true, success_mark: '✔'.colorize(:green)
11
+ )
12
+ @spinner.update(title: title)
13
+
14
+ # Don't Auto spin when debug output is happening
15
+ @spinner.auto_spin unless ENV['DEBUG']
16
+ end
17
+
18
+ def spin_done
19
+ # Ignore when Quiet is Set
20
+ return true if Cli.quiet
21
+
22
+ title = @spinner.tokens[:title]
23
+ spin_end = humanize(@spin_time)
24
+
25
+ title_update = if spin_end.blank?
26
+ title
27
+ else
28
+ "#{title} (#{spin_end.colorize(:blue)})"
29
+ end
30
+
31
+ @spinner.update(title: title_update)
32
+ @spinner.success
33
+ end
34
+
35
+ def time
36
+ Time.now.strftime('%I:%M:%S').colorize(:light_black)
37
+ end
38
+
39
+ # Replace TimeDifference with https://stackoverflow.com/a/4136485/1678507
40
+ def humanize(time)
41
+ miliseconds = (Time.now - time) * 1000
42
+
43
+ [[1000, :ms], [60, :s], [60, :m], [24, :h]].map do |count, name|
44
+ next unless miliseconds.positive?
45
+
46
+ miliseconds, n = miliseconds.divmod(count)
47
+
48
+ "#{n.to_i}#{name}" unless n.to_i.zero?
49
+ end.compact.reverse.join(' ')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,102 @@
1
+ # TODO: Deprecate, was used specifically for Elk
2
+ # rubocop:disable /AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/
3
+ module GreenHat
4
+ # Log Identifier
5
+ module SuperLog
6
+ def self.log?(kind)
7
+ [
8
+ 'gitaly/current',
9
+ 'gitaly/gitaly_ruby_json.log',
10
+ 'gitlab-rails/api_json.log',
11
+ 'gitlab-rails/application_json.log',
12
+ 'gitlab-rails/audit_json.log',
13
+ 'gitlab-rails/graphql_json.log',
14
+ 'gitlab-rails/integrations_json.log',
15
+ 'gitlab-rails/production_json.log',
16
+ 'gitlab-rails/sidekiq_client.log',
17
+ 'gitlab-shell/gitlab-shell.log',
18
+ 'gitlab-workhorse/current',
19
+ 'puma/puma_stdout.log',
20
+ 'sidekiq/current',
21
+ 'gitlab-rails/importer.log',
22
+ 'gitlabsos.log',
23
+ 'nginx/gitlab_access.log',
24
+ 'patroni/current'
25
+ ].any? { |x| x.include? kind.to_s }
26
+
27
+ true
28
+ end
29
+
30
+ # ==========================================================================
31
+ # File Pattern Matching
32
+ # ==========================================================================
33
+ def self.api_json_format?(path)
34
+ ['rails_api_json_log'].any? { |x| path.include? x }
35
+ end
36
+
37
+ def self.unicorn_stderr_format?(path)
38
+ %w[
39
+ unicorn_stderr
40
+ ].any? { |x| path.include? x }
41
+ end
42
+
43
+ def self.reconfigure_format?(path)
44
+ %w[
45
+ reconfigure
46
+ ].any? { |x| path.include? x }
47
+ end
48
+
49
+ def self.shellwords?(path)
50
+ %w[
51
+ gitlab_pages_current
52
+ alertmanager_current
53
+ registry_current
54
+ prometheus_current
55
+
56
+ ].any? { |x| path.include? x }
57
+ end
58
+
59
+ def self.time_space?(path)
60
+ %w[
61
+ postgresql_current
62
+ redis_current
63
+ unicorn_current
64
+ gitlab_monitor_current
65
+ sidekiq_exporter_log
66
+ ].any? { |x| path.include? x }
67
+ end
68
+
69
+ def self.json_format?(path)
70
+ %w[
71
+ production_json_log
72
+ gitaly_current
73
+ geo_log
74
+ sidekiq_current
75
+ sidekiq_log
76
+ gitlab_shell_gitlab_shell_log
77
+ gitlab_rails_audit_json_log
78
+ gitlab_rails_application_json_log
79
+ ].any? { |x| path.include? x }
80
+ end
81
+
82
+ def self.dmesg_format?(path)
83
+ %w[
84
+ dmesg
85
+ ].any? { |x| path.include? x }
86
+ end
87
+ # ==========================================================================
88
+
89
+ # Identify Formatter
90
+ def self.type?(path)
91
+ return :api_json_format if api_json_format?(path)
92
+ return :unicorn_stderr_format if unicorn_stderr_format?(path)
93
+ return :reconfigure_format if reconfigure_format?(path)
94
+ return :shellwords if shellwords?(path)
95
+ return :time_space if time_space?(path)
96
+ return :json_format if json_format?(path)
97
+ return :dmesg_format if dmesg_format?(path)
98
+
99
+ nil
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,29 @@
1
+ module TTY
2
+ class Reader
3
+ # Shim Helper
4
+ class Line
5
+ def move_word_left
6
+ loop do
7
+ # Don't go past beginning
8
+ break if @cursor.zero?
9
+
10
+ left 1
11
+
12
+ break if self[@cursor].blank?
13
+ end
14
+ end
15
+
16
+ def move_word_right
17
+ loop do
18
+ right 1
19
+ break if self[@cursor].blank?
20
+ end
21
+ end
22
+
23
+ # No Tabs
24
+ def insert(chars)
25
+ self[@cursor] = chars unless ["\t", "\e[Z"].include?(chars)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,326 @@
1
+ # https://github.com/piotrmurach/tty-reader/commit/cc38eadf888ac179a77d72c21ebda987cfea3aca
2
+
3
+ # Disabling Since this is a Shim
4
+ # rubocop:disable all
5
+
6
+
7
+ module TTY
8
+ class Reader
9
+ class Line
10
+ # ANSI_MATCHER = /(\[)?\033(\[)?[;?\d]*[\dA-Za-z](\])?/
11
+
12
+ # The word break characters list used by shell
13
+ DEFAULT_WORD_BREAK_CHARACTERS = " \t\n\"\\'`@$><=|&{("
14
+
15
+ # Strip ANSI characters from the text
16
+ #
17
+ # @param [String] text
18
+ #
19
+ # @return [String]
20
+ #
21
+ # @api public
22
+ def self.sanitize(text)
23
+ text.dup.gsub(ANSI_MATCHER, '')
24
+ end
25
+
26
+ # The editable text
27
+ # @api public
28
+ attr_accessor :text
29
+
30
+ # The current cursor position witin the text
31
+ # @api public
32
+ attr_reader :cursor
33
+
34
+ # The line mode
35
+ # @api public
36
+ attr_reader :mode
37
+
38
+ # The prompt displayed before input
39
+ # @api public
40
+ attr_reader :prompt
41
+
42
+ # The word separator pattern for splitting the text
43
+ #
44
+ # @return [Regexp]
45
+ #
46
+ # @api public
47
+ attr_reader :separator
48
+
49
+ # Create a Line instance
50
+ #
51
+ # @api private
52
+ def initialize(text = '', prompt: '', separator: nil)
53
+ @text = text.dup
54
+ @prompt = prompt.dup
55
+ break_chars = DEFAULT_WORD_BREAK_CHARACTERS.chars
56
+ @separator = separator || Regexp.union(break_chars)
57
+ @cursor = [0, @text.length].max
58
+ @mode = :edit
59
+
60
+ yield self if block_given?
61
+ end
62
+
63
+ # Check if line is in edit mode
64
+ #
65
+ # @return [Boolean]
66
+ #
67
+ # @public
68
+ def editing?
69
+ @mode == :edit
70
+ end
71
+
72
+ # Enable edit mode
73
+ #
74
+ # @return [Boolean]
75
+ #
76
+ # @public
77
+ def edit_mode
78
+ @mode = :edit
79
+ end
80
+
81
+ # Check if line is in replace mode
82
+ #
83
+ # @return [Boolean]
84
+ #
85
+ # @public
86
+ def replacing?
87
+ @mode == :replace
88
+ end
89
+
90
+ # Enable replace mode
91
+ #
92
+ # @return [Boolean]
93
+ #
94
+ # @public
95
+ def replace_mode
96
+ @mode = :replace
97
+ end
98
+
99
+ # Check if cursor reached beginning of the line
100
+ #
101
+ # @return [Boolean]
102
+ #
103
+ # @api public
104
+ def start?
105
+ @cursor.zero?
106
+ end
107
+
108
+ # Check if cursor reached end of the line
109
+ #
110
+ # @return [Boolean]
111
+ #
112
+ # @api public
113
+ def end?
114
+ @cursor == @text.length
115
+ end
116
+
117
+ # Move line position to the left by n chars
118
+ #
119
+ # @api public
120
+ def left(n = 1)
121
+ @cursor = [0, @cursor - n].max
122
+ end
123
+
124
+ # Move line position to the right by n chars
125
+ #
126
+ # @api public
127
+ def right(n = 1)
128
+ @cursor = [@text.length, @cursor + n].min
129
+ end
130
+
131
+ # Move cursor to beginning position
132
+ #
133
+ # @api public
134
+ def move_to_start
135
+ @cursor = 0
136
+ end
137
+
138
+ # Move cursor to end position
139
+ #
140
+ # @api public
141
+ def move_to_end
142
+ @cursor = @text.length # put cursor outside of text
143
+ end
144
+
145
+ # Insert characters inside a line. When the lines exceeds
146
+ # maximum length, an extra space is added to accomodate index.
147
+ #
148
+ # @param [Integer] i
149
+ # the index to insert at
150
+ #
151
+ # @param [String] chars
152
+ # the characters to insert
153
+ #
154
+ # @example
155
+ # text = "aaa"
156
+ # line[5]= "b"
157
+ # => "aaa b"
158
+ #
159
+ # @api public
160
+ def []=(i, chars)
161
+ edit_mode
162
+
163
+ if i.is_a?(Range)
164
+ @text[i] = chars
165
+ @cursor += chars.length
166
+ return
167
+ end
168
+
169
+ if i <= 0
170
+ before_text = ''
171
+ after_text = @text.dup
172
+ elsif i > @text.length - 1 # insert outside of line input
173
+ before_text = @text.dup
174
+ after_text = "\s" * (i - @text.length)
175
+ @cursor += after_text.length
176
+ else
177
+ before_text = @text[0..i - 1].dup
178
+ after_text = @text[i..-1].dup
179
+ end
180
+
181
+ @text = if i > @text.length - 1
182
+ before_text + after_text + chars
183
+ else
184
+ before_text + chars + after_text
185
+ end
186
+
187
+ @cursor = i + chars.length
188
+ end
189
+
190
+ # Read character
191
+ #
192
+ # @api public
193
+ def [](i)
194
+ @text[i]
195
+ end
196
+
197
+ # Find a word under the cursor based on the word separator
198
+ #
199
+ # @param [Boolean] before
200
+ # whether to start searching before or after a break character
201
+ #
202
+ # @return [String]
203
+ #
204
+ # @api public
205
+ def word(before: true)
206
+ @text[range(before: before)]
207
+ end
208
+
209
+ # Find a range of characters under the cursor based on the word separator
210
+ #
211
+ # @param [Integer] from
212
+ # the start index
213
+ #
214
+ # @param [Symbol] before
215
+ # whether to start search before or after break character
216
+ #
217
+ # @return [Range]
218
+ #
219
+ # @api public
220
+ def range(from: @cursor, before: true)
221
+ # move back or forward by one character when at a word boundary
222
+ if word_boundary?
223
+ from = before ? from - 1 : from + 1
224
+ end
225
+
226
+ # find start position
227
+ start_pos = @text.rindex(separator, from) || 0
228
+ start_pos += 1 unless start_pos.zero?
229
+
230
+ # find end position
231
+ end_pos = @text.index(separator, start_pos) || text_size
232
+ end_pos -= 1 unless @text.empty?
233
+
234
+ start_pos..end_pos
235
+ end
236
+
237
+ # Check if cursor is at a word boundary
238
+ #
239
+ # @return [Boolean]
240
+ #
241
+ # @api private
242
+ def word_boundary?
243
+ @text[@cursor] =~ separator
244
+ end
245
+
246
+ # Replace current line with new text
247
+ #
248
+ # @param [String] text
249
+ #
250
+ # @api public
251
+ def replace(text)
252
+ @text = text
253
+ @cursor = @text.length # put cursor outside of text
254
+ replace_mode
255
+ end
256
+
257
+ # Insert char(s) at cursor position
258
+ #
259
+ # @api public
260
+ def insert(chars)
261
+ self[@cursor] = chars
262
+ end
263
+
264
+ # Add char and move cursor
265
+ #
266
+ # @api public
267
+ def <<(char)
268
+ @text << char
269
+ @cursor += 1
270
+ end
271
+
272
+ # Remove char from the line at current position
273
+ #
274
+ # @api public
275
+ def delete(n = 1)
276
+ @text.slice!(@cursor, n)
277
+ end
278
+
279
+ # Remove char from the line in front of the cursor
280
+ #
281
+ # @param [Integer] n
282
+ # the number of chars to remove
283
+ #
284
+ # @api public
285
+ def remove(n = 1)
286
+ left(n)
287
+ @text.slice!(@cursor, n)
288
+ end
289
+
290
+ # Full line with prompt as string
291
+ #
292
+ # @api public
293
+ def to_s
294
+ "#{@prompt}#{@text}"
295
+ end
296
+ alias inspect to_s
297
+
298
+ # Prompt size
299
+ #
300
+ # @api public
301
+ def prompt_size
302
+ p = self.class.sanitize(@prompt).split(/\r?\n/)
303
+ # return the length of each line + screen width for every line past the first
304
+ # which accounts for multi-line prompts
305
+ p.join.length + ((p.length - 1) * TTY::Screen.width)
306
+ end
307
+
308
+ # Text size
309
+ #
310
+ # @api public
311
+ def text_size
312
+ self.class.sanitize(@text).size
313
+ end
314
+
315
+ # Full line size with prompt
316
+ #
317
+ # @api public
318
+ def size
319
+ prompt_size + text_size
320
+ end
321
+ alias length size
322
+ end
323
+ end
324
+ end
325
+
326
+ # rubocop:enable all