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.
- checksums.yaml +4 -4
- data/bin/greenhat +1 -4
- data/lib/greenhat/accessors/disk.rb +42 -3
- data/lib/greenhat/accessors/gitlab.rb +30 -1
- data/lib/greenhat/accessors/memory.rb +1 -1
- data/lib/greenhat/archive.rb +19 -8
- data/lib/greenhat/cli.rb +24 -126
- data/lib/greenhat/entrypoint.rb +170 -0
- data/lib/greenhat/host.rb +25 -37
- data/lib/greenhat/settings.rb +6 -0
- data/lib/greenhat/shell/args.rb +22 -9
- data/lib/greenhat/shell/faststats.rb +23 -3
- data/lib/greenhat/shell/field_helper.rb +1 -1
- data/lib/greenhat/shell/filter_help.rb +232 -9
- data/lib/greenhat/shell/log.rb +153 -9
- data/lib/greenhat/shell/markdown.rb +352 -0
- data/lib/greenhat/shell/old_search_helper.rb +54 -0
- data/lib/greenhat/shell/page.rb +1 -1
- data/lib/greenhat/shell/pipe.rb +31 -0
- data/lib/greenhat/shell/platform.rb +28 -0
- data/lib/greenhat/shell/report.rb +106 -25
- data/lib/greenhat/shell/shell_helper.rb +115 -106
- data/lib/greenhat/shell.rb +10 -3
- data/lib/greenhat/thing/file_types.rb +136 -8
- data/lib/greenhat/thing/formatters/json.rb +4 -0
- data/lib/greenhat/thing/formatters/kube_json.rb +36 -0
- data/lib/greenhat/thing/formatters/kube_nginx.rb +48 -0
- data/lib/greenhat/thing/formatters/kube_webservice.rb +51 -0
- data/lib/greenhat/thing/formatters/nginx.rb +6 -2
- data/lib/greenhat/thing/formatters/registry.rb +47 -0
- data/lib/greenhat/thing/formatters/time_space.rb +0 -16
- data/lib/greenhat/thing/helpers.rb +12 -0
- data/lib/greenhat/thing/kind.rb +5 -0
- data/lib/greenhat/thing.rb +11 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat/views/api.slim +55 -0
- data/lib/greenhat/views/chart.slim +42 -0
- data/lib/greenhat/views/chart_template.slim +31 -0
- data/lib/greenhat/views/chartkick.js +21 -0
- data/lib/greenhat/views/css.slim +47 -0
- data/lib/greenhat/views/gitaly.slim +53 -0
- data/lib/greenhat/views/headers.slim +16 -0
- data/lib/greenhat/views/index-old.slim +51 -0
- data/lib/greenhat/views/index.slim +14 -14
- data/lib/greenhat/views/info.slim +17 -18
- data/lib/greenhat/views/production.slim +55 -0
- data/lib/greenhat/views/sidekiq.slim +55 -0
- data/lib/greenhat/views/time.slim +63 -0
- data/lib/greenhat/views/workhorse.slim +16 -0
- data/lib/greenhat/web/api.rb +94 -0
- data/lib/greenhat/web/chartkick_shim.rb +14 -0
- data/lib/greenhat/web/faststats.rb +44 -0
- data/lib/greenhat/web/gitaly.rb +65 -0
- data/lib/greenhat/web/helpers.rb +198 -0
- data/lib/greenhat/web/production.rb +104 -0
- data/lib/greenhat/web/sidekiq.rb +73 -0
- data/lib/greenhat/web/stats_helpers.rb +74 -0
- data/lib/greenhat/web/time.rb +36 -0
- data/lib/greenhat/web/workhorse.rb +43 -0
- data/lib/greenhat/web.rb +63 -19
- data/lib/greenhat.rb +2 -0
- metadata +78 -5
data/lib/greenhat/views/css.slim
CHANGED
@@ -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 ='
|
27
|
+
a href ='/chart'
|
28
28
|
.btn-flat.white-text
|
29
29
|
i.fa.fa-chart-pie.left.line-height
|
30
|
-
|
|
30
|
+
| Chart
|
31
31
|
|
32
32
|
|
33
33
|
.container
|
34
34
|
br
|
35
|
-
-
|
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
|
2
|
+
- if host.gitlab_version
|
3
3
|
.col.s12.entry.flow-text
|
4
4
|
.col.s4 Gitlab Version
|
5
5
|
.col.s8
|
6
|
-
=
|
6
|
+
= host.gitlab_version
|
7
7
|
|
8
|
-
|
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
|
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
|