greenhat 0.3.3 → 0.4.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/bin/greenhat +1 -4
  3. data/lib/greenhat/accessors/disk.rb +42 -3
  4. data/lib/greenhat/accessors/gitlab.rb +30 -1
  5. data/lib/greenhat/accessors/memory.rb +1 -1
  6. data/lib/greenhat/archive.rb +19 -8
  7. data/lib/greenhat/cli.rb +24 -126
  8. data/lib/greenhat/entrypoint.rb +170 -0
  9. data/lib/greenhat/host.rb +25 -37
  10. data/lib/greenhat/settings.rb +6 -0
  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 +232 -9
  15. data/lib/greenhat/shell/log.rb +153 -9
  16. data/lib/greenhat/shell/markdown.rb +352 -0
  17. data/lib/greenhat/shell/old_search_helper.rb +54 -0
  18. data/lib/greenhat/shell/page.rb +1 -1
  19. data/lib/greenhat/shell/pipe.rb +31 -0
  20. data/lib/greenhat/shell/platform.rb +28 -0
  21. data/lib/greenhat/shell/report.rb +106 -25
  22. data/lib/greenhat/shell/shell_helper.rb +115 -106
  23. data/lib/greenhat/shell.rb +10 -3
  24. data/lib/greenhat/thing/file_types.rb +136 -8
  25. data/lib/greenhat/thing/formatters/json.rb +4 -0
  26. data/lib/greenhat/thing/formatters/kube_json.rb +36 -0
  27. data/lib/greenhat/thing/formatters/kube_nginx.rb +48 -0
  28. data/lib/greenhat/thing/formatters/kube_webservice.rb +51 -0
  29. data/lib/greenhat/thing/formatters/nginx.rb +6 -2
  30. data/lib/greenhat/thing/formatters/registry.rb +47 -0
  31. data/lib/greenhat/thing/formatters/time_space.rb +0 -16
  32. data/lib/greenhat/thing/helpers.rb +12 -0
  33. data/lib/greenhat/thing/kind.rb +5 -0
  34. data/lib/greenhat/thing.rb +11 -0
  35. data/lib/greenhat/version.rb +1 -1
  36. data/lib/greenhat/views/api.slim +55 -0
  37. data/lib/greenhat/views/chart.slim +42 -0
  38. data/lib/greenhat/views/chart_template.slim +31 -0
  39. data/lib/greenhat/views/chartkick.js +21 -0
  40. data/lib/greenhat/views/css.slim +47 -0
  41. data/lib/greenhat/views/gitaly.slim +53 -0
  42. data/lib/greenhat/views/headers.slim +16 -0
  43. data/lib/greenhat/views/index-old.slim +51 -0
  44. data/lib/greenhat/views/index.slim +14 -14
  45. data/lib/greenhat/views/info.slim +17 -18
  46. data/lib/greenhat/views/production.slim +55 -0
  47. data/lib/greenhat/views/sidekiq.slim +55 -0
  48. data/lib/greenhat/views/time.slim +63 -0
  49. data/lib/greenhat/views/workhorse.slim +16 -0
  50. data/lib/greenhat/web/api.rb +94 -0
  51. data/lib/greenhat/web/chartkick_shim.rb +14 -0
  52. data/lib/greenhat/web/faststats.rb +44 -0
  53. data/lib/greenhat/web/gitaly.rb +65 -0
  54. data/lib/greenhat/web/helpers.rb +198 -0
  55. data/lib/greenhat/web/production.rb +104 -0
  56. data/lib/greenhat/web/sidekiq.rb +73 -0
  57. data/lib/greenhat/web/stats_helpers.rb +74 -0
  58. data/lib/greenhat/web/time.rb +36 -0
  59. data/lib/greenhat/web/workhorse.rb +43 -0
  60. data/lib/greenhat/web.rb +63 -19
  61. data/lib/greenhat.rb +2 -0
  62. metadata +78 -5
@@ -11,6 +11,15 @@ css:
11
11
  .padding {
12
12
  padding: 10px !important;
13
13
  }
14
+
15
+ .margin {
16
+ margin: 10px;
17
+ }
18
+
19
+ .round {
20
+ border-radius: 2px;
21
+ }
22
+
14
23
 
15
24
  .line-height {
16
25
  line-height: inherit !important;
@@ -124,3 +133,41 @@ css:
124
133
  justify-content: left;
125
134
  flex-wrap: wrap;
126
135
  }
136
+
137
+ .chart-input {
138
+ margin: 10px;
139
+ border-radius: 3px;
140
+ padding: 15px;
141
+ background: rgb(60,60,60)
142
+ }
143
+
144
+ .text-right {
145
+ text-align: right
146
+ }
147
+
148
+ .chart-btn {
149
+ width: 100%;
150
+ font-size: 1.5rem;
151
+ }
152
+
153
+ .chart-menu {
154
+ position: fixed;
155
+ right: 5%;
156
+ top: 70px;
157
+ }
158
+
159
+ .legend {
160
+ font-weight: 300;
161
+ font-size: 0.8rem;
162
+ color: #fff;
163
+ background-color: #26a69a;
164
+ border-radius: 2px;
165
+ min-width: 3rem;
166
+ padding: 0 6px;
167
+ margin-left: 14px;
168
+ text-align: center;
169
+ line-height: 22px;
170
+ height: 22px;
171
+ float: right;
172
+ box-sizing: border-box;
173
+ }
@@ -0,0 +1,53 @@
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="#method" Method
9
+ li
10
+ a href="#time" Time
11
+
12
+ h3.white-text.center Gitaly
13
+
14
+ h4.col.s12.white-text.center id="top" Top
15
+ .col.s12.card.padding.z-depth-4
16
+ == bubble_chart(faststats_top('gitaly/current', :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
+ .col.s12.card.padding.z-depth-4
23
+ == bubble_chart(faststats_top('gitaly/current', :user_stats), xtitle:'Duration', ytitle:'% Count', label: "Total", title: 'by User')
24
+ .col.s12.padding
25
+ .legend X: Duration
26
+ .legend.red Y: % of total calls
27
+ .legend.blue Size: Total Calls
28
+
29
+ .col.s12.card.padding.z-depth-4
30
+ == bubble_chart(faststats_top('gitaly/current', :client_stats), xtitle:'Duration', ytitle:'% Count', label: "Total", title: 'by Client')
31
+ .col.s12.padding
32
+ .legend X: Duration
33
+ .legend.red Y: % of total calls
34
+ .legend.blue Size: Total Calls
35
+
36
+ h4.col.s12.white-text.center id="method" Method
37
+ .col.s12.card.padding.z-depth-4
38
+ == pie_chart(faststats_field('gitaly/current', :count), title: 'Total Request Count')
39
+ .col.s12.card.padding.z-depth-4
40
+ == column_chart(faststats_field('gitaly/current', :p95), title: 'p95')
41
+ .col.s12.card.padding.z-depth-4
42
+ == column_chart(faststats_field('gitaly/current', :median), title: 'Median')
43
+
44
+ h4.col.s12.white-text.center id="time" Over Time
45
+
46
+ .col.s12.card.padding.z-depth-4
47
+ == area_chart(gitaly_duration, title: 'Duration', ytitle: 'ms')
48
+
49
+ .col.s12.card.padding.z-depth-4
50
+ == area_chart(gitaly_avg_method_series, title: 'Avg Method Duration')
51
+
52
+ .col.s12.card.padding.z-depth-4
53
+ == column_chart(gitaly_errors_series, title: 'Errors by Method')
@@ -0,0 +1,16 @@
1
+ title SOS Display
2
+ meta content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" name="viewport"
3
+
4
+ // Materialize
5
+ link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet"
6
+ script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"
7
+
8
+ script src="https://code.jquery.com/jquery-2.2.4.min.js"
9
+
10
+ link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" rel="stylesheet"
11
+
12
+ // Data tables
13
+ script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"
14
+ link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"
15
+
16
+ script src="/chart/chartkick.js"
@@ -0,0 +1,51 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title SOS Display
5
+ meta content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" name="viewport"
6
+
7
+ // Materialize
8
+ link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet"
9
+ script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"
10
+
11
+ script src="https://code.jquery.com/jquery-2.2.4.min.js"
12
+
13
+ link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" rel="stylesheet"
14
+
15
+ // Data tables
16
+ script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"
17
+ link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"
18
+
19
+ body
20
+ == slim :css
21
+
22
+ nav.green
23
+ .nav-wrapper
24
+ a.brand-logo.center href="/" Greenhat
25
+ ul.left.white-text
26
+ li
27
+ a href ='http://localhost:5601/app/kibana' target="_blank"
28
+ .btn-flat.white-text
29
+ i.fa.fa-chart-pie.left.line-height
30
+ | Kibana
31
+
32
+
33
+ .container
34
+ br
35
+ - hosts.each do |host|
36
+ // Host Container
37
+ .row.blue.white-text.mid.card
38
+ i.fab.fa-lg.left.line-height class=host.icon
39
+ .flow-text = host.archive_name
40
+
41
+ // Host Info
42
+ == slim :info, host
43
+
44
+ // Other Templates
45
+ == slim :memory, host
46
+ == slim :disk_free, host
47
+ == slim :netstat, host
48
+ == slim :manifest, host
49
+ == slim :process, host
50
+ == slim :ulimit, host
51
+ == slim :systemctl, host
@@ -24,28 +24,28 @@ html
24
24
  a.brand-logo.center href="/" Greenhat
25
25
  ul.left.white-text
26
26
  li
27
- a href ='http://localhost:5601/app/kibana' target="_blank"
27
+ a href ='/chart'
28
28
  .btn-flat.white-text
29
29
  i.fa.fa-chart-pie.left.line-height
30
- | Kibana
30
+ | Chart
31
31
 
32
32
 
33
33
  .container
34
34
  br
35
- - hosts.each do |host|
35
+ - Host.all.each do |host|
36
36
  // Host Container
37
37
  .row.blue.white-text.mid.card
38
38
  i.fab.fa-lg.left.line-height class=host.icon
39
39
  .flow-text = host.archive_name
40
40
 
41
- // Host Info
42
- == slim :info, host
43
-
44
- // Other Templates
45
- == slim :memory, host
46
- == slim :disk_free, host
47
- == slim :netstat, host
48
- == slim :manifest, host
49
- == slim :process, host
50
- == slim :ulimit, host
51
- == slim :systemctl, host
41
+ / // Host Info
42
+ == slim :info, locals: { host: host }
43
+
44
+ / // Other Templates
45
+ / == slim :memory, host
46
+ / == slim :disk_free, host
47
+ / == slim :netstat, host
48
+ / == slim :manifest, host
49
+ / == slim :process, host
50
+ / == slim :ulimit, host
51
+ / == slim :systemctl, host
@@ -1,15 +1,16 @@
1
1
  .row.striped.card
2
- - if manifest
2
+ - if host.gitlab_version
3
3
  .col.s12.entry.flow-text
4
4
  .col.s4 Gitlab Version
5
5
  .col.s8
6
- = manifest.build_version
6
+ = host.gitlab_version
7
7
 
8
- - if uptime
8
+
9
+ - if host.uptime
9
10
  .col.s12.entry
10
11
  .col.s4.aligner style='height:50px;' Uptime
11
12
  .col.s8.aligner
12
- - uptime.each do |data|
13
+ - host.uptime.each do |data|
13
14
  - if data.include? 'load average'
14
15
  - data.split(':').each do |line|
15
16
  .col.s4 = line
@@ -17,23 +18,21 @@
17
18
  = data
18
19
 
19
20
  .col.s12.entry.aligner.padding
20
- - if cpuinfo
21
+ - if host.cpuinfo
21
22
  .bubble
22
23
  span.green.bubble-left CPU Count
23
- span.blue.bubble-right = cpuinfo.count
24
-
25
- - if total_memory
26
- .bubble
27
- span.green.bubble-left Total Memory
28
- span.blue.bubble-right = total_memory
29
-
30
- - if cpu_speed
31
- .bubble
32
- span.green.bubble-left = cpu_speed.first
33
- span.blue.bubble-right = cpu_speed.last.to_i
24
+ span.blue.bubble-right = host.cpuinfo['CPU(s)']
34
25
 
26
+ / - if host.total_memory
27
+ / .bubble
28
+ / span.green.bubble-left Total Memory
29
+ / span.blue.bubble-right = total_memory
35
30
 
31
+ / - if host.cpu_speed
32
+ / .bubble
33
+ / span.green.bubble-left = cpu_speed.first
34
+ / span.blue.bubble-right = cpu_speed.last.to_i
36
35
 
37
- - if uname
36
+ - if host.uname
38
37
  .col.s12.entry
39
- small = uname
38
+ small = host.uname
@@ -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 Production
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/production_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/production_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(prod_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/production_json.log', :count), title: 'Total by Path')
36
+
37
+ .col.s12.card.padding.z-depth-4
38
+ == column_chart(faststats_field('gitlab-rails/production_json.log',:p95), title: 'p95', ytitle: 'ms')
39
+
40
+ .col.s12.card.padding.z-depth-4
41
+ == column_chart(faststats_field('gitlab-rails/production_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(prod_status_series, title: 'By Status', ytitle: 'Total')
47
+
48
+ .col.s12.card.padding.z-depth-4
49
+ == area_chart(prod_duration_series, title: 'Duration', ytitle: 'ms')
50
+
51
+ .col.s12.card.padding.z-depth-4
52
+ == column_chart(prod_duration_series_stacked, stacked: true, title: 'Duration Breakdown', ytitle: 'seconds')
53
+
54
+ .col.s12.card.padding.z-depth-4
55
+ == area_chart(prod_duration_series_stacked, stacked: true, title: 'Duration Breakdown', ytitle: 'seconds')
@@ -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="#worker" Worker
9
+ li
10
+ a href="#time" Time
11
+
12
+ h3.white-text.center Sidekiq
13
+
14
+ h4.col.s12.white-text.center id="top" Top
15
+ .col.s12.card.padding.z-depth-4
16
+ == bubble_chart(faststats_top('sidekiq/current', :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('sidekiq/current', :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
+
31
+ h4.col.s12.white-text.center id="worker" Worker
32
+ .col.s12.card.padding.z-depth-4
33
+ == pie_chart(faststats_field('sidekiq/current', :count), title: 'Total Jobs')
34
+
35
+ .col.s12.card.padding.z-depth-4
36
+ == column_chart(faststats_field('sidekiq/current',:p95), title: 'p95', ytitle: 'ms')
37
+
38
+ .col.s12.card.padding.z-depth-4
39
+ == column_chart(faststats_field('sidekiq/current',:median), title: 'Median', ytitle: 'ms')
40
+
41
+
42
+
43
+ h4.col.s12.white-text.center id="time" Over Time
44
+
45
+ .col.s12.card.padding.z-depth-4
46
+ == column_chart(sidekiq_errors_series, title: 'Job Errors')
47
+
48
+ .col.s12.card.padding.z-depth-4
49
+ == area_chart(sidekiq_duration, title: 'Job Duration', ytitle: 'seconds')
50
+
51
+ .col.s12.card.padding.z-depth-4
52
+ == area_chart(sidekiq_avg_duration_series, title: 'Job Duration by Class', ytitle: 'seconds')
53
+
54
+ .col.s12.card.padding.z-depth-4
55
+ == area_chart(sidekiq_job_latency, title: 'Scheduling Latency Total', ytitle: 'Latency Seconds')
@@ -0,0 +1,63 @@
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="/chart" Chart
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
+ | Dashboard
23
+
24
+ .container.padding
25
+ .row
26
+ form.col.s12
27
+ .row
28
+ .col.s12.z-depth-2.chart-input
29
+ .input-field
30
+ input.center.white-text placeholder="nginx --status=500" name='query' type='text' value='#{params[:query]}'
31
+ label for="query" Query
32
+
33
+ .row
34
+ .col.s4
35
+ .chart-input.z-depth-2
36
+ .input-field
37
+ input.white-text.center placeholder="5" name='interval' type='number' value='#{params[:interval] || 5 }' min="1" max="60"
38
+ label for="interval" Interval (Minutes)
39
+
40
+ .col.s4
41
+ .chart-input.z-depth-2
42
+ .input-field
43
+ input.white-text.center name='group' type='text' value='#{params[:group]}'
44
+ label for="group" Group
45
+
46
+ .col.s4
47
+ .chart-input.z-depth-2
48
+ .input-field
49
+ input.white-text.center name='avg' type='text' value='#{params[:avg]}'
50
+ label for="avg" Avg
51
+
52
+ .row
53
+ .input-field.col.s12.center
54
+ button.btn.waves-effect.waves-light type="submit" Go
55
+
56
+ .row
57
+ .col.s12.card.padding.z-depth-4
58
+ == area_chart @index
59
+
60
+ .row
61
+ .col.s12.card.padding.z-depth-4
62
+ == column_chart @index
63
+
@@ -0,0 +1,16 @@
1
+ == slim :chart_template
2
+ .row
3
+
4
+ h3.white-text.center Workhorse
5
+
6
+ .col.s12.card.padding.z-depth-4
7
+ == area_chart(workhorse_request_total, title: 'Request by Status', ytitle: 'Count')
8
+
9
+ .col.s12.card.padding.z-depth-4
10
+ == area_chart(workhorse_duration, title: 'Request Duration', ytitle: 'ms')
11
+
12
+
13
+ .col.s12.card.padding.z-depth-4
14
+ == pie_chart(workhorse_client_total, title: 'Top User Agent')
15
+
16
+
@@ -0,0 +1,94 @@
1
+ # General Web Helper
2
+ module WebHelpers
3
+ # ======================================================
4
+ # == [ API ]
5
+ # ======================================================
6
+ def api_avg_path_duration_series
7
+ query = [
8
+ 'gitlab-rails/api_json.log',
9
+ '--slice=time,path,duration_s'
10
+ ].join(' ')
11
+
12
+ results = GreenHat::ShellHelper.filter_internal(query)
13
+
14
+ method_key = :path
15
+ duration_key = :duration_s
16
+
17
+ # Collect Total by Duration
18
+ top = results.each_with_object({}) do |v, obj|
19
+ obj[v[method_key]] ||= []
20
+ obj[v[method_key]] << v[duration_key]
21
+
22
+ obj
23
+ end
24
+
25
+ # Average / Round
26
+ top.transform_values! { |x| (x.sum / x.size.to_f).round(1) }
27
+
28
+ # Only top by duration
29
+ method_calls = top_method_calls(top)
30
+ results.select! { |x| method_calls.any? x[method_key] }
31
+
32
+ build_group_time_avg(results, method_key, duration_key) # 5 Minutes
33
+ end
34
+
35
+ def api_avg_duration_series
36
+ query = [
37
+ 'gitlab-rails/api_json.log',
38
+ '--slice=time,path,duration_s',
39
+ '--exists=duration_s',
40
+ '--duration_s!=0',
41
+ '--exact'
42
+ ].join(' ')
43
+
44
+ results = GreenHat::ShellHelper.filter_internal(query)
45
+
46
+ # MS is hard
47
+ results.each do |r|
48
+ r[:duration_s] = r[:duration_s] * 1000
49
+ end
50
+
51
+ build_percentile_list(results, :duration_s)
52
+
53
+ # build_time_avg(results, :duration_s).transform_values { |x| x.round(1) }
54
+ end
55
+
56
+ def api_duration_series_stacked
57
+ stacks = %i[
58
+ redis_duration_s
59
+ view_duration_s
60
+ gitaly_duration_s
61
+ redis_cache_duration_s
62
+ duration_s
63
+ db_duration_s
64
+ redis_shared_state_duration_s
65
+ queue_duration_s
66
+ db_duration_s
67
+ ]
68
+
69
+ query = [
70
+ 'gitlab-rails/api_json.log',
71
+ "--slice=time,path,#{stacks.join(',')}"
72
+ ].join(' ')
73
+
74
+ results = GreenHat::ShellHelper.filter_internal(query)
75
+ output = build_stack_time_avg(results, stacks)
76
+
77
+ # MS are hard
78
+ output.each do |dataset|
79
+ dataset[:data].transform_values! { |x| (x * 1000).round(1) }
80
+ end
81
+
82
+ output
83
+ end
84
+
85
+ def api_duration_pie
86
+ all = faststats_run('gitlab-rails/api_json.log', 'top')[:totals]
87
+
88
+ # Grab Specifics
89
+ totals = all.except(:count, :fails).transform_values(&:round)
90
+
91
+ # Organize
92
+ totals.sort_by(&:last).reverse.to_h
93
+ end
94
+ end
@@ -0,0 +1,14 @@
1
+ # Shim
2
+ module Chartkick
3
+ class << self
4
+ attr_accessor :content_for, :options
5
+ end
6
+ self.options = {}
7
+
8
+ # Shim Chart Types
9
+ module Helper
10
+ def bubble_chart(data_source, options = {})
11
+ chartkick_chart 'BubbleChart', data_source, options
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,44 @@
1
+ # Fast Stat Helpers
2
+ module WebHelpers
3
+ def faststats_field(file, field = :count)
4
+ results = faststats_run(file).stats[0..10].map do |x|
5
+ [x[:prim_field], x[field]]
6
+ end
7
+
8
+ # Sort and Round
9
+ results = results.sort_by(&:last).reverse.to_h
10
+ results.transform_values! { |v| v.round(1) }
11
+
12
+ results
13
+ end
14
+
15
+ def faststats_run(file = 'sidekiq/current', cmd = '')
16
+ GreenHat::ShellHelper::Faststats.run(Thing.find_by(type: file), cmd)
17
+ end
18
+
19
+ def faststats_top(file = 'sidekiq/current', kind = :project_stats)
20
+ thing = Thing.find_by(type: file)
21
+ results = GreenHat::ShellHelper::Faststats.run(thing, 'top')
22
+
23
+ # -------------------------------------------------------
24
+ # Calculate Total and Percentages
25
+ list = results.dig(kind, :stats).sort_by { |_k, v| v[:duration] }.to_h
26
+ count = list.values.sum { |x| x[:count] }
27
+ # duration = list.values.sum { |x| x[:duration] }
28
+ # -------------------------------------------------------
29
+
30
+ # Handle Short Results
31
+ top = results.dig(kind, :stats).sort_by { |_k, v| v[:duration] }
32
+ top = top.size >= 10 ? top[-10..] : top
33
+
34
+ top.to_h.map do |k, v|
35
+ count_perc = percent(v[:count], count)
36
+ {
37
+ name: k,
38
+ data: [
39
+ [v[:duration].round, count_perc, v[:count]]
40
+ ]
41
+ }
42
+ end
43
+ end
44
+ end