greenhat 0.3.4 → 0.5.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/bin/greenhat +2 -6
  3. data/lib/greenhat/accessors/disk.rb +1 -3
  4. data/lib/greenhat/accessors/gitlab.rb +7 -2
  5. data/lib/greenhat/accessors/memory.rb +1 -1
  6. data/lib/greenhat/archive.rb +19 -8
  7. data/lib/greenhat/cli.rb +35 -135
  8. data/lib/greenhat/entrypoint.rb +170 -0
  9. data/lib/greenhat/host.rb +25 -37
  10. data/lib/greenhat/settings.rb +33 -5
  11. data/lib/greenhat/shell/args.rb +22 -9
  12. data/lib/greenhat/shell/faststats.rb +23 -3
  13. data/lib/greenhat/shell/field_helper.rb +1 -1
  14. data/lib/greenhat/shell/filter_help.rb +217 -162
  15. data/lib/greenhat/shell/gitlab.rb +1 -0
  16. data/lib/greenhat/shell/log.rb +150 -25
  17. data/lib/greenhat/shell/markdown.rb +21 -25
  18. data/lib/greenhat/shell/old_search_helper.rb +54 -0
  19. data/lib/greenhat/shell/page.rb +1 -1
  20. data/lib/greenhat/shell/pipe.rb +31 -0
  21. data/lib/greenhat/shell/platform.rb +28 -0
  22. data/lib/greenhat/shell/query.rb +378 -0
  23. data/lib/greenhat/shell/report.rb +76 -24
  24. data/lib/greenhat/shell/shell_helper.rb +42 -393
  25. data/lib/greenhat/shell.rb +19 -4
  26. data/lib/greenhat/thing/file_types.rb +51 -1
  27. data/lib/greenhat/thing/formatters/api_json.rb +4 -2
  28. data/lib/greenhat/thing/formatters/bracket_log.rb +1 -1
  29. data/lib/greenhat/thing/formatters/colon_split_strip.rb +2 -2
  30. data/lib/greenhat/thing/formatters/dotenv.rb +1 -1
  31. data/lib/greenhat/thing/formatters/format.rb +0 -11
  32. data/lib/greenhat/thing/formatters/free_m.rb +2 -2
  33. data/lib/greenhat/thing/formatters/json.rb +43 -15
  34. data/lib/greenhat/thing/formatters/json_shellwords.rb +3 -2
  35. data/lib/greenhat/thing/formatters/kube_json.rb +3 -2
  36. data/lib/greenhat/thing/formatters/multiline_json.rb +1 -1
  37. data/lib/greenhat/thing/formatters/nginx.rb +11 -3
  38. data/lib/greenhat/thing/formatters/table.rb +3 -3
  39. data/lib/greenhat/thing/formatters/time_space.rb +0 -16
  40. data/lib/greenhat/thing/helpers.rb +12 -11
  41. data/lib/greenhat/thing/info_format.rb +4 -4
  42. data/lib/greenhat/thing/kind.rb +5 -0
  43. data/lib/greenhat/thing/super_log.rb +0 -101
  44. data/lib/greenhat/thing.rb +31 -25
  45. data/lib/greenhat/version.rb +1 -1
  46. data/lib/greenhat/views/api.slim +55 -0
  47. data/lib/greenhat/views/chart.slim +42 -0
  48. data/lib/greenhat/views/chart_template.slim +31 -0
  49. data/lib/greenhat/views/chartkick.js +21 -0
  50. data/lib/greenhat/views/css.slim +47 -0
  51. data/lib/greenhat/views/gitaly.slim +53 -0
  52. data/lib/greenhat/views/headers.slim +16 -0
  53. data/lib/greenhat/views/index-old.slim +51 -0
  54. data/lib/greenhat/views/index.slim +14 -14
  55. data/lib/greenhat/views/info.slim +17 -18
  56. data/lib/greenhat/views/production.slim +55 -0
  57. data/lib/greenhat/views/sidekiq.slim +55 -0
  58. data/lib/greenhat/views/time.slim +63 -0
  59. data/lib/greenhat/views/workhorse.slim +16 -0
  60. data/lib/greenhat/web/api.rb +94 -0
  61. data/lib/greenhat/web/chartkick_shim.rb +14 -0
  62. data/lib/greenhat/web/faststats.rb +44 -0
  63. data/lib/greenhat/web/gitaly.rb +65 -0
  64. data/lib/greenhat/web/helpers.rb +198 -0
  65. data/lib/greenhat/web/production.rb +104 -0
  66. data/lib/greenhat/web/sidekiq.rb +73 -0
  67. data/lib/greenhat/web/stats_helpers.rb +74 -0
  68. data/lib/greenhat/web/time.rb +36 -0
  69. data/lib/greenhat/web/workhorse.rb +43 -0
  70. data/lib/greenhat/web.rb +63 -19
  71. data/lib/greenhat.rb +2 -0
  72. metadata +74 -5
@@ -11,9 +11,10 @@ module GreenHat
11
11
  result = Oj.load row
12
12
 
13
13
  # Parsing Time
14
- format_json_traverse result
14
+ format_time(result)
15
15
 
16
- flatten_hash(result).sort.to_h
16
+ # flatten_hash(result).sort.to_h
17
+ result
17
18
  rescue StandardError => e
18
19
  # TODO: Background Logger?
19
20
  e.message
@@ -29,6 +30,7 @@ module GreenHat
29
30
  v.is_a?(Hash) ? a.merge(flatten_hash(v, "#{prefix}#{k}.")) : a.merge("#{prefix}#{k}".to_sym => v)
30
31
  end
31
32
  end
33
+
32
34
  # ==========================================================================
33
35
  end
34
36
  end
@@ -25,7 +25,7 @@ module GreenHat
25
25
  result
26
26
  rescue StandardError => e
27
27
  # TODO: Background logger
28
- LogBot.fatal('dmesg', "Unable to Parse, #{row}:#{e.message}")
28
+ LogBot.warn('dmesg', "Unable to Parse, #{row}:#{e.message}")
29
29
  end
30
30
 
31
31
  self.result.compact!
@@ -4,9 +4,9 @@ module GreenHat
4
4
  module Formatters
5
5
  # Formatters for single json blobs in entire file
6
6
  def format_colon_split_strip
7
- self.result = raw.map do |row|
7
+ self.result = raw_full.to_h do |row|
8
8
  row.split(':', 2).map(&:strip)
9
- end.to_h
9
+ end
10
10
  end
11
11
  end
12
12
  end
@@ -4,7 +4,7 @@ module GreenHat
4
4
  module Formatters
5
5
  # Formatters for Dmesg
6
6
  def format_dotenv
7
- self.result = Dotenv::Parser.new(raw.join("\n")).call
7
+ self.result = Dotenv::Parser.new(raw_full.join("\n")).call
8
8
  end
9
9
  end
10
10
  end
@@ -1,12 +1 @@
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
1
 
8
- def log_type
9
- SuperLog.type?(path)
10
- end
11
- end
12
- end
@@ -5,7 +5,7 @@ module GreenHat
5
5
  # Get Split Memory Table
6
6
  def format_free_m
7
7
  # Headers to Readable Symbol
8
- headers = raw.first.split(' ', 6).map(&:downcase).map do |x|
8
+ headers = raw_full.first.split.map(&:downcase).map do |x|
9
9
  x.gsub(/\s+/, '_').gsub(/[^0-9A-Za-z_]/, '')
10
10
  end.map(&:to_sym)
11
11
 
@@ -15,7 +15,7 @@ module GreenHat
15
15
  final = []
16
16
 
17
17
  # Put fields into a Hash based on Location/Key
18
- raw[1..].map(&:split).each do |row|
18
+ raw_full[1..].map(&:split).each do |row|
19
19
  result = {}
20
20
  row.each_with_index do |detail, i|
21
21
  result[headers[i]] = detail.split(':').first
@@ -14,10 +14,10 @@ module GreenHat
14
14
  { message: row }
15
15
  end
16
16
 
17
- # Parsing Time
18
- format_json_traverse result
17
+ # Parsing Time / Recusrive is really slow
18
+ format_time(result)
19
19
 
20
- result.sort.to_h
20
+ result
21
21
  rescue StandardError => e
22
22
  # TODO: Background Logger?
23
23
  e.message
@@ -27,11 +27,12 @@ module GreenHat
27
27
 
28
28
  :ok
29
29
  end
30
+
30
31
  # ==========================================================================
31
32
 
32
- # Recursively Navigate
33
+ # Recursively Navigate -- Recusrive is really slow
33
34
  def format_json_traverse(result)
34
- format_json_time(result)
35
+ format_time(result)
35
36
 
36
37
  result.each do |_key, value|
37
38
  next unless value.instance_of? Hash
@@ -40,23 +41,50 @@ module GreenHat
40
41
  end
41
42
  end
42
43
 
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
44
+ def format_time_fields
45
+ %i[time timestamp created_at enqueued_at completed_at]
46
+ end
47
+
48
+ # Loop through potential fields and parse as needed
49
+ def format_time(result)
50
+ format_time_fields.each do |field|
51
+ result[field] = format_time_parse(result[field]) if result.key?(field)
52
+ rescue StandardError => e
53
+ LogBot.warn('JSON Format Time', e.message)
54
+ next
55
+ end
51
56
  end
52
57
 
53
- # Handle Epoch Timestamps as well as string timestamps
58
+ # Check for Common Fields
59
+ # def format_json_time(result)
60
+ # if result.key? :time
61
+ # result.time = format_time_parse(result.time)
62
+ # elsif result.key?(:timestamp)
63
+ # result.time = format_time_parse(result.timestamp)
64
+ # end
65
+
66
+ # result.created_at = format_time_parse(result.created_at) if result.key? :created_at
67
+ # result.enqueued_at = format_time_parse(result.enqueued_at) if result.key? :enqueued_at
68
+ # rescue StandardError => e
69
+ # LogBot.warn("JSON Time Parse", e.message)
70
+ # true
71
+ # end
72
+
54
73
  def format_time_parse(time)
74
+ Time.parse time
75
+ rescue StandardError
76
+ # Handle Epoch Timestamps as well as string timestamps
77
+ format_time_numeric(time)
78
+ end
79
+
80
+ def format_time_numeric(time)
55
81
  if time.numeric?
56
82
  Time.at time
57
83
  else
58
- Time.parse time
84
+ time
59
85
  end
86
+ rescue StandardError => e
87
+ LogBot.warn('JSON Time Parse', e.message)
60
88
  end
61
89
  # ---
62
90
  end
@@ -14,9 +14,9 @@ module GreenHat
14
14
  end
15
15
 
16
16
  # Parsing Time
17
- format_json_traverse result
17
+ format_time(result)
18
18
 
19
- result.sort.to_h
19
+ result
20
20
  rescue StandardError => e
21
21
  LogBot.warn('JSON Parse', e.message)
22
22
  next
@@ -36,6 +36,7 @@ module GreenHat
36
36
 
37
37
  result
38
38
  end
39
+
39
40
  # ==========================================================================
40
41
  end
41
42
  end
@@ -19,9 +19,9 @@ module GreenHat
19
19
  end
20
20
 
21
21
  # Parsing Time
22
- format_json_traverse result
22
+ format_time(result)
23
23
 
24
- result.sort.to_h
24
+ result
25
25
  rescue StandardError => e
26
26
  # TODO: Background Logger?
27
27
  e.message
@@ -31,6 +31,7 @@ module GreenHat
31
31
 
32
32
  :ok
33
33
  end
34
+
34
35
  # =========================================================================
35
36
  end
36
37
  end
@@ -4,7 +4,7 @@ module GreenHat
4
4
  module Formatters
5
5
  # Formatters for single json blobs in entire file
6
6
  def format_multiline_json
7
- self.result = Oj.load raw.join
7
+ self.result = Oj.load raw_full.join
8
8
  end
9
9
  end
10
10
  end
@@ -6,11 +6,14 @@ module GreenHat
6
6
  # Formatters
7
7
  # ==========================================================================
8
8
  def format_nginx
9
- self.result = raw.map do |row|
10
- ip, _sym, remote_user, rest = row.split(' ', 4)
9
+ output = raw.map do |row|
10
+ next if row.chomp.empty?
11
+
12
+ conn_data, rest = row.split(' [', 2)
13
+ ip, _sym, remote_user = conn_data.split(' ', 3)
11
14
 
12
15
  time, rest = rest.split(']', 2)
13
- time = Time.strptime(time, '[%d/%b/%Y:%H:%M:%S %z')
16
+ time = Time.strptime(time, '%d/%b/%Y:%H:%M:%S %z')
14
17
 
15
18
  verb, status, bytes, http_referer, http_user_agent, gzip_ratio = Shellwords.split(rest)
16
19
 
@@ -29,8 +32,13 @@ module GreenHat
29
32
  gzip_ratio: gzip_ratio,
30
33
  time: time
31
34
  }
35
+ rescue StandardError => e
36
+ LogBot.warn('NGINX Parse', e.message)
37
+ { msg: row }
32
38
  end
33
39
 
40
+ # Remove Empty Entries
41
+ self.result = output.compact
34
42
  :ok
35
43
  end
36
44
 
@@ -2,17 +2,17 @@
2
2
  module GreenHat
3
3
  # Log
4
4
  module Formatters
5
- # Formatters for Dmesg
5
+ # Table Formatting
6
6
  def format_table
7
7
  # Headers to Readable Symbol
8
- headers = raw.first.split(' ', 6).map(&:downcase).map do |x|
8
+ headers = raw_full.first.split(' ', 6).map(&:downcase).map do |x|
9
9
  x.gsub(/\s+/, '_').gsub(/[^0-9A-Za-z_]/, '')
10
10
  end.map(&:to_sym)
11
11
 
12
12
  final = []
13
13
 
14
14
  # Put fields into a Hash based on Location/Key
15
- raw[1..].map(&:split).each do |row|
15
+ raw_full.map(&:split)[1..].each do |row|
16
16
  result = {}
17
17
  row.each_with_index do |detail, i|
18
18
  result[headers[i]] = detail
@@ -18,19 +18,3 @@ module GreenHat
18
18
  # ==========================================================================
19
19
  end
20
20
  end
21
-
22
- # def time_space
23
- # IO.foreach(file) do |row|
24
- # time, msg = row.split(' ', 2)
25
- # result = {
26
- # time: parse_datetime(time), msg: msg, host: thing.host,
27
- # source: path_format
28
- # }
29
-
30
- # result[:time] ||= datetime
31
- # post result
32
- # rescue StandardError => e
33
- # puts "Unable to Parse, #{name}:#{e.message}"
34
- # post(time: datetime, msg: row, source: path_format, host: thing.host)
35
- # end
36
- # end
@@ -25,17 +25,6 @@ module GreenHat
25
25
  tmp_path.split('/').last(2).join(divider)
26
26
  end
27
27
  end
28
-
29
- # Check what kind of file we have
30
- def type_check
31
- if info?
32
- :info
33
- elsif SuperLog.type?(path)
34
- :log
35
- else
36
- :raw
37
- end
38
- end
39
28
  end
40
29
  end
41
30
 
@@ -69,3 +58,15 @@ class FalseClass
69
58
  0
70
59
  end
71
60
  end
61
+
62
+ # https://stackoverflow.com/a/449322/1678507
63
+ class Time
64
+ # Time#round already exists with different meaning in Ruby 1.9
65
+ def round_off(seconds = 60)
66
+ Time.at((to_f / seconds).round * seconds).utc
67
+ end
68
+
69
+ def floor(seconds = 60)
70
+ Time.at((to_f / seconds).floor * seconds).utc
71
+ end
72
+ end
@@ -64,15 +64,15 @@ module GreenHat
64
64
  conns, sockets = raw.split { |x| x.include? 'Active' }.reject(&:empty?)
65
65
 
66
66
  formatted_conns = conns[1..].map do |entry|
67
- entry.split(' ', 7).map(&:strip).each_with_index.map do |field, idx|
67
+ entry.split(' ', 7).map(&:strip).each_with_index.to_h do |field, idx|
68
68
  [format_netstat_conn_headers[idx], field]
69
- end.to_h
69
+ end
70
70
  end
71
71
 
72
72
  formatted_sockets = sockets[1..].map do |entry|
73
- entry.split(' ').map(&:strip).reject(&:blank?).each_with_index.map do |field, idx|
73
+ entry.split(' ').map(&:strip).reject(&:blank?).each_with_index.to_h do |field, idx|
74
74
  [format_netstat_socket_headers[idx], field]
75
- end.to_h
75
+ end
76
76
  end
77
77
 
78
78
  {
@@ -73,6 +73,11 @@ module GreenHat
73
73
  end
74
74
  end
75
75
 
76
+ if Settings.assume_raw?
77
+ self.type = 'raw'
78
+ return true
79
+ end
80
+
76
81
  puts "Unable to determine file type for #{name.pastel(:yellow)}"
77
82
  puts "Use '#{'json'.pastel(:cyan)}' or '#{'raw'.pastel(:cyan)}' if there are no matches (see file_types.rb)"
78
83
 
@@ -1,102 +1 @@
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
1
 
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
@@ -24,8 +24,7 @@ class Thing < Teron
24
24
 
25
25
  # Preloader Flags
26
26
  field :parsed # Flag for Parsing
27
- field :result # Processed Data
28
- field :raw_result # Flag for reading raw data
27
+ field :result, dump: false # Processed Data
29
28
  field :result_fields # All available fields
30
29
 
31
30
  def friendly_name
@@ -57,10 +56,14 @@ class Thing < Teron
57
56
  result_fields
58
57
  end
59
58
 
59
+ # Readlines rather than putting whole thing into memory
60
60
  def raw
61
- raw_read if raw_result.nil?
61
+ File.foreach(file)
62
+ end
62
63
 
63
- raw_result
64
+ # Where full read is needed
65
+ def raw_full
66
+ File.read(file).split("\n")
64
67
  end
65
68
 
66
69
  # Filter / Archive Pattern Matching
@@ -73,32 +76,27 @@ class Thing < Teron
73
76
  data.blank?
74
77
  end
75
78
 
76
- def raw_read
77
- spin_start("Read #{name.pastel(:blue)} #{size.pastel(:bright_black)}")
78
- self.raw_result = File.read(file).split("\n")
79
- rescue StandardError => e
80
- LogBot.fatal('Raw Read', message: e.message, backtrace: e.backtrace.first)
81
- self.raw_result = ''
82
- ensure
83
- spin_done
84
- end
85
-
86
79
  def output(print_it = true)
87
80
  if print_it
88
- puts raw.join("\n")
81
+ puts raw.map(&:to_s).map(&:chomp)
89
82
  else
90
- raw
83
+ raw.map(&:to_s).map(&:chomp)
91
84
  end
92
85
  end
93
86
 
94
- # Log Identifier Helper
95
- def log?
96
- GreenHat::SuperLog.log? kind
87
+ # Hashed values searching
88
+ def process?
89
+ kind != :raw && methods.include?(formatter)
97
90
  end
98
91
 
99
- # Hashed values searching
100
- def processed?
101
- kind != :raw
92
+ # Things that can be queried (Query Helper)
93
+ def query?
94
+ data.instance_of?(Array)
95
+ end
96
+
97
+ # Helper for all things that can be hash/value filtered
98
+ def self.list
99
+ all.select.select(&:process?)
102
100
  end
103
101
 
104
102
  # Helper Formatter Method
@@ -107,9 +105,6 @@ class Thing < Teron
107
105
  end
108
106
 
109
107
  def process
110
- # Read First if Needed (Spinner)
111
- raw_read if raw_result.nil?
112
-
113
108
  if methods.include? formatter
114
109
  spin_start("Parse #{name.pastel(:blue)} #{kind.to_s.pastel(:bright_black)} ")
115
110
  begin
@@ -140,4 +135,15 @@ class Thing < Teron
140
135
 
141
136
  []
142
137
  end
138
+
139
+ def query_save(results, name)
140
+ self.archive = Archive.first
141
+ self.result = results
142
+ self.name = name
143
+ self.log = true
144
+ self.parsed = true
145
+ self.type = 'json'
146
+ self.result_fields = field_processing
147
+ save!
148
+ end
143
149
  end
@@ -1,3 +1,3 @@
1
1
  module GreenHat
2
- VERSION = '0.3.4'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -0,0 +1,55 @@
1
+ == slim :chart_template
2
+ .row
3
+ .chart-menu
4
+ ul.section.table-of-contents
5
+ li
6
+ a href="#top" Top
7
+ li
8
+ a href="#path" Path
9
+ li
10
+ a href="#time" Time
11
+
12
+ h3.white-text.center API
13
+
14
+ h4.col.s12.white-text.center id="top" Top
15
+ .col.s12.card.padding.z-depth-4
16
+ == bubble_chart(faststats_top('gitlab-rails/api_json.log', :project_stats), xtitle:'Duration', ytitle:'% Count', label: "Total", title: 'by Project')
17
+ .col.s12.padding
18
+ .legend X: Duration
19
+ .legend.red Y: % of total calls
20
+ .legend.blue Size: Total Calls
21
+
22
+
23
+ .col.s12.card.padding.z-depth-4
24
+ == bubble_chart(faststats_top('gitlab-rails/api_json.log', :user_stats), xtitle:'Duration', ytitle:'% Count', label: "Total", title: 'by User')
25
+ .col.s12.padding
26
+ .legend X: Duration
27
+ .legend.red Y: % of total calls
28
+ .legend.blue Size: Total Calls
29
+
30
+ .col.s12.card.padding.z-depth-4
31
+ == pie_chart(api_duration_pie, title: 'Duration Total')
32
+
33
+ h4.col.s12.white-text.center id="path" Path
34
+ .col.s12.card.padding.z-depth-4
35
+ == pie_chart(faststats_field('gitlab-rails/api_json.log', :count), title: 'Total by Path')
36
+
37
+ .col.s12.card.padding.z-depth-4
38
+ == column_chart(faststats_field('gitlab-rails/api_json.log',:p95), title: 'p95', ytitle: 'ms')
39
+
40
+ .col.s12.card.padding.z-depth-4
41
+ == column_chart(faststats_field('gitlab-rails/api_json.log',:median), title: 'Median', ytitle: 'ms')
42
+
43
+ h4.col.s12.white-text.center id="time" Over Time
44
+
45
+ .col.s12.card.padding.z-depth-4
46
+ == area_chart(api_avg_path_duration_series, title: 'Path Duration', ytitle: 'seconds')
47
+
48
+ .col.s12.card.padding.z-depth-4
49
+ == area_chart(api_avg_duration_series, title: 'Avg Duration', ytitle: 'ms')
50
+
51
+ .col.s12.card.padding.z-depth-4
52
+ == column_chart(api_duration_series_stacked, stacked: true, title: 'Duration Breakdown', ytitle: 'seconds')
53
+
54
+ .col.s12.card.padding.z-depth-4
55
+ == area_chart(api_duration_series_stacked, stacked: true, title: 'Duration Breakdown', ytitle: 'seconds')
@@ -0,0 +1,42 @@
1
+ doctype html
2
+ html
3
+ head
4
+ == slim :headers
5
+ body.grey.darken-4
6
+ == slim :css
7
+
8
+ nav.blue-grey.darken-4
9
+ .nav-wrapper
10
+ a.brand-logo.center href="/" Charts Home
11
+ ul.left.white-text
12
+ li
13
+ a href ='/'
14
+ .btn-flat.white-text
15
+ i.fa.fa-home.left.line-height
16
+ | Home
17
+
18
+ li
19
+ a href ='/chart'
20
+ .btn-flat.white-text
21
+ i.fa.fa-chart-pie.left.line-height
22
+ | Charts
23
+ li
24
+ a href ='/chart/time'
25
+ .btn-flat.white-text
26
+ i.fa.fa-chart-line.left.line-height
27
+ | Time Query
28
+
29
+ .container.padding
30
+ .row
31
+ h5.white-text.center Dashboards
32
+ .row
33
+ .col.s4.padding
34
+ a.blue.btn-large.chart-btn href="/charts/gitaly" Gitaly
35
+ .col.s4.padding
36
+ a.green.btn-large.chart-btn href="/charts/sidekiq" Sidekiq
37
+ .col.s4.padding
38
+ a.red.btn-large.chart-btn href="/charts/api" Api
39
+ .col.s4.padding
40
+ a.purple.btn-large.chart-btn href="/charts/production" Production
41
+ .col.s4.padding
42
+ a.teal.btn-large.chart-btn href="/charts/workhorse" Workhorse