greenhat 0.3.2 → 0.3.6

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/greenhat/accessors/disk.rb +42 -3
  3. data/lib/greenhat/accessors/gitlab.rb +30 -1
  4. data/lib/greenhat/accessors/memory.rb +1 -1
  5. data/lib/greenhat/archive.rb +11 -2
  6. data/lib/greenhat/cli.rb +37 -0
  7. data/lib/greenhat/host.rb +25 -37
  8. data/lib/greenhat/shell/args.rb +22 -9
  9. data/lib/greenhat/shell/faststats.rb +23 -3
  10. data/lib/greenhat/shell/field_helper.rb +1 -1
  11. data/lib/greenhat/shell/filter_help.rb +232 -9
  12. data/lib/greenhat/shell/log.rb +153 -9
  13. data/lib/greenhat/shell/markdown.rb +352 -0
  14. data/lib/greenhat/shell/old_search_helper.rb +54 -0
  15. data/lib/greenhat/shell/page.rb +1 -1
  16. data/lib/greenhat/shell/pipe.rb +31 -0
  17. data/lib/greenhat/shell/platform.rb +28 -0
  18. data/lib/greenhat/shell/report.rb +106 -25
  19. data/lib/greenhat/shell/shell_helper.rb +114 -106
  20. data/lib/greenhat/shell.rb +7 -0
  21. data/lib/greenhat/thing/file_types.rb +126 -7
  22. data/lib/greenhat/thing/formatters/json.rb +4 -0
  23. data/lib/greenhat/thing/formatters/kube_json.rb +36 -0
  24. data/lib/greenhat/thing/formatters/kube_nginx.rb +48 -0
  25. data/lib/greenhat/thing/formatters/kube_webservice.rb +51 -0
  26. data/lib/greenhat/thing/formatters/nginx.rb +6 -2
  27. data/lib/greenhat/thing/formatters/registry.rb +47 -0
  28. data/lib/greenhat/thing/formatters/time_space.rb +0 -16
  29. data/lib/greenhat/thing/helpers.rb +12 -0
  30. data/lib/greenhat/thing.rb +10 -0
  31. data/lib/greenhat/version.rb +1 -1
  32. data/lib/greenhat/views/api.slim +55 -0
  33. data/lib/greenhat/views/chart.slim +42 -0
  34. data/lib/greenhat/views/chart_template.slim +31 -0
  35. data/lib/greenhat/views/chartkick.js +21 -0
  36. data/lib/greenhat/views/css.slim +47 -0
  37. data/lib/greenhat/views/gitaly.slim +53 -0
  38. data/lib/greenhat/views/headers.slim +16 -0
  39. data/lib/greenhat/views/index-old.slim +51 -0
  40. data/lib/greenhat/views/index.slim +14 -14
  41. data/lib/greenhat/views/info.slim +17 -18
  42. data/lib/greenhat/views/production.slim +55 -0
  43. data/lib/greenhat/views/sidekiq.slim +55 -0
  44. data/lib/greenhat/views/time.slim +63 -0
  45. data/lib/greenhat/views/workhorse.slim +16 -0
  46. data/lib/greenhat/web/api.rb +94 -0
  47. data/lib/greenhat/web/chartkick_shim.rb +14 -0
  48. data/lib/greenhat/web/faststats.rb +44 -0
  49. data/lib/greenhat/web/gitaly.rb +65 -0
  50. data/lib/greenhat/web/helpers.rb +198 -0
  51. data/lib/greenhat/web/production.rb +104 -0
  52. data/lib/greenhat/web/sidekiq.rb +73 -0
  53. data/lib/greenhat/web/stats_helpers.rb +74 -0
  54. data/lib/greenhat/web/time.rb +36 -0
  55. data/lib/greenhat/web/workhorse.rb +43 -0
  56. data/lib/greenhat/web.rb +63 -19
  57. data/lib/greenhat.rb +1 -0
  58. metadata +73 -2
@@ -103,7 +103,8 @@ module GreenHat
103
103
  StringColor.do(key, entry)
104
104
  end
105
105
 
106
- if flags[:truncate]
106
+ # Stats truncation handled separately
107
+ if flags[:truncate] && !flags[:stats]
107
108
  entry_truncate(formatted_entry, flags[:truncate])
108
109
  else
109
110
  formatted_entry
@@ -150,8 +151,21 @@ module GreenHat
150
151
  format_table_entry(flags, val)
151
152
  end
152
153
 
154
+ # Internal Query Helper
155
+ # query = 'gitlab-rails/application_json.log --message!="Cannot obtain an exclusive lease" --severity=error'
156
+ # ShellHelper.filter_internal(query)
157
+ def self.filter_internal(search = '')
158
+ files, flags, args = Args.parse(Shellwords.split(search))
159
+ flags[:combine] = true
160
+
161
+ # Default to everything
162
+ files = Thing.all.map(&:name) if files.empty?
163
+
164
+ ShellHelper.filter_start(files, flags, args)
165
+ end
166
+
153
167
  # Main Entry Point for Filtering
154
- def self.filter_start(files, flags, args)
168
+ def self.filter_start(files, flags = {}, args = {})
155
169
  # Convert to Things
156
170
  logs = ShellHelper.find_things(files, flags).select(&:processed?)
157
171
 
@@ -167,11 +181,17 @@ module GreenHat
167
181
 
168
182
  # Include Total Count in Name
169
183
  results = ShellHelper.filter(log.data, flags, args)
184
+ duration = calculate_duration(results)
185
+
170
186
  title = [
171
187
  log.friendly_name,
172
188
  " #{results.count}".pastel(:bright_black)
189
+
173
190
  ]
174
191
 
192
+ # Append Duration
193
+ title.push(" #{duration.pastel(:cyan, :dim)}") unless duration.blank?
194
+
175
195
  # Save unless empty
176
196
  obj[title.join] = results unless results.count.zero?
177
197
 
@@ -180,6 +200,31 @@ module GreenHat
180
200
  end
181
201
  end
182
202
 
203
+ def self.calculate_duration(results)
204
+ only_with_time = results.select(&:time)
205
+
206
+ # If slice is used ignore
207
+ return nil if only_with_time.empty?
208
+
209
+ sorted = only_with_time.map(&:time).sort
210
+ humanize_time(sorted.first, sorted.last)
211
+ end
212
+
213
+ # Replace TimeDifference with https://stackoverflow.com/a/4136485/1678507
214
+ def self.humanize_time(time_start, time_end, increments = 2)
215
+ miliseconds = (time_end - time_start) * 1000
216
+
217
+ list = [[1000, :ms], [60, :s], [60, :m], [24, :h]].map do |count, name|
218
+ next unless miliseconds.positive?
219
+
220
+ miliseconds, n = miliseconds.divmod(count)
221
+
222
+ "#{n.to_i}#{name}" unless n.to_i.zero?
223
+ end
224
+
225
+ list.compact.reverse[0..increments - 1].join(' ')
226
+ end
227
+
183
228
  # Filter Logic
184
229
  # TODO: Simplify
185
230
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -189,7 +234,7 @@ module GreenHat
189
234
  # Experimenting with deep clone
190
235
  results = Marshal.load(Marshal.dump(data))
191
236
  results.select! do |row|
192
- args.send(flags.logic) do |arg|
237
+ args.send(flags.logic || :all?) do |arg|
193
238
  filter_row_key(row, arg, flags)
194
239
  end
195
240
  end
@@ -255,7 +300,6 @@ module GreenHat
255
300
  end
256
301
 
257
302
  # Filter Start and End Times
258
- # rubocop:disable Metrics/MethodLength
259
303
  # TODO: This is a bit icky, simplify/dry
260
304
  def self.filter_time(results, flags)
261
305
  if flags.key?(:start)
@@ -292,7 +336,6 @@ module GreenHat
292
336
 
293
337
  results
294
338
  end
295
- # rubocop:enable Metrics/MethodLength
296
339
 
297
340
  def self.filter_except(results, except)
298
341
  # Avoid Empty Results
@@ -368,7 +411,10 @@ module GreenHat
368
411
 
369
412
  # Loop through Stats, Separate Hash/Tables
370
413
  stats.map do |field|
371
- occurrences = filter_count_occurrences(results, field)
414
+ occurrences = filter_count_occurrences(results, field, flags)
415
+
416
+ # Use Truncate For Long Keys
417
+ occurrences.transform_keys! { |key| key.to_s[0..flags[:truncate]] } if flags[:truncate]
372
418
 
373
419
  # Total Occurences
374
420
  total = occurrences.values.sum
@@ -387,13 +433,6 @@ module GreenHat
387
433
  # Append Header / Total with field name
388
434
  output.unshift([field.to_s.pastel(:bright_black), total])
389
435
 
390
- # Use Truncate For Long Keys
391
- if flags[:truncate]
392
- output.map! do |key, value|
393
- [key.to_s[0..flags[:truncate]], value]
394
- end
395
- end
396
-
397
436
  # Format
398
437
  output.to_h
399
438
  end
@@ -405,10 +444,17 @@ module GreenHat
405
444
  end
406
445
 
407
446
  # Helper to Count occurrences
408
- def self.filter_count_occurrences(results, field)
447
+ def self.filter_count_occurrences(results, field, flags = {})
409
448
  results.each_with_object(Hash.new(0)) do |entry, counts|
410
449
  if entry.key? field
411
- counts[entry[field]] += 1
450
+ # Rounding in pagination breaks stats
451
+ key = if flags.key?(:round) && entry[field].numeric?
452
+ entry[field].to_f.round(flags.round)
453
+ else
454
+ entry[field]
455
+ end
456
+
457
+ counts[key] += 1
412
458
  else
413
459
  counts['None'.pastel(:bright_black)] += 1
414
460
  end
@@ -426,48 +472,83 @@ module GreenHat
426
472
  end
427
473
 
428
474
  # Break out filter row logic into separate method
429
-
430
475
  def self.filter_row_key(row, arg, flags)
431
476
  # Ignore Other Logic if Field isn't even included / Full Text Searching
432
477
  return false unless row.key?(arg[:field]) || arg[:field] == :text
433
478
 
434
479
  # Sensitivity Check / Check for Match / Full Text Searching
435
- included = if arg[:field] == :text
436
- filter_row_entry(row.to_s, arg, flags)
437
- else
438
- filter_row_entry(row[arg.field].to_s, arg, flags)
439
- end
480
+ search_data = arg[:field] == :text ? row : row[arg.field]
481
+ match = filter_row_entry(search_data.to_s, arg, flags)
440
482
 
441
483
  # Pivot of off include vs exclude
442
484
  if arg.bang
443
- !included
485
+ !match
444
486
  else
445
- included
487
+ match
446
488
  end
447
489
  end
448
490
 
449
491
  # Field Partial / Case / Exact search
450
492
  def self.filter_row_entry(entry, arg, flags)
451
493
  # Exact Matching / Unless doing full text search
452
- return entry.to_s == arg.value.to_s if flags.key?(:exact) && arg.field != :text
494
+ return entry == arg.value.to_s if flags.key?(:exact) && arg.field != :text
453
495
 
454
- if flags.key?(:case)
455
- entry.include? arg.value.to_s
456
- else
457
- entry.downcase.include? arg.value.to_s.downcase
496
+ # Cast to String/Integer Helper
497
+ entry, value = filter_entry_cast(entry, arg, flags)
498
+
499
+ entry.send(arg.logic, value)
500
+ end
501
+
502
+ # Handle casting to strings or integers
503
+ def self.filter_entry_cast(entry, arg, flags)
504
+ # Cast to String
505
+ value = arg.value.to_s
506
+
507
+ case arg.logic
508
+ when :include?
509
+
510
+ # Exact Case argument
511
+ unless flags.key?(:case)
512
+ entry.downcase!
513
+ value.downcase!
514
+ end
515
+ when :>=, :<=
516
+ entry = entry.to_i if entry.numeric?
517
+ value = value.to_i if value&.numeric?
458
518
  end
519
+
520
+ [entry, value]
521
+ end
522
+
523
+ def self.filter_entry_logic(entry, arg)
524
+ entry.send(arg.logic, arg.value)
459
525
  end
460
526
 
461
527
  # Total Count Helper
462
- def self.total_count(results)
463
- results.each do |k, v|
528
+ def self.total_count(results, flags)
529
+ results.map do |k, v|
464
530
  puts k
465
- puts "Total: #{v.count.to_s.pastel(:blue)}"
531
+ # puts "Total: #{v.count.to_s.pastel(:blue)}"
532
+ # puts "Time Covered: #{calculate_duration(v).pastel(:cyan)}"
533
+
534
+ output = {}
535
+ output[:total] = v.count
536
+ output[:duration] = calculate_duration(v)
537
+
538
+ # Sort / Get first and Last
539
+ list = v.select(&:time).map(&:time)
540
+ unless list.blank?
541
+ output[:start] = list.first
542
+ output[:end] = list.last
543
+ end
544
+
545
+ puts render_table(output, flags)
546
+
466
547
  puts
467
548
  end
468
549
  end
469
550
 
470
- # Total Count Helper
551
+ # Table Printer Helper
471
552
  def self.fields_print(results)
472
553
  results.each do |k, v|
473
554
  puts k
@@ -531,7 +612,7 @@ module GreenHat
531
612
  return file if file.instance_of?(Thing)
532
613
 
533
614
  if flags.fuzzy_file_match
534
- Thing.all.select { |x| x.name.include? file }
615
+ Thing.all.select { |x| x.name.include?(file) || x.type.include?(file) }
535
616
  else
536
617
  Thing.where name: file
537
618
  end
@@ -543,62 +624,6 @@ module GreenHat
543
624
  things
544
625
  end
545
626
 
546
- # Main Entry Point for Searching
547
- # def self.search_start(log_list, filter_type, args, opts)
548
- def self.search_start(files, flags, args)
549
- # Convert to Things
550
- logs = ShellHelper.find_things(files, flags)
551
-
552
- logs.each_with_object({}) do |log, obj|
553
- # Ignore Empty Results / No Thing
554
- next if log&.data.blank?
555
-
556
- obj[log.friendly_name] = ShellHelper.search(log.data, flags, args)
557
-
558
- obj
559
- end
560
- end
561
-
562
- # Generic Search Helper / String/Regex
563
- def self.search(data, flags = {}, args = {})
564
- results = data.clone.flatten.compact
565
- results.select! do |row|
566
- args.send(flags.logic) do |arg|
567
- search_row(row, arg, flags)
568
- end
569
- end
570
-
571
- # Strip Results if Slice is defined
572
- results.map! { |row| row.slice(*flags[:slice]) } if flags[:slice]
573
-
574
- # Strip Results if Except is defined
575
- results.map! { |row| row.except(*flags[:except]) } if flags[:except]
576
-
577
- # Remove Blank from either slice or except
578
- results.reject!(&:empty?)
579
-
580
- results
581
- end
582
-
583
- # Break out filter row logic into separate method
584
- def self.search_row(row, arg, flags)
585
- # Sensitivity Check / Check for Match
586
- included = filter_row_entry(row.to_s, arg, flags)
587
-
588
- # Pivot of off include vs exclude
589
- if arg.bang
590
- !included
591
- else
592
- included
593
- end
594
- end
595
-
596
- # TODO: Remove?
597
- # Color Reader Helper
598
- # def self.pastel
599
- # @pastel ||= Pastel.new
600
- # end
601
-
602
627
  # Number Helper
603
628
  # https://gitlab.com/zedtux/human_size_to_number/-/blob/master/lib/human_size_to_number/helper.rb
604
629
  def self.human_size_to_number(string)
@@ -620,23 +645,6 @@ module GreenHat
620
645
  number.round
621
646
  end
622
647
 
623
- # TODO: Needed?
624
- def self.filter_and(data, params = {})
625
- result = data.clone.flatten.compact
626
- params.each do |k, v|
627
- result.select! do |row|
628
- if row.key? k.to_sym
629
- row[k.to_sym].include? v
630
- else
631
- false
632
- end
633
- end
634
- next
635
- end
636
-
637
- result
638
- end
639
-
640
648
  # General Helper for `show`
641
649
  def self.common_opts
642
650
  puts 'Common Options'.pastel(:blue)
@@ -7,6 +7,13 @@ module GreenHat
7
7
  # rubocop:enable Lint/Debugger
8
8
  end
9
9
 
10
+ def self.web
11
+ # Load Required Files
12
+ require 'greenhat/web'
13
+
14
+ GreenHat::Web.toggle
15
+ end
16
+
10
17
  def self.df
11
18
  Disk.df
12
19
  end
@@ -43,6 +43,13 @@ module GreenHat
43
43
  /dmesg/
44
44
  ]
45
45
  },
46
+ 'lets-encrypt/renewal' => {
47
+ format: :bracket_log,
48
+ log: true,
49
+ pattern: [
50
+ %r{lets-encrypt/renewal}
51
+ ]
52
+ },
46
53
  'repmgrd/current' => {
47
54
  format: :bracket_log,
48
55
  log: true,
@@ -87,6 +94,12 @@ module GreenHat
87
94
  /getenforce/
88
95
  ]
89
96
  },
97
+ 'geo-logcursor/current' => {
98
+ format: :raw,
99
+ pattern: [
100
+ %r{geo-logcursor/current}
101
+ ]
102
+ },
90
103
  'gitaly/current' => {
91
104
  format: :json_shell,
92
105
  log: true,
@@ -225,7 +238,8 @@ module GreenHat
225
238
  format: :json,
226
239
  log: true,
227
240
  pattern: [
228
- %r{gitlab-rails/audit_json.log}
241
+ %r{gitlab-rails/audit_json.log},
242
+ %r{webservice.log/audit_json.log}
229
243
  ]
230
244
  },
231
245
  'gitlab-rails/auth.log' => {
@@ -336,6 +350,20 @@ module GreenHat
336
350
  %r{nginx/current}
337
351
  ]
338
352
  },
353
+ 'nginx-ingress.log' => {
354
+ format: :kube_nginx,
355
+ log: true,
356
+ pattern: [
357
+ /nginx-ingress.log/
358
+ ]
359
+ },
360
+ 'nginx/access.log' => {
361
+ format: :nginx,
362
+ log: true,
363
+ pattern: [
364
+ %r{nginx/access.log}
365
+ ]
366
+ },
339
367
  'nginx/gitlab_pages_access.log' => {
340
368
  format: :nginx,
341
369
  log: true,
@@ -422,7 +450,7 @@ module GreenHat
422
450
  ]
423
451
  },
424
452
  'registry/current' => {
425
- format: :time_shellwords,
453
+ format: :time_registry,
426
454
  log: true,
427
455
  pattern: [
428
456
  %r{registry/current},
@@ -444,16 +472,18 @@ module GreenHat
444
472
  },
445
473
  'puma/puma_stderr.log' => {
446
474
  format: :raw,
447
- log: true,
475
+ log: false,
448
476
  pattern: [
449
- %r{puma/puma_stderr.log}
477
+ %r{puma/puma_stderr.log},
478
+ %r{webservice.log/puma.stderr.log}
450
479
  ]
451
480
  },
452
481
  'puma/puma_stdout.log' => {
453
482
  format: :json,
454
483
  log: true,
455
484
  pattern: [
456
- %r{puma/puma_stdout.log}
485
+ %r{puma/puma_stdout.log},
486
+ %r{webservice.log/puma.stdout.log}
457
487
  ]
458
488
  },
459
489
  'gitlab-pages/current' => {
@@ -529,6 +559,20 @@ module GreenHat
529
559
  %r{unicorn/current}
530
560
  ]
531
561
  },
562
+ 'unicorn_stats' => {
563
+ format: :time_space,
564
+ log: true,
565
+ pattern: [
566
+ /unicorn_stats/
567
+ ]
568
+ },
569
+ 'unicorn/unicorn_stdout.log' => {
570
+ format: :raw,
571
+ log: true,
572
+ pattern: [
573
+ %r{unicorn/unicorn_stdout.log}
574
+ ]
575
+ },
532
576
  'running_swappiness' => {
533
577
  format: :raw,
534
578
  pattern: [
@@ -566,6 +610,7 @@ module GreenHat
566
610
  log: true,
567
611
  pattern: [
568
612
  %r{sidekiq/current},
613
+ /sidekiq_current/,
569
614
  %r{sidekiq/@.*}
570
615
  ]
571
616
  },
@@ -629,6 +674,12 @@ module GreenHat
629
674
  /uname/
630
675
  ]
631
676
  },
677
+ 'gitlab_socket_stats' => {
678
+ format: :gitlab_socket_stats,
679
+ pattern: [
680
+ /gitlab_socket_stats/
681
+ ]
682
+ },
632
683
  'uptime' => {
633
684
  format: :raw,
634
685
  pattern: [
@@ -745,13 +796,15 @@ module GreenHat
745
796
  'gitlab-rails/application.log' => {
746
797
  format: :raw,
747
798
  pattern: [
748
- %r{gitlab-rails/application.log}
799
+ %r{gitlab-rails/application.log},
800
+ %r{webservice.log/application.log}
749
801
  ]
750
802
  },
751
803
  'gitlab-rails/production.log' => {
752
804
  format: :raw,
753
805
  pattern: [
754
- %r{gitlab-rails/production.log}
806
+ %r{gitlab-rails/production.log},
807
+ %r{webservice.log/production.log}
755
808
  ]
756
809
  },
757
810
  'gitlab/version-manifest.txt' => {
@@ -765,6 +818,72 @@ module GreenHat
765
818
  pattern: [
766
819
  %r{sidekiq/perf.data}
767
820
  ]
821
+ },
822
+
823
+ # ======================================================================
824
+ # KubeSoS TODO Section
825
+ # Things I am going to shortcut and set to raw for now
826
+ # ======================================================================
827
+ # Attempted Parsing
828
+ 'kubesos_json' => {
829
+ log: true,
830
+ format: :kube_json,
831
+ pattern: [
832
+ /gitaly.log/
833
+ ]
834
+ },
835
+
836
+ 'kube_webservice' => {
837
+ log: false,
838
+ format: :kube_webservice,
839
+ pattern: [
840
+ /^webservice\.log$/
841
+ ]
842
+ },
843
+
844
+ 'kubesos' => {
845
+ format: :raw,
846
+ pattern: [
847
+ /all_values.yaml/,
848
+ %r{webservice.log/sidekiq_client.log},
849
+ /chart-version/,
850
+ /configmaps/,
851
+ /describe_deployments/,
852
+ /describe_ingress/,
853
+ /describe_nodes/,
854
+ /describe_pods/,
855
+ /describe_pv/,
856
+ /describe_pvc/,
857
+ /events/,
858
+ /get_deployments/,
859
+ /get_endpoints/,
860
+ /get_jobs/,
861
+ /get_pods/,
862
+ /get_pv/,
863
+ /get_pvc/,
864
+ /get_services/,
865
+ /gitaly.log/,
866
+ /gitlab-exporter.log/,
867
+ /gitlab-pages.log/,
868
+ /gitlab-shell.log/,
869
+ /grafana.log/,
870
+ /helm-version/,
871
+ /kubectl-check/,
872
+ /migrations.log/,
873
+ /minio.log/,
874
+ /nfs-client-provisioner.log/,
875
+ /operator.log/,
876
+ /postgresql.log/,
877
+ /prometheus.log/,
878
+ /redis.log/,
879
+ /registry.log/,
880
+ /secrets/,
881
+ /sidekiq.log/,
882
+ /task-runner.log/,
883
+ /top_nodes/,
884
+ /top_pods/,
885
+ /user_supplied_values.yaml/
886
+ ]
768
887
  }
769
888
  }
770
889
  end
@@ -43,6 +43,10 @@ module GreenHat
43
43
  # Check for Common Fields
44
44
  def format_json_time(result)
45
45
  result.time = format_time_parse(result.time) if result.key? :time
46
+
47
+ # If timestamp exists but time doesn't, add time
48
+ result.time = format_time_parse(result.timestamp) if result.key?(:timestamp) && !result.key?(:time)
49
+
46
50
  result.created_at = format_time_parse(result.created_at) if result.key? :created_at
47
51
  result.enqueued_at = format_time_parse(result.enqueued_at) if result.key? :enqueued_at
48
52
  rescue StandardError => e
@@ -0,0 +1,36 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # K8s logs seem to have a lot of non-json entries
7
+ # Extract all json, ignore everything else
8
+ # ==========================================================================
9
+ def format_kube_json
10
+ self.result = raw.map do |row|
11
+ # Skip all non-json
12
+ next unless row.first == '{'
13
+
14
+ result = begin
15
+ Oj.load row
16
+ rescue EncodingError
17
+ puts
18
+ next
19
+ end
20
+
21
+ # Parsing Time
22
+ format_json_traverse result
23
+
24
+ result.sort.to_h
25
+ rescue StandardError => e
26
+ # TODO: Background Logger?
27
+ e.message
28
+ LogBot.warn('JSON Parse', e.message)
29
+ next
30
+ end.compact
31
+
32
+ :ok
33
+ end
34
+ # =========================================================================
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ # Top
2
+ module GreenHat
3
+ # Log
4
+ module Formatters
5
+ # ==========================================================================
6
+ # Formatters
7
+ # ==========================================================================
8
+ def format_kube_nginx
9
+ self.result = raw.map do |row|
10
+ ip, _sym, remote_user, rest = row.split(' ', 4)
11
+
12
+ time, rest = rest.split(']', 2)
13
+ time = Time.strptime(time, '[%d/%b/%Y:%H:%M:%S %z')
14
+
15
+ verb, status, bytes, http_referer, http_user_agent, gzip_ratio = Shellwords.split(rest)
16
+
17
+ method, path, http_version = verb.split
18
+
19
+ {
20
+ remote_addr: ip,
21
+ remote_user: remote_user,
22
+ method: method,
23
+ path: path,
24
+ status: status,
25
+ bytes: bytes,
26
+ http_version: http_version,
27
+ http_referer: http_referer,
28
+ http_user_agent: http_user_agent,
29
+ gzip_ratio: gzip_ratio,
30
+ time: time
31
+ }
32
+
33
+ # Fall back for malformed logs
34
+ rescue StandardError
35
+ { message: row }
36
+ end
37
+
38
+ :ok
39
+ end
40
+
41
+ # rubocop:disable Layout/LineLength
42
+ # NGINX Conf: /var/opt/gitlab/nginx/conf/nginx.conf
43
+ # log_format gitlab_access '$remote_addr - $remote_user [$time_local] "$request_method $filtered_request_uri $server_protocol" $status $body_bytes_sent "$filtered_http_referer" "$http_user_agent" $gzip_ratio';
44
+ # rubocop:enable Layout/LineLength
45
+
46
+ # ==========================================================================
47
+ end
48
+ end