activeinsights 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/active_insights/application_controller.rb +5 -1
- data/app/controllers/active_insights/jobs_controller.rb +13 -0
- data/app/controllers/active_insights/jobs_latencies_controller.rb +22 -0
- data/app/controllers/active_insights/jobs_p_values_controller.rb +33 -0
- data/app/controllers/active_insights/jpm_controller.rb +17 -0
- data/app/controllers/active_insights/requests_controller.rb +1 -1
- data/app/controllers/active_insights/requests_p_values_controller.rb +35 -0
- data/app/controllers/active_insights/rpm_controller.rb +1 -1
- data/app/helpers/active_insights/application_helper.rb +2 -3
- data/app/models/active_insights/job.rb +16 -0
- data/app/models/active_insights/record.rb +75 -0
- data/app/models/active_insights/request.rb +6 -70
- data/app/views/active_insights/jobs/index.html.erb +65 -0
- data/app/views/active_insights/jobs_latencies/index.html.erb +27 -0
- data/app/views/active_insights/{p_values → jobs_p_values}/index.html.erb +9 -3
- data/app/views/active_insights/jpm/index.html.erb +26 -0
- data/app/views/active_insights/requests/index.html.erb +11 -7
- data/app/views/active_insights/{controller_p_values → requests_p_values}/index.html.erb +9 -3
- data/app/views/active_insights/rpm/index.html.erb +1 -1
- data/app/views/layouts/active_insights/application.html.erb +22 -0
- data/config/initializers/importmap.rb +0 -2
- data/config/routes.rb +25 -6
- data/db/migrate/{20240111225806_active_insights_request.rb → 20240111225806_create_active_insights_tables.rb} +19 -1
- data/lib/active_insights/engine.rb +11 -10
- data/lib/active_insights/seeders/jobs.rb +81 -0
- data/lib/active_insights/{seeder.rb → seeders/requests.rb} +3 -1
- data/lib/active_insights/version.rb +1 -1
- metadata +16 -11
- data/app/assets/javascripts/active_insights/application.js +0 -13
- data/app/controllers/active_insights/controller_p_values_controller.rb +0 -24
- data/app/controllers/active_insights/p_values_controller.rb +0 -21
- data/vendor/javascript/chart.js.js +0 -10
- data/vendor/javascript/chartkick.js +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e24234a0d53a68ad07e1149dc56d83b9f75ae2301de4cfe15f3990334fe2966b
|
4
|
+
data.tar.gz: b4f0bff96dcea5a9de9f082946c8764c48c59db27882ae491c9f2b51a7a534c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63cd5d499220b4d50a240468213f17b08a7b130c3df71c4fb9be1c2f25b16820c67c2d121a6b490baf7326f6a10dd9bbea4e04d12e30b4909c6998b1c10ad12c
|
7
|
+
data.tar.gz: 763484678c65f1616798c6f633b70f481cd7a6cb20a14dbae0bd1c1aaa870a5886baff0b1c84de23c208e9b1fa72bb98124d1cfced7febdafe5814f5cc754c7d
|
@@ -25,7 +25,7 @@ module ActiveInsights
|
|
25
25
|
end.beginning_of_day
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def base_request_scope
|
29
29
|
scope = ActiveInsights::Request.where(started_at: @date)
|
30
30
|
if ActiveInsights.ignored_endpoints.present?
|
31
31
|
scope = scope.where.
|
@@ -33,5 +33,9 @@ module ActiveInsights
|
|
33
33
|
end
|
34
34
|
scope
|
35
35
|
end
|
36
|
+
|
37
|
+
def base_jobs_scope
|
38
|
+
ActiveInsights::Job.where(started_at: @date)
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class JobsController < ApplicationController
|
5
|
+
def index
|
6
|
+
@jobs = base_jobs_scope.with_durations.select(:job, :queue).
|
7
|
+
group(:job, :queue).sort_by(&:agony).reverse
|
8
|
+
|
9
|
+
@latency =
|
10
|
+
base_jobs_scope.select("AVG(queue_time) as latency").to_a.first.latency
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class JobsLatenciesController < ApplicationController
|
5
|
+
def index
|
6
|
+
@latencies = minutes.map do |minute|
|
7
|
+
[minute.pretty_started_at, minute.latency.round(1)]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def redirection
|
12
|
+
redirect_to jobs_latency_path(params[:date])
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def minutes
|
18
|
+
@minutes ||= base_jobs_scope.minute_by_minute.select_started_at.
|
19
|
+
select("AVG(queue_time) as latency")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class JobsPValuesController < ApplicationController
|
5
|
+
def index
|
6
|
+
@p50 = minutes.map{ |minute| [minute.pretty_started_at, minute.p50] }
|
7
|
+
@p95 = minutes.map{ |minute| [minute.pretty_started_at, minute.p95] }
|
8
|
+
@p99 = minutes.map{ |minute| [minute.pretty_started_at, minute.p99] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def redirection
|
12
|
+
if job.present?
|
13
|
+
redirect_to job_p_values_path(params[:date], job)
|
14
|
+
else
|
15
|
+
redirect_to jobs_p_values_path(params[:date])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def minutes
|
22
|
+
@minutes ||= begin
|
23
|
+
scope = base_jobs_scope.minute_by_minute.with_durations
|
24
|
+
scope = scope.where(job:) if job.present?
|
25
|
+
scope.select_started_at
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def job
|
30
|
+
params[:job].presence
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class JpmController < ApplicationController
|
5
|
+
def index
|
6
|
+
@minutes =
|
7
|
+
base_jobs_scope.minute_by_minute.select("COUNT(id) AS jpm").
|
8
|
+
select_started_at.map do |minute|
|
9
|
+
[minute.started_at.strftime("%-l:%M%P"), minute.jpm]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def redirection
|
14
|
+
redirect_to jpm_path(params[:date])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,7 +4,7 @@ module ActiveInsights
|
|
4
4
|
class RequestsController < ApplicationController
|
5
5
|
def index
|
6
6
|
@requests =
|
7
|
-
|
7
|
+
base_request_scope.with_durations.select(:formatted_controller).
|
8
8
|
group(:formatted_controller).sort_by(&:agony).reverse
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class RequestsPValuesController < ApplicationController
|
5
|
+
def index
|
6
|
+
@p50 = minutes.map{ |minute| [minute.pretty_started_at, minute.p50] }
|
7
|
+
@p95 = minutes.map{ |minute| [minute.pretty_started_at, minute.p95] }
|
8
|
+
@p99 = minutes.map{ |minute| [minute.pretty_started_at, minute.p99] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def redirection
|
12
|
+
if formatted_controller.present?
|
13
|
+
redirect_to controller_p_values_path(params[:date],
|
14
|
+
formatted_controller)
|
15
|
+
else
|
16
|
+
redirect_to requests_p_values_path(params[:date])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def minutes
|
23
|
+
@minutes ||= begin
|
24
|
+
scope = base_request_scope.minute_by_minute.with_durations
|
25
|
+
scope = scope.where(formatted_controller:) if
|
26
|
+
formatted_controller.present?
|
27
|
+
scope.select_started_at
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def formatted_controller
|
32
|
+
params[:formatted_controller].presence
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -4,7 +4,7 @@ module ActiveInsights
|
|
4
4
|
class RpmController < ApplicationController
|
5
5
|
def index
|
6
6
|
@minutes =
|
7
|
-
|
7
|
+
base_request_scope.minute_by_minute.select("COUNT(id) AS rpm").
|
8
8
|
select_started_at.map do |minute|
|
9
9
|
[minute.started_at.strftime("%-l:%M%P"), minute.rpm]
|
10
10
|
end
|
@@ -2,13 +2,12 @@
|
|
2
2
|
|
3
3
|
module ActiveInsights
|
4
4
|
module ApplicationHelper
|
5
|
-
def active_insights_importmap_tags
|
5
|
+
def active_insights_importmap_tags
|
6
6
|
importmap = ActiveInsights::Engine.importmap
|
7
7
|
|
8
8
|
safe_join [
|
9
9
|
javascript_inline_importmap_tag(importmap.to_json(resolver: self)),
|
10
10
|
javascript_importmap_module_preload_tags(importmap),
|
11
|
-
javascript_import_module_tag(entry_point)
|
12
11
|
], "\n"
|
13
12
|
end
|
14
13
|
|
@@ -33,7 +32,7 @@ module ActiveInsights
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def per_minute(amount, duration)
|
36
|
-
(amount / duration.in_minutes).round(
|
35
|
+
(amount / duration.in_minutes).round(1)
|
37
36
|
end
|
38
37
|
|
39
38
|
private
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInsights
|
4
|
+
class Job < ::ActiveInsights::Record
|
5
|
+
def self.setup(started, finished, unique_id, payload)
|
6
|
+
create!(started_at: started, finished_at: finished, uuid: unique_id,
|
7
|
+
db_runtime: payload[:db_runtime], job: payload[:job].class.to_s,
|
8
|
+
queue: payload[:job].queue_name,
|
9
|
+
scheduled_at: payload[:job].scheduled_at)
|
10
|
+
end
|
11
|
+
|
12
|
+
before_validation do
|
13
|
+
self.queue_time ||= (started_at - scheduled_at) * 1000.0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -5,5 +5,80 @@ module ActiveInsights
|
|
5
5
|
self.abstract_class = true
|
6
6
|
|
7
7
|
connects_to(**ActiveInsights.connects_to) if ActiveInsights.connects_to
|
8
|
+
|
9
|
+
scope :with_durations, lambda {
|
10
|
+
case connection.adapter_name
|
11
|
+
when "SQLite"
|
12
|
+
select("JSON_GROUP_ARRAY(duration) AS durations")
|
13
|
+
when "Mysql2", "Mysql2Spatial", "Mysql2Rgeo", "Trilogy"
|
14
|
+
select("JSON_ARRAYAGG(duration) AS durations")
|
15
|
+
when "PostgreSQL"
|
16
|
+
select("JSON_AGG(duration) AS durations")
|
17
|
+
end
|
18
|
+
}
|
19
|
+
scope :minute_by_minute, lambda {
|
20
|
+
case connection.adapter_name
|
21
|
+
when "SQLite"
|
22
|
+
group("strftime('%Y-%m-%d %H:%M:00 UTC', " \
|
23
|
+
"'#{table_name}'.'started_at')")
|
24
|
+
when "Mysql2", "Mysql2Spatial", "Mysql2Rgeo", "Trilogy"
|
25
|
+
group("CONVERT_TZ(DATE_FORMAT(`#{table_name}`.`started_at`" \
|
26
|
+
", '%Y-%m-%d %H:%i:00'), 'Etc/UTC', '+00:00')")
|
27
|
+
when "PostgreSQL"
|
28
|
+
group("DATE_TRUNC('minute', \"#{table_name}\"." \
|
29
|
+
"\"started_at\"::timestamptz AT TIME ZONE 'Etc/UTC') " \
|
30
|
+
"AT TIME ZONE 'Etc/UTC'")
|
31
|
+
end
|
32
|
+
}
|
33
|
+
scope :select_started_at, lambda {
|
34
|
+
case connection.adapter_name
|
35
|
+
when "SQLite", "Mysql2", "Mysql2Spatial", "Mysql2Rgeo", "Trilogy"
|
36
|
+
select(:started_at)
|
37
|
+
when "PostgreSQL"
|
38
|
+
select("DATE_TRUNC('minute', \"#{table_name}\"." \
|
39
|
+
"\"started_at\"::timestamptz AT TIME ZONE 'Etc/UTC') " \
|
40
|
+
"AT TIME ZONE 'Etc/UTC' as started_at")
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
before_validation do
|
45
|
+
self.duration ||= (finished_at - started_at) * 1000.0
|
46
|
+
end
|
47
|
+
|
48
|
+
def agony
|
49
|
+
parsed_durations.sum
|
50
|
+
end
|
51
|
+
|
52
|
+
def parsed_durations
|
53
|
+
return unless respond_to?(:durations)
|
54
|
+
|
55
|
+
@parsed_durations ||=
|
56
|
+
if durations.is_a?(Array) then durations
|
57
|
+
else
|
58
|
+
JSON.parse(durations)
|
59
|
+
end.sort
|
60
|
+
end
|
61
|
+
|
62
|
+
def pretty_started_at
|
63
|
+
started_at.strftime("%-l:%M%P")
|
64
|
+
end
|
65
|
+
|
66
|
+
def p50
|
67
|
+
percentile_value(0.5)
|
68
|
+
end
|
69
|
+
|
70
|
+
def p95
|
71
|
+
percentile_value(0.95)
|
72
|
+
end
|
73
|
+
|
74
|
+
def p99
|
75
|
+
percentile_value(0.99)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def percentile_value(percentile)
|
81
|
+
parsed_durations[(percentile * parsed_durations.size).ceil - 1].round(1)
|
82
|
+
end
|
8
83
|
end
|
9
84
|
end
|
@@ -2,76 +2,12 @@
|
|
2
2
|
|
3
3
|
module ActiveInsights
|
4
4
|
class Request < ::ActiveInsights::Record
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
when "PostgreSQL"
|
12
|
-
select("JSON_AGG(duration) AS durations")
|
13
|
-
end
|
14
|
-
}
|
15
|
-
scope :minute_by_minute, lambda {
|
16
|
-
case connection.adapter_name
|
17
|
-
when "SQLite"
|
18
|
-
group("strftime('%Y-%m-%d %H:%M:00 UTC', " \
|
19
|
-
"'active_insights_requests'.'started_at')")
|
20
|
-
when "Mysql2", "Mysql2Spatial", "Mysql2Rgeo", "Trilogy"
|
21
|
-
group("CONVERT_TZ(DATE_FORMAT(`active_insights_requests`.`started_at`" \
|
22
|
-
", '%Y-%m-%d %H:%i:00'), 'Etc/UTC', '+00:00')")
|
23
|
-
when "PostgreSQL"
|
24
|
-
group("DATE_TRUNC('minute', \"active_insights_requests\"." \
|
25
|
-
"\"started_at\"::timestamptz AT TIME ZONE 'Etc/UTC') " \
|
26
|
-
"AT TIME ZONE 'Etc/UTC'")
|
27
|
-
end
|
28
|
-
}
|
29
|
-
scope :select_started_at, lambda {
|
30
|
-
case connection.adapter_name
|
31
|
-
when "SQLite", "Mysql2", "Mysql2Spatial", "Mysql2Rgeo", "Trilogy"
|
32
|
-
select(:started_at)
|
33
|
-
when "PostgreSQL"
|
34
|
-
select("DATE_TRUNC('minute', \"active_insights_requests\"." \
|
35
|
-
"\"started_at\"::timestamptz AT TIME ZONE 'Etc/UTC') " \
|
36
|
-
"AT TIME ZONE 'Etc/UTC' as started_at")
|
37
|
-
end
|
38
|
-
}
|
39
|
-
|
40
|
-
def agony
|
41
|
-
parsed_durations.sum
|
42
|
-
end
|
43
|
-
|
44
|
-
def parsed_durations
|
45
|
-
return unless respond_to?(:durations)
|
46
|
-
|
47
|
-
@parsed_durations ||=
|
48
|
-
if durations.is_a?(Array) then durations
|
49
|
-
else
|
50
|
-
JSON.parse(durations)
|
51
|
-
end.sort
|
52
|
-
end
|
53
|
-
|
54
|
-
def pretty_started_at
|
55
|
-
started_at.strftime("%-l:%M%P")
|
56
|
-
end
|
57
|
-
|
58
|
-
def p50
|
59
|
-
percentile_value(0.5)
|
5
|
+
def self.setup(started, finished, unique_id, payload)
|
6
|
+
create!(started_at: started, finished_at: finished, uuid: unique_id,
|
7
|
+
http_method: payload[:method], **payload.slice(
|
8
|
+
:controller, :action, :format, :status, :view_runtime,
|
9
|
+
:db_runtime
|
10
|
+
))
|
60
11
|
end
|
61
|
-
|
62
|
-
def p95
|
63
|
-
percentile_value(0.95)
|
64
|
-
end
|
65
|
-
|
66
|
-
def p99
|
67
|
-
percentile_value(0.99)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def percentile_value(percentile)
|
73
|
-
parsed_durations[(percentile * parsed_durations.size).ceil - 1].round(1)
|
74
|
-
end
|
75
|
-
|
76
12
|
end
|
77
13
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<header>
|
2
|
+
<h1>Metrics for <%= display_date(@date.first) %></h1>
|
3
|
+
<div class="flex flex-row items-center">
|
4
|
+
<%= link_to "View request metrics", active_insights.requests_path, class: "white mr-15px" %>
|
5
|
+
|
6
|
+
<%= form_with url: active_insights.jobs_path, method: :get do |f| %>
|
7
|
+
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
8
|
+
<% f.submit "submit", class: "hidden" %>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
</header>
|
12
|
+
|
13
|
+
<div class="pl-30px pt-30px flex flex-row justify-around font-size-30">
|
14
|
+
<% @jobs.flat_map(&:parsed_durations).tap do |durations| %>
|
15
|
+
<%= link_to jpm_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
16
|
+
<div><%= per_minute(durations.size, (@date.last - @date.first).seconds) %></div>
|
17
|
+
<b>JPM</b>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<%= link_to jobs_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
21
|
+
<div><%= p50(durations) %> ms</div>
|
22
|
+
<b>p50</b>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<%= link_to jobs_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
26
|
+
<div><%= p95(durations) %> ms</div>
|
27
|
+
<b>p95</b>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
<%= link_to jobs_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
31
|
+
<div><%= p99(durations) %> ms</div>
|
32
|
+
<b>p99</b>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<%= link_to jobs_latency_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
36
|
+
<div><%= @latency.round(1) %> ms</div>
|
37
|
+
<b>Latency</b>
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<table>
|
43
|
+
<thead>
|
44
|
+
<tr>
|
45
|
+
<th>Name</th>
|
46
|
+
<th>Queue</th>
|
47
|
+
<th>JPM</th>
|
48
|
+
<th>p50</th>
|
49
|
+
<th>p95</th>
|
50
|
+
<th>p99</th>
|
51
|
+
</tr>
|
52
|
+
</thead>
|
53
|
+
<tbody>
|
54
|
+
<% @jobs.each do |model| %>
|
55
|
+
<tr>
|
56
|
+
<td><%= link_to model.job, job_p_values_path(@date.first.to_date, model.job) %></td>
|
57
|
+
<td><%= model.queue %></td>
|
58
|
+
<td><%= per_minute(model.parsed_durations.size, (@date.last - @date.first).seconds) %></td>
|
59
|
+
<td><%= model.p50 %> ms</td>
|
60
|
+
<td><%= model.p95 %> ms</td>
|
61
|
+
<td><%= model.p99 %> ms</td>
|
62
|
+
</tr>
|
63
|
+
<% end %>
|
64
|
+
</tbody>
|
65
|
+
</table>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<header>
|
2
|
+
<h1>Job Latency for <%= display_date(@date.first) %> (in ms)</h1>
|
3
|
+
|
4
|
+
<%= form_with url: active_insights.jobs_latency_redirection_path, method: :get do |f| %>
|
5
|
+
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
6
|
+
<% f.submit "submit", class: "hidden" %>
|
7
|
+
<% end %>
|
8
|
+
</header>
|
9
|
+
|
10
|
+
<div class="p-16px">
|
11
|
+
<%= column_chart @latencies, height: "80%", colors: ["#C00"], library: {
|
12
|
+
borderSkipped: true, barPercentage: 1, categoryPercentage: 1,
|
13
|
+
plugins: { zoom: { zoom: { wheel: { enabled: false }, drag: { enabled: true, backgroundColor: 'rgba(225,225,225,0.5)' }, mode: 'x' } } },
|
14
|
+
scales: {
|
15
|
+
x: { barPercentage: 1.0, autoSkip: false, display: false },
|
16
|
+
y: { grid: { display: false }, ticks: { color: "white" }, min: (@latencies.map(&:second).min.to_f * 0.98).ceil, max: (@latencies.map(&:second).max) }
|
17
|
+
} } %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<script>
|
21
|
+
document.addEventListener('keydown',(event) => {
|
22
|
+
const chart = Chartkick.charts[Object.keys(Chartkick.charts)[0]].getChartObject()
|
23
|
+
if (event.key === 'Escape' || event.key === 'Esc') {
|
24
|
+
chart.resetZoom()
|
25
|
+
}
|
26
|
+
});
|
27
|
+
</script>
|
@@ -1,6 +1,12 @@
|
|
1
1
|
<header>
|
2
|
-
|
3
|
-
|
2
|
+
<% if params[:job].present? %>
|
3
|
+
<h1><%= params[:job] %> metrics for <%= display_date(@date.first) %> (in ms)</h1>
|
4
|
+
<% else %>
|
5
|
+
<h1>Job Metrics for <%= display_date(@date.first) %> (in ms)</h1>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= form_with url: active_insights.jobs_p_values_redirection_path, method: :get do |f| %>
|
9
|
+
<%= f.hidden_field :job, value: params[:job] %>
|
4
10
|
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
5
11
|
<% f.submit "submit", class: "hidden" %>
|
6
12
|
<% end %>
|
@@ -12,7 +18,7 @@
|
|
12
18
|
elements: { point: { radius: 0 } },
|
13
19
|
scales: {
|
14
20
|
x: { autoSkip: false, display: false },
|
15
|
-
y: { grid: { display: false }, ticks: { color: "white" }, min: (@p50.map(&:second).min * 0.98).ceil, max: (@p99.map(&:second).max) }
|
21
|
+
y: { grid: { display: false }, ticks: { color: "white" }, min: (@p50.map(&:second).min.to_f * 0.98).ceil, max: (@p99.map(&:second).max) }
|
16
22
|
} } %>
|
17
23
|
</div>
|
18
24
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<header>
|
2
|
+
<h1>JPM Metrics for <%= display_date(@date.first) %></h1>
|
3
|
+
<%= form_with url: active_insights.jpm_redirection_path, method: :get do |f| %>
|
4
|
+
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
5
|
+
<% f.submit "submit", class: "hidden" %>
|
6
|
+
<% end %>
|
7
|
+
</header>
|
8
|
+
|
9
|
+
<div class="p-16px">
|
10
|
+
<%= column_chart @minutes, height: "80%", colors: ["#C00"], library: {
|
11
|
+
borderSkipped: true, barPercentage: 1, categoryPercentage: 1,
|
12
|
+
plugins: { zoom: { zoom: { wheel: { enabled: false }, drag: { enabled: true, backgroundColor: 'rgba(225,225,225,0.5)' }, mode: 'x' } } },
|
13
|
+
scales: {
|
14
|
+
x: { barPercentage: 1.0, autoSkip: false, display: false },
|
15
|
+
y: { grid: { display: false }, ticks: { color: "white" }, min: (@minutes.map(&:second).min.to_f * 0.98).ceil, max: (@minutes.map(&:second).max) }
|
16
|
+
} } %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<script>
|
20
|
+
document.addEventListener('keydown',(event) => {
|
21
|
+
const chart = Chartkick.charts[Object.keys(Chartkick.charts)[0]].getChartObject()
|
22
|
+
if (event.key === 'Escape' || event.key === 'Esc') {
|
23
|
+
chart.resetZoom()
|
24
|
+
}
|
25
|
+
});
|
26
|
+
</script>
|
@@ -1,9 +1,13 @@
|
|
1
1
|
<header>
|
2
2
|
<h1>Metrics for <%= display_date(@date.first) %></h1>
|
3
|
-
|
4
|
-
<%=
|
5
|
-
|
6
|
-
|
3
|
+
<div class="flex flex-row items-center">
|
4
|
+
<%= link_to "View job metrics", active_insights.jobs_path, class: "white mr-15px" %>
|
5
|
+
|
6
|
+
<%= form_with url: active_insights.requests_path, method: :get do |f| %>
|
7
|
+
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
8
|
+
<% f.submit "submit", class: "hidden" %>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
7
11
|
</header>
|
8
12
|
|
9
13
|
<div class="pl-30px pt-30px flex flex-row justify-around font-size-30">
|
@@ -13,17 +17,17 @@
|
|
13
17
|
<b>RPM</b>
|
14
18
|
<% end %>
|
15
19
|
|
16
|
-
<%= link_to
|
20
|
+
<%= link_to requests_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
17
21
|
<div><%= p50(durations) %> ms</div>
|
18
22
|
<b>p50</b>
|
19
23
|
<% end %>
|
20
24
|
|
21
|
-
<%= link_to
|
25
|
+
<%= link_to requests_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
22
26
|
<div><%= p95(durations) %> ms</div>
|
23
27
|
<b>p95</b>
|
24
28
|
<% end %>
|
25
29
|
|
26
|
-
<%= link_to
|
30
|
+
<%= link_to requests_p_values_path(@date.first.to_date), class: "flex flex-col justify-center items-center no-underline" do %>
|
27
31
|
<div><%= p99(durations) %> ms</div>
|
28
32
|
<b>p99</b>
|
29
33
|
<% end %>
|
@@ -1,6 +1,12 @@
|
|
1
1
|
<header>
|
2
|
-
|
3
|
-
|
2
|
+
<% if params[:formatted_controller].present? %>
|
3
|
+
<h1><%= params[:formatted_controller] %> metrics for <%= display_date(@date.first) %> (in ms)</h1>
|
4
|
+
<% else %>
|
5
|
+
<h1>Response Metrics for <%= display_date(@date.first) %> (in ms)</h1>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= form_with url: active_insights.requests_p_values_redirection_path, method: :get do |f| %>
|
9
|
+
<%= f.hidden_field :formatted_controller, value: params[:formatted_controller] %>
|
4
10
|
<%= f.date_field :date, max: Date.current, onchange: "this.form.submit()", value: @date.first.to_date %>
|
5
11
|
<% f.submit "submit", class: "hidden" %>
|
6
12
|
<% end %>
|
@@ -12,7 +18,7 @@
|
|
12
18
|
elements: { point: { radius: 0 } },
|
13
19
|
scales: {
|
14
20
|
x: { autoSkip: false, display: false },
|
15
|
-
y: { grid: { display: false }, ticks: { color: "white" }, min: (@p50.map(&:second).min * 0.98).ceil, max: (@p99.map(&:second).max) }
|
21
|
+
y: { grid: { display: false }, ticks: { color: "white" }, min: (@p50.map(&:second).min.to_f * 0.98).ceil, max: (@p99.map(&:second).max) }
|
16
22
|
} } %>
|
17
23
|
</div>
|
18
24
|
|
@@ -12,7 +12,7 @@
|
|
12
12
|
plugins: { zoom: { zoom: { wheel: { enabled: false }, drag: { enabled: true, backgroundColor: 'rgba(225,225,225,0.5)' }, mode: 'x' } } },
|
13
13
|
scales: {
|
14
14
|
x: { barPercentage: 1.0, autoSkip: false, display: false },
|
15
|
-
y: { grid: { display: false }, ticks: { color: "white" }, min: (@minutes.map(&:second).min * 0.98).ceil, max: (@minutes.map(&:second).max) }
|
15
|
+
y: { grid: { display: false }, ticks: { color: "white" }, min: (@minutes.map(&:second).min.to_f * 0.98).ceil, max: (@minutes.map(&:second).max) }
|
16
16
|
} } %>
|
17
17
|
</div>
|
18
18
|
|
@@ -6,6 +6,21 @@
|
|
6
6
|
<%= csrf_meta_tags %>
|
7
7
|
<%= csp_meta_tag %>
|
8
8
|
<%= active_insights_importmap_tags %>
|
9
|
+
<script type="module">
|
10
|
+
import {Chart, registerables} from "chart.js";
|
11
|
+
|
12
|
+
Chart.register(...registerables);
|
13
|
+
|
14
|
+
import "chartjs-adapter-date-fns";
|
15
|
+
import zoomPlugin from "chartjs-plugin-zoom";
|
16
|
+
import Chartkick from "chartkick";
|
17
|
+
|
18
|
+
window.Chartkick = Chartkick;
|
19
|
+
window.Chart = Chart;
|
20
|
+
|
21
|
+
Chartkick.use(Chart);
|
22
|
+
Chart.register(zoomPlugin);
|
23
|
+
</script>
|
9
24
|
|
10
25
|
<title>Active Insights</title>
|
11
26
|
<style>
|
@@ -338,6 +353,13 @@
|
|
338
353
|
padding: 16px;
|
339
354
|
}
|
340
355
|
|
356
|
+
a.white {
|
357
|
+
color: #fff;
|
358
|
+
}
|
359
|
+
.mr-15px {
|
360
|
+
margin-right: 15px;
|
361
|
+
}
|
362
|
+
|
341
363
|
<%= yield :style %>
|
342
364
|
</style>
|
343
365
|
</head>
|
@@ -3,8 +3,6 @@
|
|
3
3
|
require "active_insights"
|
4
4
|
|
5
5
|
ActiveInsights::Engine.importmap.draw do
|
6
|
-
pin "application", to: "active_insights/application.js"
|
7
|
-
|
8
6
|
pin "chartkick", to: "https://ga.jspm.io/npm:chartkick@5.0.1/dist/chartkick.esm.js"
|
9
7
|
pin "chart.js", to: "https://ga.jspm.io/npm:chart.js@4.4.1/dist/chart.js"
|
10
8
|
pin "chartjs-adapter-date-fns", to: "https://ga.jspm.io/npm:chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.esm.js"
|