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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/greenhat/accessors/disk.rb +1 -1
  3. data/lib/greenhat/archive.rb +2 -0
  4. data/lib/greenhat/cli.rb +12 -2
  5. data/lib/greenhat/entrypoint.rb +36 -33
  6. data/lib/greenhat/host.rb +1 -1
  7. data/lib/greenhat/logbot.rb +1 -1
  8. data/lib/greenhat/paper/flag_helper.rb +18 -0
  9. data/lib/greenhat/paper/paper_helper.rb +118 -0
  10. data/lib/greenhat/paper.rb +34 -0
  11. data/lib/greenhat/reports/builder.rb +98 -0
  12. data/lib/greenhat/reports/helpers.rb +101 -0
  13. data/lib/greenhat/reports/internal_methods.rb +156 -0
  14. data/lib/greenhat/reports/reports/errors.rb +51 -0
  15. data/lib/greenhat/reports/reports/faststats.rb +42 -0
  16. data/lib/greenhat/reports/reports/full.rb +143 -0
  17. data/lib/greenhat/reports/runner.rb +58 -0
  18. data/lib/greenhat/reports/shared.rb +37 -0
  19. data/lib/greenhat/reports/shell_helper.rb +34 -0
  20. data/lib/greenhat/reports.rb +79 -0
  21. data/lib/greenhat/settings.rb +6 -1
  22. data/lib/greenhat/shell/args.rb +9 -9
  23. data/lib/greenhat/shell/color_string.rb +1 -1
  24. data/lib/greenhat/shell/faststats.rb +24 -5
  25. data/lib/greenhat/shell/field_helper.rb +1 -1
  26. data/lib/greenhat/shell/filter_help.rb +36 -189
  27. data/lib/greenhat/shell/log.rb +28 -16
  28. data/lib/greenhat/shell/markdown.rb +355 -352
  29. data/lib/greenhat/shell/process.rb +11 -5
  30. data/lib/greenhat/shell/query.rb +184 -28
  31. data/lib/greenhat/shell/report.rb +415 -412
  32. data/lib/greenhat/shell/reports.rb +41 -0
  33. data/lib/greenhat/shell/shell_helper.rb +172 -117
  34. data/lib/greenhat/shell.rb +13 -2
  35. data/lib/greenhat/thing/file_types.rb +38 -2
  36. data/lib/greenhat/thing/formatters/clean_raw.rb +1 -1
  37. data/lib/greenhat/thing/formatters/exporters.rb +48 -0
  38. data/lib/greenhat/thing/formatters/identify_db.rb +32 -0
  39. data/lib/greenhat/thing/formatters/runner_log.rb +70 -0
  40. data/lib/greenhat/thing/formatters/table.rb +15 -1
  41. data/lib/greenhat/thing/formatters/time_json.rb +12 -1
  42. data/lib/greenhat/thing/kind.rb +1 -1
  43. data/lib/greenhat/thing.rb +1 -0
  44. data/lib/greenhat/version.rb +1 -1
  45. data/lib/greenhat.rb +6 -8
  46. metadata +33 -4
  47. data/lib/greenhat/pry_helpers.rb +0 -51
  48. data/lib/greenhat/thing/super_log.rb +0 -1
@@ -0,0 +1,41 @@
1
+ # Reporting
2
+ require 'greenhat/reports/shared' # Methods for Shell and Builder
3
+ require 'greenhat/reports/internal_methods' # Class / Execution Only
4
+ require 'greenhat/reports/runner' # Class execution
5
+ require 'greenhat/reports/builder' # CLI Reports
6
+ require 'greenhat/reports/shell_helper'
7
+
8
+ module GreenHat
9
+ # CLI Helper
10
+ module Shell
11
+ # Logs
12
+ module Reports
13
+ # Easy Show All
14
+ def self.ls(raw = [])
15
+ filter, _flags, _args = Args.parse(raw)
16
+
17
+ list = GreenHat::ShellHelper::Reports.list
18
+ list.select! { |x| x.include? filter.first } unless filter.blank?
19
+
20
+ list.each do |x|
21
+ puts "- #{File.basename(x, '.rb').pastel(:yellow)}"
22
+ end
23
+ end
24
+
25
+ def self.default(raw = [])
26
+ list, flags, args = Args.parse(raw)
27
+
28
+ # Collect Reporst to Run
29
+ run_list = GreenHat::ShellHelper::Reports.list.select do |entry|
30
+ list.include? File.basename(entry, '.rb')
31
+ end
32
+
33
+ run_list.uniq!
34
+
35
+ run_list.each do |file|
36
+ GreenHat::ShellHelper::Reports.run(file: file, args: args, flags: flags)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,5 @@
1
1
  module GreenHat
2
2
  # Common Helpers
3
- # rubocop:disable Metrics/ModuleLength
4
3
  module ShellHelper
5
4
  # Use File Process for Output
6
5
  def self.file_output(files, flags = {})
@@ -48,114 +47,156 @@ module GreenHat
48
47
 
49
48
  # Check if content needs to paged, or if auto_height is off
50
49
  if Page.skip?(flags, data)
51
- puts data.map { |entry| entry_show(flags, entry) }.compact.join("\n")
50
+ create_ledger(data, flags).each { |entry| puts entry.render }
52
51
  return true
53
52
  end
54
53
 
55
- # Default Pager
56
- TTY::Pager.page do |pager|
57
- data.each do |entry|
58
- output = "\n#{entry_show(flags, entry)}"
59
-
60
- # output += "\n" if flags[:table_style] == 'basic'
61
-
62
- # Breaks any intentional spaces
63
- # next if output.blank?
64
-
65
- pager.write(output) # write line to the pager
54
+ # Create Jobs
55
+ # Generate List of Formatted Output
56
+ ledger = create_ledger(data, flags)
57
+
58
+ # Start Thread
59
+ # TODO: Confirm / Test or Remove
60
+ unless flags.no_paper_thread
61
+ thread = Thread.new do
62
+ pending = ledger.clone
63
+ loop do
64
+ pending = pending.reject(&:done)
65
+ break if pending.empty?
66
+
67
+ pending.first.async
68
+ end
66
69
  end
67
70
  end
68
- end
69
-
70
- # Entry Shower / Top Level
71
- def self.entry_show(flags, entry, key = nil)
72
- LogBot.debug('Entry Show', entry.class) if ENV['DEBUG']
73
- case entry
74
- when Hash then render_table(entry, flags)
75
- when Float, Integer, Array
76
- format_table_entry(flags, entry, key)
77
- # Ignore Special Formatting for Strings / Usually already formatted
78
- when String
79
- entry
80
- else
81
- LogBot.warn('Shell Show', "Unknown #{entry.class}")
82
- nil
83
- end
84
- end
85
71
 
86
- # Format Table Entries
87
- def self.format_table_entry(flags, entry, key = nil)
88
- formatted_entry = case entry
89
- # Rounding
90
- when Float, Integer || entry.numeric?
91
- flags.key?(:round) ? entry.to_f.round(flags.round).ai : entry.ai
92
-
93
- # General Inspecting
94
- when Hash then entry.ai(ruby19_syntax: true)
95
-
96
- # Arrays often contain Hashes. Dangerous Recursive?
97
- when Array
98
- entry.map { |x| format_table_entry(flags, x) }.join("\n")
99
- when Time
100
- entry.to_s.pastel(:bright_white)
101
-
102
- # Default String Formatting
103
- else
104
- StringColor.do(key, entry)
105
- end
106
-
107
- # Stats truncation handled separately
108
- if flags[:truncate] && !flags[:stats]
109
- entry_truncate(formatted_entry, flags[:truncate])
110
- else
111
- formatted_entry
112
- end
113
- rescue StandardError => e
114
- if ENV['DEBUG']
115
- LogBot.warn('Table Format Entry', message: e.message)
116
- ap e.backtrace
117
- end
118
- end
119
-
120
- # Print the Table in a Nice way
121
- def self.render_table(entry, flags)
122
- entry = entry.to_h { |k, v| [k, format_table_entry(flags, v, k)] }
123
- # Pre-format Entry
124
-
125
- table_style = flags[:table_style]&.to_sym || :unicode
126
-
127
- table = TTY::Table.new(header: entry.keys, rows: [entry], orientation: :vertical)
128
-
129
- LogBot.debug('Rendering Entries') if ENV['DEBUG']
130
- output = table.render(table_style, padding: [0, 1, 0, 1], multiline: true) do |renderer|
131
- renderer.border.style = :cyan
72
+ TTY::Pager.page do |pager|
73
+ ledger.each do |paper|
74
+ # New Line is only needed on pager.write
75
+ pager.write "#{paper.render}\n"
76
+ end
132
77
  end
133
78
 
134
- # Line breaks for basic tables
135
- output += "\n" if flags[:table_style] == 'basic'
79
+ # Terminate
80
+ thread.kill unless flags.no_paper_thread
136
81
 
137
- output
82
+ # -----------------
83
+ end
138
84
 
139
- # LogBot.debug('Finish Render Table') if ENV['DEBUG']
140
- # Fall Back to Amazing Inspect
141
- rescue StandardError => e
142
- if ENV['DEBUG']
143
- LogBot.warn('Table', message: e.message)
144
- ap e.backtrace
85
+ # Collect Class Objects for output
86
+ def self.create_ledger(data, flags)
87
+ data.map do |x|
88
+ Paper.new(data: x, flags: flags)
145
89
  end
90
+ end
146
91
 
147
- [
148
- entry.ai,
149
- ('_' * (TTY::Screen.width / 3)).pastel(:cyan),
150
- "\n"
151
- ].join("\n")
92
+ def self.puts(text = '')
93
+ $stdout.puts text
152
94
  end
153
95
 
154
- def self.render_table_entry(val, col_index, flags)
155
- return val.to_s unless col_index == 1
96
+ # Entry Shower / Top Level
97
+ # def self.entry_show(flags, entry, key = nil)
98
+ # LogBot.debug('Entry Show', entry.class) if ENV['DEBUG']
99
+ # case entry
100
+ # when Hash then render_table(entry, flags)
101
+ # when Float, Integer
102
+ # format_table_entry(flags, entry, key)
103
+ # # Ignore Special Formatting for Strings / Usually already formatted
104
+ # when String
105
+ # entry
106
+ # when Array
107
+ # render_array_table(entry, flags)
108
+ # else
109
+ # LogBot.warn('Shell Show', "Unknown #{entry.class}")
110
+ # nil
111
+ # end
112
+ # end
156
113
 
157
- format_table_entry(flags, val)
158
- end
114
+ # Format Table Entries
115
+ # def self.format_table_entry(flags, entry, key = nil)
116
+ # formatted_entry = case entry
117
+ # # Rounding
118
+ # when Float, Integer || entry.numeric?
119
+ # flags.key?(:round) ? entry.to_f.round(flags.round).ai : entry.ai
120
+
121
+ # # General Inspecting
122
+ # when Hash then entry.ai(ruby19_syntax: true)
123
+
124
+ # # Arrays often contain Hashes. Dangerous Recursive?
125
+ # when Array
126
+ # entry.map { |x| format_table_entry(flags, x) }.join("\n")
127
+ # when Time
128
+ # entry.to_s.pastel(:bright_white)
129
+
130
+ # # Default String Formatting
131
+ # else
132
+ # StringColor.do(key, entry)
133
+ # end
134
+
135
+ # # Stats truncation handled separately
136
+ # if flags[:truncate] && !flags[:stats]
137
+ # entry_truncate(formatted_entry, flags[:truncate])
138
+ # else
139
+ # formatted_entry
140
+ # end
141
+ # rescue StandardError => e
142
+ # if ENV['DEBUG']
143
+ # LogBot.warn('Table Format Entry', message: e.message)
144
+ # ap e.backtrace
145
+ # end
146
+ # end
147
+
148
+ # def self.render_array_table(entry, flags)
149
+ # table_style = flags[:table_style]&.to_sym || :unicode
150
+ # header, rows = entry
151
+ # table = TTY::Table.new(header: header, rows: rows)
152
+
153
+ # LogBot.debug('Rendering Entries') if ENV['DEBUG']
154
+ # output = table.render(table_style, padding: [0, 1, 0, 1], multiline: true) do |renderer|
155
+ # renderer.border.style = :cyan
156
+ # end
157
+
158
+ # # Line breaks for basic tables
159
+ # output += "\n" if flags[:table_style] == 'basic'
160
+
161
+ # output
162
+ # end
163
+
164
+ # # Print the Table in a Nice way
165
+ # def self.render_table(entry, flags)
166
+ # entry = entry.to_h { |k, v| [k, format_table_entry(flags, v, k)] }
167
+ # # Pre-format Entry
168
+
169
+ # table_style = flags[:table_style]&.to_sym || :unicode
170
+
171
+ # table = TTY::Table.new(header: entry.keys, rows: [entry], orientation: :vertical)
172
+
173
+ # LogBot.debug('Rendering Entries') if ENV['DEBUG']
174
+ # output = table.render(table_style, padding: [0, 1, 0, 1], multiline: true) do |renderer|
175
+ # renderer.border.style = :cyan
176
+ # end
177
+
178
+ # # Line breaks for basic tables
179
+ # output += "\n" if flags[:table_style] == 'basic'
180
+
181
+ # output
182
+ # rescue StandardError => e
183
+ # if ENV['DEBUG']
184
+ # LogBot.warn('Table', message: e.message)
185
+ # ap e.backtrace
186
+ # end
187
+
188
+ # [
189
+ # entry.ai,
190
+ # ('_' * (TTY::Screen.width / 3)).pastel(:cyan),
191
+ # "\n"
192
+ # ].join("\n")
193
+ # end
194
+
195
+ # def self.render_table_entry(val, col_index, flags)
196
+ # return val.to_s unless col_index == 1
197
+
198
+ # format_table_entry(flags, val)
199
+ # end
159
200
 
160
201
  # Internal Query Helper
161
202
  # query = 'gitlab-rails/application_json.log --message!="Cannot obtain an exclusive lease" --severity=error'
@@ -183,28 +224,42 @@ module GreenHat
183
224
 
184
225
  # Total Count Helper
185
226
  def self.total_count(results, flags)
186
- results.map do |k, v|
187
- puts k
188
- # puts "Total: #{v.count.to_s.pastel(:blue)}"
189
- # puts "Time Covered: #{calculate_duration(v).pastel(:cyan)}"
190
-
191
- output = {}
192
- output[:total] = v.count
193
- output[:duration] = Query.calculate_duration(v)
194
-
195
- # Sort / Get first and Last
196
- list = v.select(&:time).map(&:time)
197
- unless list.blank?
198
- output[:start] = list.first
199
- output[:end] = list.last
200
- end
227
+ # Support Combine Helper
228
+ # TODO I Believe this should be removed now
229
+ # total_count_hash(results, flags) if results.instance_of? Hash
201
230
 
202
- puts render_table(output, flags)
231
+ total_count_array(results, flags) if results.instance_of? Array
232
+ end
203
233
 
204
- puts
234
+ # Hash Iteration
235
+ def self.total_count_hash(results, flags)
236
+ results.flat_map do |k, values|
237
+ [k, total_count_array(values, flags)]
205
238
  end
206
239
  end
207
240
 
241
+ # List Calculation
242
+ def self.total_count_array(results, flags)
243
+ # Option to only return the count
244
+ return results.count if flags[:total] == 'simple'
245
+
246
+ output = {}
247
+ output[:total] = results.count
248
+ output[:duration] = Query.calculate_duration(results)
249
+
250
+ # Sort / Get first and Last
251
+ list = results.select(&:time).map(&:time)
252
+ unless list.blank?
253
+ output[:start] = list.first
254
+ output[:end] = list.last
255
+ end
256
+
257
+ # Hide empty results
258
+ output.reject! { |_k, v| v.blank? }
259
+
260
+ render_table(output, flags)
261
+ end
262
+
208
263
  # Table Printer Helper
209
264
  def self.fields_print(results)
210
265
  results.each do |k, v|
@@ -239,7 +294,7 @@ module GreenHat
239
294
  file_list = prepare_list(file_list, base_list)
240
295
 
241
296
  # Convert to Things
242
- find_things(file_list, flags)
297
+ find_things(file_list, flags, base_list)
243
298
  end
244
299
 
245
300
  # Total Log List Manipulator
@@ -263,13 +318,15 @@ module GreenHat
263
318
  end
264
319
 
265
320
  # Shortcut find things
266
- def self.find_things(files, flags = {})
267
- things = files.uniq.flat_map do |file|
321
+ def self.find_things(file_list, flags = {}, base_list = nil)
322
+ base_list ||= Thing.all
323
+
324
+ things = file_list.uniq.flat_map do |file|
268
325
  # If Thing, Return Thing
269
326
  return file if file.instance_of?(Thing)
270
327
 
271
328
  if flags.fuzzy_file_match
272
- Thing.list.select { |x| x.name.include?(file) || x.type.include?(file) }
329
+ base_list.select { |x| x.name.include?(file) || x.type.include?(file) }
273
330
  else
274
331
  Thing.where name: file
275
332
  end
@@ -315,6 +372,4 @@ module GreenHat
315
372
  puts
316
373
  end
317
374
  end
318
-
319
- # rubocop:enable Metrics/ModuleLength
320
375
  end
@@ -18,6 +18,12 @@ module GreenHat
18
18
  GreenHat::Web.toggle
19
19
  end
20
20
 
21
+ # Append Log Location so follow up commands are executed there
22
+ def self.default(raw_list = [])
23
+ Cli.move_shell Shell::Log
24
+ Log.default(raw_list)
25
+ end
26
+
21
27
  def self.df
22
28
  Disk.df
23
29
  end
@@ -101,8 +107,13 @@ module GreenHat
101
107
  end
102
108
  end
103
109
 
104
- def self.ls
105
- GreenHat::Cli.help(false)
110
+ def self.ls(raw = [])
111
+ if raw.empty?
112
+ GreenHat::Cli.help(false)
113
+ else
114
+ Cli.move_shell Shell::Log
115
+ Log.ls(raw)
116
+ end
106
117
  end
107
118
 
108
119
  def self.ll
@@ -27,7 +27,8 @@ module GreenHat
27
27
  'df_h' => {
28
28
  format: :table,
29
29
  pattern: [
30
- /df_h/
30
+ /df_h/,
31
+ /df_hT/
31
32
  ]
32
33
  },
33
34
  'df_inodes' => {
@@ -64,6 +65,13 @@ module GreenHat
64
65
  %r{log/syslog}
65
66
  ]
66
67
  },
68
+ 'gitlab-runner.log' => {
69
+ format: :runner_log,
70
+ log: true,
71
+ pattern: [
72
+ /gitlab-runner.log/
73
+ ]
74
+ },
67
75
  'etc/fstab' => {
68
76
  format: :clean_raw,
69
77
  pattern: [
@@ -123,6 +131,20 @@ module GreenHat
123
131
  %r{consul/current}
124
132
  ]
125
133
  },
134
+ 'consul/identify_primary_db_node.log' => {
135
+ format: :identify_db,
136
+ log: true,
137
+ pattern: [
138
+ %r{consul/identify_primary_db_node.log}
139
+ ]
140
+ },
141
+ 'gitlab-kas/current' => {
142
+ format: :time_space,
143
+ log: true,
144
+ pattern: [
145
+ %r{gitlab-kas/current}
146
+ ]
147
+ },
126
148
  'sentinel/current' => {
127
149
  format: :time_space,
128
150
  log: true,
@@ -151,6 +173,13 @@ module GreenHat
151
173
  %r{mailroom/mail_room_json.log}
152
174
  ]
153
175
  },
176
+ 'gitlab_migrations' => {
177
+ format: :raw,
178
+ log: true,
179
+ pattern: [
180
+ /gitlab_migrations/
181
+ ]
182
+ },
154
183
  'gitlab-rails/git_json.log' => {
155
184
  format: :json,
156
185
  log: true,
@@ -201,12 +230,19 @@ module GreenHat
201
230
  ]
202
231
  },
203
232
  'gitlab-exporter/current' => {
204
- format: :time_space,
233
+ format: :exporters,
205
234
  log: true,
206
235
  pattern: [
207
236
  %r{gitlab-exporter/current}
208
237
  ]
209
238
  },
239
+ 'gitlab-rails/web_exporter' => {
240
+ format: :exporters,
241
+ log: true,
242
+ pattern: [
243
+ %r{gitlab-rails/web_exporter}
244
+ ]
245
+ },
210
246
  'gitlab-monitor/current' => {
211
247
  format: :time_space,
212
248
  log: true,
@@ -4,7 +4,7 @@ module GreenHat
4
4
  module Formatters
5
5
  # Remove Comments / Empty Lines
6
6
  def format_clean_raw
7
- staging = raw.clone
7
+ staging = raw_full.clone
8
8
 
9
9
  # Empty
10
10
  staging.reject!(&:empty?)
@@ -0,0 +1,48 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # General Exporter Parser
7
+ # https://gitlab.com/gitlab-com/support/toolbox/greenhat/-/issues/30
8
+ # [YYYY-MM-DDTHH:MM:SS.sss-HHMM] …ip… - - [DD/Mon/YYYY:HH:MM:SS ZON]
9
+ # "GET /metrics HTTP/1.1" 200 12345 "-" "Prometheus/2.25.0"
10
+ # ==========================================================================
11
+ def format_exporters
12
+ self.result = raw.map do |row|
13
+ result = {}
14
+ time, output = row.split(' ', 2)
15
+ result[:time] = Time.parse(time)
16
+
17
+ # Weird Edge Cases for when IP is not included
18
+ msg = ''
19
+ if output.include? '- - '
20
+ ip, msg = output.split('- -', 2)
21
+ result[:ip] = ip unless ip.empty?
22
+ else
23
+ msg = output
24
+ end
25
+
26
+ # Styrip Extra Time / Get Call Details
27
+ if msg&.include? ']'
28
+ _time, request = msg.split('] ', 2)
29
+ result[:msg] = request # Pass full request
30
+
31
+ # Breakout
32
+ method, path, protocol, status, bytes = request.gsub('"', '').split(' ', 5)
33
+
34
+ result.merge!(method: method, path: path, protocol: protocol, status: status, bytes: bytes)
35
+
36
+ else
37
+ result[:msg] = msg
38
+ end
39
+
40
+ result
41
+ rescue StandardError => e
42
+ # TODO: Background logger
43
+ LogBot.warn('Exporters', "Unable to Parse, #{row}:#{e.message}")
44
+ end
45
+ end
46
+ # ==========================================================================
47
+ end
48
+ end
@@ -0,0 +1,32 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # consul/identify_primary_db_node.log
6
+ # https://gitlab.com/gitlab-com/support/toolbox/greenhat/-/issues/33
7
+ # I, [YYYY-MM-DDThh:mm:ss.ssssss #12345] INFO -- : Found master: sub.domain.tld
8
+ def format_identify_db
9
+ self.result = raw.map do |row|
10
+ next if row.empty? || row == "\n"
11
+
12
+ level_abrv, row = row.split(', ', 2)
13
+
14
+ time, output = row.split('] ', 2)
15
+ time = Time.parse time.split('[', 2).last.strip
16
+
17
+ level, _a, _b, msg = output.split(' ', 4)
18
+ {
19
+ time: time,
20
+ i: level_abrv,
21
+ level: level,
22
+ message: msg
23
+ }
24
+ rescue StandardError => e
25
+ # TODO: Background logger
26
+ LogBot.warn('identify_db', "Unable to Parse, #{row}:#{e.message}")
27
+ end
28
+
29
+ result.compact!
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # Attempt to make runner logs easier to parse
6
+ def format_runner_log
7
+ self.result = raw.map do |row|
8
+ next if row.empty? || row == "\n"
9
+ next if row.include? '-- Logs begin at' # Skip Header
10
+
11
+ process_runner_log_row(row)
12
+ end
13
+
14
+ result.compact!
15
+ end
16
+
17
+ # Split / Parse Time
18
+ # TODO: Better sys log parsing? Cannot find ready-made regex/ruby parser
19
+ def process_runner_log_row(row)
20
+ month, day, time, device, service, message = row.split(' ', 6)
21
+ service&.gsub!(':', '')
22
+ pid = service&.match(/\[(.*?)\]/)&.captures&.first
23
+
24
+ entry = {
25
+ time: format_time_parse("#{month} #{day} #{time}"),
26
+ device: device,
27
+ service: service,
28
+ message: message,
29
+ pid: pid,
30
+ row: row # Insert full row for different timestamp formats
31
+ }
32
+
33
+ # Remove Empty Keys
34
+ entry.compact!
35
+
36
+ # Shellwords split - Skip Blank
37
+ process_runner_row_message(message, entry) unless message.blank?
38
+
39
+ entry
40
+
41
+ # Return everything incase of error
42
+ rescue StandardError => e
43
+ LogBot.warn('Runner Log Parse', e.message)
44
+ {
45
+ message: row
46
+ }
47
+ end
48
+
49
+ def process_runner_row_message(message, entry)
50
+ # Insert Keywords / Format Time if Possible
51
+ Shellwords.split(message).select { |x| x.include? '=' }.each do |x|
52
+ key, value = x.split('=', 2)
53
+
54
+ # Don't overwrite stuff
55
+ case key
56
+ when 'time'
57
+ entry["#{key}-msg".to_sym] = format_time_parse value
58
+ when 'message', :message
59
+ entry["#{key}-msg".to_sym] = value
60
+ else
61
+ entry[key.to_sym] = value
62
+ end
63
+ end
64
+ rescue StandardError
65
+ # LogBot.debug('Runner Log Parse', e.message)
66
+ nil
67
+ end
68
+ # --
69
+ end
70
+ end
@@ -2,10 +2,24 @@
2
2
  module GreenHat
3
3
  # Log
4
4
  module Formatters
5
+ # Looks like this may be different per Type
6
+ def header_count
7
+ case name
8
+ when 'df_hT' then 7
9
+ end
10
+ end
11
+
5
12
  # Table Formatting
6
13
  def format_table
14
+ # Default to split by space unless specifically needed
15
+ headers_raw = if header_count
16
+ raw_full.first.split(' ', header_count)
17
+ else
18
+ raw_full.first.split
19
+ end
20
+
7
21
  # Headers to Readable Symbol
8
- headers = raw_full.first.split(' ', 6).map(&:downcase).map do |x|
22
+ headers = headers_raw.map(&:downcase).map do |x|
9
23
  x.gsub(/\s+/, '_').gsub(/[^0-9A-Za-z_]/, '')
10
24
  end.map(&:to_sym)
11
25