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,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
|
-
|
50
|
+
create_ledger(data, flags).each { |entry| puts entry.render }
|
52
51
|
return true
|
53
52
|
end
|
54
53
|
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
#
|
135
|
-
|
79
|
+
# Terminate
|
80
|
+
thread.kill unless flags.no_paper_thread
|
136
81
|
|
137
|
-
|
82
|
+
# -----------------
|
83
|
+
end
|
138
84
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
-
|
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
|
-
|
155
|
-
|
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
|
-
|
158
|
-
|
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
|
-
|
187
|
-
|
188
|
-
|
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
|
-
|
231
|
+
total_count_array(results, flags) if results.instance_of? Array
|
232
|
+
end
|
203
233
|
|
204
|
-
|
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(
|
267
|
-
|
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
|
-
|
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
|
data/lib/greenhat/shell.rb
CHANGED
@@ -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
|
-
|
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: :
|
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,
|
@@ -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 =
|
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
|
|