simple_apm 1.1.1 → 1.1.2
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/README.md +4 -0
- data/app/assets/javascripts/simple_apm/application.js +94 -0
- data/app/assets/stylesheets/simple_apm/application.css +92 -7
- data/app/controllers/simple_apm/apm_controller.rb +22 -11
- data/app/helpers/simple_apm/application_helper.rb +24 -0
- data/app/models/simple_apm/action.rb +5 -5
- data/app/models/simple_apm/diagnostic_report.rb +203 -0
- data/app/models/simple_apm/sql.rb +1 -1
- data/app/views/layouts/simple_apm/application.html.erb +37 -58
- data/app/views/simple_apm/apm/_diagnostic_export.html.erb +17 -0
- data/app/views/simple_apm/apm/_timings.html.erb +18 -0
- data/app/views/simple_apm/apm/action_info.html.erb +36 -15
- data/app/views/simple_apm/apm/actions.html.erb +40 -21
- data/app/views/simple_apm/apm/dashboard.html.erb +38 -19
- data/app/views/simple_apm/apm/data.html.erb +59 -15
- data/app/views/simple_apm/apm/index.html.erb +45 -17
- data/app/views/simple_apm/apm/missing.html.erb +8 -0
- data/app/views/simple_apm/apm/show.html.erb +46 -21
- data/config/locales/simple_apm.en.yml +71 -2
- data/config/locales/simple_apm.zh-CN.yml +79 -10
- data/config/routes.rb +1 -1
- data/lib/simple_apm/version.rb +1 -1
- data/lib/simple_apm/worker.rb +4 -1
- metadata +5 -1
|
@@ -5,6 +5,25 @@
|
|
|
5
5
|
</div>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
|
+
<% total_hits = @data.sum { |day| day[:hits].to_i } %>
|
|
9
|
+
<div class="apm-metrics apm-metrics-compact">
|
|
10
|
+
<div class="apm-stat">
|
|
11
|
+
<p class="apm-stat-label"><%= t("simple_apm.data.retained_days") %></p>
|
|
12
|
+
<div class="apm-stat-value"><%= number_with_delimiter(@data.length) %></div>
|
|
13
|
+
<div class="apm-stat-meta"><%= t("simple_apm.data.history_title") %></div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="apm-stat">
|
|
16
|
+
<p class="apm-stat-label"><%= t("simple_apm.data.retained_requests") %></p>
|
|
17
|
+
<div class="apm-stat-value"><%= number_with_delimiter(total_hits) %></div>
|
|
18
|
+
<div class="apm-stat-meta"><%= t("simple_apm.data.summary_hint") %></div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="apm-stat">
|
|
21
|
+
<p class="apm-stat-label"><%= t("simple_apm.data.weighted_avg_response") %></p>
|
|
22
|
+
<div class="apm-stat-value"><%= total_hits.positive? ? sec_str(@data.sum { |day| day[:time].to_f } / total_hits) : '—' %></div>
|
|
23
|
+
<div class="apm-stat-meta"><%= t("simple_apm.dashboard.weighted_daily_average") %></div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
8
27
|
<section class="apm-panel">
|
|
9
28
|
<div class="apm-panel-header">
|
|
10
29
|
<div>
|
|
@@ -14,10 +33,10 @@
|
|
|
14
33
|
<div class="apm-toolbar-actions">
|
|
15
34
|
<% if SimpleApm::Redis.running? %>
|
|
16
35
|
<span class="apm-status apm-status-ok"><%= t("simple_apm.common.running") %></span>
|
|
17
|
-
<%=
|
|
36
|
+
<%= button_to t("simple_apm.data.pause_collection"), data_delete_path(type: 'stop_data'), method: :post, class: 'btn btn-warning', form: {data: {confirm: t("simple_apm.data.confirm_pause")}} %>
|
|
18
37
|
<% else %>
|
|
19
38
|
<span class="apm-status apm-status-danger"><%= t("simple_apm.common.paused") %></span>
|
|
20
|
-
<%=
|
|
39
|
+
<%= button_to t("simple_apm.data.resume_collection"), data_delete_path(type: 'rerun_data'), method: :post, class: 'btn btn-primary' %>
|
|
21
40
|
<% end %>
|
|
22
41
|
</div>
|
|
23
42
|
</div>
|
|
@@ -28,8 +47,8 @@
|
|
|
28
47
|
<p class="apm-page-subtitle"><%= t("simple_apm.data.delete_subtitle") %></p>
|
|
29
48
|
</div>
|
|
30
49
|
<div class="apm-toolbar-actions">
|
|
31
|
-
<%=
|
|
32
|
-
<%=
|
|
50
|
+
<%= button_to t("simple_apm.data.keep_one_week"), data_delete_path(type: 'week'), method: :post, class: 'btn btn-danger', form: {data: {confirm: t("simple_apm.data.confirm_delete_week")}} %>
|
|
51
|
+
<%= button_to t("simple_apm.data.keep_one_month"), data_delete_path(type: 'month'), method: :post, class: 'btn btn-danger', form: {data: {confirm: t("simple_apm.data.confirm_delete_month")}} %>
|
|
33
52
|
</div>
|
|
34
53
|
</div>
|
|
35
54
|
</div>
|
|
@@ -43,28 +62,53 @@
|
|
|
43
62
|
</div>
|
|
44
63
|
</div>
|
|
45
64
|
<div class="apm-panel-body">
|
|
65
|
+
<% if @data.empty? %>
|
|
66
|
+
<div class="apm-empty-state">
|
|
67
|
+
<h3 class="apm-panel-title"><%= t("simple_apm.data.no_data") %></h3>
|
|
68
|
+
<p><%= t("simple_apm.data.no_data_hint") %></p>
|
|
69
|
+
</div>
|
|
70
|
+
<% else %>
|
|
46
71
|
<div class="apm-table-wrap">
|
|
47
|
-
<table
|
|
72
|
+
<table id="history-table" class="table">
|
|
48
73
|
<thead>
|
|
49
74
|
<tr>
|
|
50
|
-
<th><%= t("simple_apm.data.date") %></th>
|
|
51
|
-
<th><%= t("simple_apm.data.request_count") %></th>
|
|
52
|
-
<th><%= t("simple_apm.data.avg_response_time") %></th>
|
|
53
|
-
<th><%= t("simple_apm.data.operation") %></th>
|
|
75
|
+
<th scope="col"><%= t("simple_apm.data.date") %></th>
|
|
76
|
+
<th scope="col"><%= t("simple_apm.data.request_count") %></th>
|
|
77
|
+
<th scope="col"><%= t("simple_apm.data.avg_response_time") %></th>
|
|
78
|
+
<th scope="col"><%= t("simple_apm.data.operation") %></th>
|
|
54
79
|
</tr>
|
|
55
80
|
</thead>
|
|
56
81
|
<tbody>
|
|
57
|
-
|
|
58
|
-
<% @data.each do |d| %>
|
|
82
|
+
<% @data.sort_by { |day| day[:day] }.reverse.each do |d| %>
|
|
59
83
|
<tr>
|
|
60
|
-
<td><%= d[:day] %></td>
|
|
61
|
-
<td><%= d[:hits] %></td>
|
|
62
|
-
<td><%= sec_str
|
|
63
|
-
<td
|
|
84
|
+
<td class="apm-mono"><%= link_to d[:day], dashboard_path(apm_date: d[:day]) %></td>
|
|
85
|
+
<td data-order="<%= d[:hits].to_i %>"><%= number_with_delimiter(d[:hits].to_i) %></td>
|
|
86
|
+
<td data-order="<%= d[:avg_time].to_f %>"><%= d[:hits].to_i.positive? ? sec_str(d[:avg_time]) : '—' %></td>
|
|
87
|
+
<td>
|
|
88
|
+
<div class="apm-toolbar-actions">
|
|
89
|
+
<%= link_to t("simple_apm.data.view_actions"), actions_path(apm_date: d[:day]), class: 'btn apm-button-secondary' %>
|
|
90
|
+
<%= link_to t("simple_apm.data.view_slow_requests"), index_path(apm_date: d[:day]), class: 'btn apm-button-secondary' %>
|
|
91
|
+
<%= button_to t("simple_apm.data.delete"), data_delete_path(date: d[:day]), method: :post, class: 'btn btn-danger', form: {data: {confirm: t("simple_apm.data.confirm_delete")}} %>
|
|
92
|
+
</div>
|
|
93
|
+
</td>
|
|
64
94
|
</tr>
|
|
65
95
|
<% end %>
|
|
66
96
|
</tbody>
|
|
67
97
|
</table>
|
|
68
98
|
</div>
|
|
99
|
+
<% end %>
|
|
69
100
|
</div>
|
|
70
101
|
</section>
|
|
102
|
+
<% unless @data.empty? %>
|
|
103
|
+
<script>
|
|
104
|
+
$(document).ready(function () {
|
|
105
|
+
$('#history-table').DataTable(window.SimpleApmUI.tableOptions({
|
|
106
|
+
order: [[0, 'desc']],
|
|
107
|
+
columnDefs: [
|
|
108
|
+
{type: 'num', targets: [1, 2]},
|
|
109
|
+
{orderable: false, searchable: false, targets: [3]}
|
|
110
|
+
]
|
|
111
|
+
}));
|
|
112
|
+
});
|
|
113
|
+
</script>
|
|
114
|
+
<% end %>
|
|
@@ -11,22 +11,30 @@
|
|
|
11
11
|
<h2 class="apm-panel-title"><%= t("simple_apm.index.samples_title") %></h2>
|
|
12
12
|
<p class="apm-panel-subtitle"><%= t("simple_apm.index.samples_subtitle") %></p>
|
|
13
13
|
</div>
|
|
14
|
+
<div class="apm-toolbar-actions">
|
|
15
|
+
<%= label_tag 'sample-limit', t("simple_apm.index.sample_limit") %>
|
|
16
|
+
<% maximum_samples = [SimpleApm::Setting::SLOW_ACTIONS_LIMIT.to_i, 1].max %>
|
|
17
|
+
<% sample_limits = ([50, 200, 500].map { |limit| [limit, maximum_samples].min } + [@sample_limit]).uniq.sort %>
|
|
18
|
+
<%= select_tag 'sample-limit', options_for_select(sample_limits, @sample_limit), class: 'form-control' %>
|
|
19
|
+
<button id="refresh-requests" type="button" class="btn apm-button-secondary"><%= t("simple_apm.index.refresh") %></button>
|
|
20
|
+
</div>
|
|
14
21
|
</div>
|
|
15
22
|
<div class="apm-panel-body">
|
|
23
|
+
<p id="slow-requests-feedback" class="apm-table-feedback" role="status" aria-live="polite"></p>
|
|
16
24
|
<div class="apm-table-wrap">
|
|
17
|
-
<table id="slow-requests" class="table">
|
|
25
|
+
<table id="slow-requests" class="table" aria-describedby="slow-requests-feedback">
|
|
18
26
|
<thead>
|
|
19
27
|
<tr>
|
|
20
|
-
<th><%= t("simple_apm.index.request_time") %></th>
|
|
21
|
-
<th><%= t("simple_apm.index.action_name") %></th>
|
|
22
|
-
<th><%= t("simple_apm.index.total_time") %></th>
|
|
23
|
-
<th><%= t("simple_apm.common.db") %></th>
|
|
24
|
-
<th><%= t("simple_apm.common.sql") %></th>
|
|
25
|
-
<th><%= t("simple_apm.common.view") %></th>
|
|
26
|
-
<th><%= t("simple_apm.common.http") %></th>
|
|
27
|
-
<th><%= t("simple_apm.index.memory_mb") %></th>
|
|
28
|
-
<th><%= t("simple_apm.common.server") %></th>
|
|
29
|
-
<th><%= t("simple_apm.index.ip") %></th>
|
|
28
|
+
<th scope="col"><%= t("simple_apm.index.request_time") %></th>
|
|
29
|
+
<th scope="col"><%= t("simple_apm.index.action_name") %></th>
|
|
30
|
+
<th scope="col"><%= t("simple_apm.index.total_time") %></th>
|
|
31
|
+
<th scope="col"><%= t("simple_apm.common.db") %></th>
|
|
32
|
+
<th scope="col"><%= t("simple_apm.common.sql") %></th>
|
|
33
|
+
<th scope="col"><%= t("simple_apm.common.view") %></th>
|
|
34
|
+
<th scope="col"><%= t("simple_apm.common.http") %></th>
|
|
35
|
+
<th scope="col"><%= t("simple_apm.index.memory_mb") %></th>
|
|
36
|
+
<th scope="col"><%= t("simple_apm.common.server") %></th>
|
|
37
|
+
<th scope="col"><%= t("simple_apm.index.ip") %></th>
|
|
30
38
|
</tr>
|
|
31
39
|
</thead>
|
|
32
40
|
</table>
|
|
@@ -36,11 +44,31 @@
|
|
|
36
44
|
|
|
37
45
|
<script type="text/javascript">
|
|
38
46
|
$(document).ready(function () {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
var requestsUrl = <%= raw json_escape(index_path(format: :json, apm_date: apm_date).to_json) %>,
|
|
48
|
+
refreshButton = $('#refresh-requests'),
|
|
49
|
+
sampleLimit = $('#sample-limit');
|
|
50
|
+
var requestsTable = $('#slow-requests').on('processing.dt', function (event, settings, processing) {
|
|
51
|
+
refreshButton.prop('disabled', processing).text(processing ? '<%= j t("simple_apm.index.refresh_loading") %>' : '<%= j t("simple_apm.index.refresh") %>');
|
|
52
|
+
sampleLimit.prop('disabled', processing);
|
|
53
|
+
$(this).attr('aria-busy', processing ? 'true' : 'false');
|
|
54
|
+
}).DataTable(window.SimpleApmUI.tableOptions({
|
|
55
|
+
ajax: requestsUrl + '&count=' + encodeURIComponent(sampleLimit.val()),
|
|
56
|
+
order: [[2, 'desc']],
|
|
57
|
+
columnDefs: [
|
|
58
|
+
{type: 'sec', targets: [2, 3, 5, 6]},
|
|
59
|
+
{type: 'num', targets: [4, 7]},
|
|
60
|
+
{className: 'apm-mono', targets: [1, 8, 9]}
|
|
61
|
+
]
|
|
62
|
+
}));
|
|
63
|
+
refreshButton.on('click', function () {
|
|
64
|
+
requestsTable.ajax.reload(null, false);
|
|
65
|
+
});
|
|
66
|
+
sampleLimit.on('change', function () {
|
|
67
|
+
var pageUrl = new URL(window.location.href);
|
|
68
|
+
pageUrl.searchParams.set('count', this.value);
|
|
69
|
+
window.history.replaceState(null, '', pageUrl.toString());
|
|
70
|
+
$('.apm-date-form input[name="count"]').val(this.value);
|
|
71
|
+
requestsTable.ajax.url(requestsUrl + '&count=' + encodeURIComponent(this.value)).load();
|
|
72
|
+
});
|
|
45
73
|
})
|
|
46
74
|
</script>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<section class="apm-panel apm-empty-state">
|
|
2
|
+
<h1 class="apm-page-title"><%= t("simple_apm.common.missing_title") %></h1>
|
|
3
|
+
<p class="apm-page-subtitle"><%= t("simple_apm.common.missing_hint") %></p>
|
|
4
|
+
<div class="apm-toolbar-actions">
|
|
5
|
+
<%= link_to t("simple_apm.layout.nav_slow_requests"), index_path, class: 'btn apm-button-secondary' %>
|
|
6
|
+
<%= link_to t("simple_apm.layout.nav_actions"), actions_path, class: 'btn btn-primary' %>
|
|
7
|
+
</div>
|
|
8
|
+
</section>
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
<nav class="apm-breadcrumb" aria-label="<%= t('simple_apm.show.title') %>">
|
|
2
|
+
<%= link_to t('simple_apm.common.back_requests'), index_path(apm_date: apm_date) %>
|
|
3
|
+
<span aria-hidden="true">/</span>
|
|
4
|
+
<%= link_to @request.action_name, action_info_path(action_name: @request.action_name, apm_date: apm_date) %>
|
|
5
|
+
</nav>
|
|
1
6
|
<div class="apm-page-header">
|
|
2
7
|
<div>
|
|
3
8
|
<h1 class="apm-page-title"><%= t("simple_apm.show.title") %></h1>
|
|
4
|
-
<p class="apm-page-subtitle"><%= @request.action_name
|
|
9
|
+
<p class="apm-page-subtitle apm-mono"><%= @request.action_name %> · <%= @request.method %> · <%= @request.format %></p>
|
|
5
10
|
</div>
|
|
11
|
+
<span class="apm-status <%= @request.status.to_i >= 400 ? 'apm-status-danger' : 'apm-status-neutral' %>"><%= t('simple_apm.common.status') %>: <%= @request.status.presence || t('simple_apm.common.unknown') %></span>
|
|
6
12
|
</div>
|
|
7
13
|
|
|
8
14
|
<div class="apm-metrics">
|
|
@@ -29,6 +35,10 @@
|
|
|
29
35
|
</div>
|
|
30
36
|
</div>
|
|
31
37
|
|
|
38
|
+
<%= render 'diagnostic_export', report: SimpleApm::DiagnosticReport.for_request(@request, date: apm_date) %>
|
|
39
|
+
|
|
40
|
+
<%= render 'timings', total: @request.during, parts: [[t('simple_apm.common.db'), @request.db_runtime], [t('simple_apm.common.view'), @request.view_runtime], [t('simple_apm.common.http'), @request.net_http_during]] %>
|
|
41
|
+
|
|
32
42
|
<section class="apm-panel">
|
|
33
43
|
<div class="apm-panel-header">
|
|
34
44
|
<div>
|
|
@@ -38,12 +48,16 @@
|
|
|
38
48
|
</div>
|
|
39
49
|
<div class="apm-panel-body">
|
|
40
50
|
<dl class="apm-detail-list">
|
|
51
|
+
<dt><%= t('simple_apm.show.request_id') %></dt>
|
|
52
|
+
<dd><span id="request-id" class="apm-mono"><%= @request.request_id %></span></dd>
|
|
53
|
+
<dt><%= t('simple_apm.show.format_method') %></dt>
|
|
54
|
+
<dd><%= @request.method.presence || t('simple_apm.common.unknown') %> / <%= @request.format %></dd>
|
|
41
55
|
<dt><%= t("simple_apm.common.url") %></dt>
|
|
42
|
-
<dd><%= @request.url %></dd>
|
|
56
|
+
<dd class="apm-mono"><%= @request.url %></dd>
|
|
43
57
|
<dt><%= t("simple_apm.show.started_at") %></dt>
|
|
44
58
|
<dd><%= time_label @request.started, true %></dd>
|
|
45
59
|
<dt><%= t("simple_apm.show.completed_memory") %></dt>
|
|
46
|
-
<dd><%= @request.completed_memory.to_f.round(1) %>
|
|
60
|
+
<dd><%= @request.completed_memory.to_f.round(1) %> MB (<%= t("simple_apm.show.memory_increase") %>: <%= @request.memory_during.to_f.round(1) %> MB)</dd>
|
|
47
61
|
<dt><%= t("simple_apm.common.server") %></dt>
|
|
48
62
|
<dd><%= @request.host %></dd>
|
|
49
63
|
<dt><%= t("simple_apm.show.ip") %></dt>
|
|
@@ -65,7 +79,6 @@
|
|
|
65
79
|
</section>
|
|
66
80
|
<% end %>
|
|
67
81
|
|
|
68
|
-
<% if @request.net_http_requests.present? %>
|
|
69
82
|
<section class="apm-panel">
|
|
70
83
|
<div class="apm-panel-header">
|
|
71
84
|
<div>
|
|
@@ -74,29 +87,35 @@
|
|
|
74
87
|
</div>
|
|
75
88
|
</div>
|
|
76
89
|
<div class="apm-panel-body">
|
|
90
|
+
<% if @request.net_http_requests.empty? %>
|
|
91
|
+
<p class="apm-stat-hint"><%= t('simple_apm.show.no_http') %></p>
|
|
92
|
+
<% else %>
|
|
77
93
|
<div class="apm-table-wrap">
|
|
78
94
|
<table class="table table-bordered">
|
|
95
|
+
<thead>
|
|
79
96
|
<tr>
|
|
80
97
|
<th><%= t("simple_apm.show.started_at") %></th>
|
|
81
98
|
<th><%= t("simple_apm.show.duration") %></th>
|
|
82
99
|
<th><%= t("simple_apm.common.url") %></th>
|
|
83
100
|
<th><%= t("simple_apm.show.other_info") %></th>
|
|
84
101
|
</tr>
|
|
102
|
+
</thead>
|
|
103
|
+
<tbody>
|
|
85
104
|
<% @request.net_http_requests.each do |r| %>
|
|
86
105
|
<tr>
|
|
87
106
|
<td><%= time_label r.started %></td>
|
|
88
107
|
<td><%= sec_str r.during %></td>
|
|
89
|
-
<td><%= r.url %></td>
|
|
90
|
-
<td><%= "#{r.filename}: #{r.line}" if r.filename.present? %></td>
|
|
108
|
+
<td class="apm-mono"><%= r.url %></td>
|
|
109
|
+
<td class="apm-mono"><%= "#{r.filename}: #{r.line}" if r.filename.present? %></td>
|
|
91
110
|
</tr>
|
|
92
111
|
<% end %>
|
|
112
|
+
</tbody>
|
|
93
113
|
</table>
|
|
94
114
|
</div>
|
|
115
|
+
<% end %>
|
|
95
116
|
</div>
|
|
96
117
|
</section>
|
|
97
|
-
<% end %>
|
|
98
118
|
|
|
99
|
-
<% if @request.sqls.present? %>
|
|
100
119
|
<section class="apm-panel">
|
|
101
120
|
<div class="apm-panel-header">
|
|
102
121
|
<div>
|
|
@@ -105,15 +124,19 @@
|
|
|
105
124
|
</div>
|
|
106
125
|
</div>
|
|
107
126
|
<div class="apm-panel-body">
|
|
127
|
+
<% if @request.sqls.empty? %>
|
|
128
|
+
<p class="apm-stat-hint"><%= t('simple_apm.show.no_sql') %></p>
|
|
129
|
+
<% else %>
|
|
108
130
|
<div class="apm-table-wrap">
|
|
109
131
|
<table id="sql-table" class="table">
|
|
110
132
|
<thead>
|
|
111
133
|
<tr>
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
<
|
|
115
|
-
<
|
|
116
|
-
<
|
|
134
|
+
<th><%= t('simple_apm.show.started_at') %></th>
|
|
135
|
+
<th><%= t('simple_apm.show.sql_name') %></th>
|
|
136
|
+
<th>SQL</th>
|
|
137
|
+
<th><%= t('simple_apm.common.duration') %></th>
|
|
138
|
+
<th><%= t('simple_apm.show.sql_cached') %></th>
|
|
139
|
+
<th><%= t("simple_apm.show.location") %></th>
|
|
117
140
|
</tr>
|
|
118
141
|
</thead>
|
|
119
142
|
<tbody>
|
|
@@ -124,24 +147,26 @@
|
|
|
124
147
|
<%= sql.name %>
|
|
125
148
|
</td>
|
|
126
149
|
<td>
|
|
127
|
-
<
|
|
150
|
+
<button type="button" class="sql" aria-label="<%= t('simple_apm.show.sql_list_subtitle') %>"><%= sql.full_sql -%></button>
|
|
128
151
|
</td>
|
|
129
|
-
<td><%= sec_str sql.during %></td>
|
|
130
|
-
<td><%= sql.
|
|
152
|
+
<td data-order="<%= sql.during.to_f %>"><%= sec_str sql.during %></td>
|
|
153
|
+
<td><%= sql.cached.nil? ? t('simple_apm.common.unknown') : t("simple_apm.show.#{sql.cached ? 'cache_hit' : 'cache_miss'}") %></td>
|
|
154
|
+
<td class="apm-mono"><%= "#{sql.filename}:#{sql.line}" if sql.filename.present? %></td>
|
|
131
155
|
</tr>
|
|
132
156
|
<% end %>
|
|
133
157
|
</tbody>
|
|
134
158
|
</table>
|
|
135
159
|
</div>
|
|
160
|
+
<% end %>
|
|
136
161
|
</div>
|
|
137
162
|
</section>
|
|
163
|
+
<% if @request.sqls.present? %>
|
|
138
164
|
<script type="text/javascript">
|
|
139
165
|
$(document).ready(function () {
|
|
140
|
-
$('#sql-table').DataTable({
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
})
|
|
166
|
+
$('#sql-table').DataTable(window.SimpleApmUI.tableOptions({
|
|
167
|
+
paging: false,
|
|
168
|
+
order: [[3, 'desc']]
|
|
169
|
+
}))
|
|
145
170
|
|
|
146
171
|
})
|
|
147
172
|
</script>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
en:
|
|
2
2
|
simple_apm:
|
|
3
3
|
actions:
|
|
4
|
+
action_count: "Actions"
|
|
5
|
+
total_hits: "Total Hits"
|
|
6
|
+
weighted_avg_response: "Avg Response Time"
|
|
7
|
+
summary_hint: "All actions for the selected date"
|
|
4
8
|
title: "Action Performance"
|
|
5
9
|
subtitle: "Aggregate hits, response time, and SQL behavior by Controller#Action."
|
|
6
10
|
list_title: "Action List"
|
|
@@ -14,6 +18,9 @@ en:
|
|
|
14
18
|
fastest_response_time: "Fastest Response Time"
|
|
15
19
|
slowest_response_time: "Slowest Response Time"
|
|
16
20
|
action_info:
|
|
21
|
+
avg_http_time: "Avg HTTP Time"
|
|
22
|
+
cached_queries: "Avg cached SQL"
|
|
23
|
+
sample_status: "HTTP Status"
|
|
17
24
|
title: "Action Overview"
|
|
18
25
|
daily_hits: "Daily Hits"
|
|
19
26
|
avg_response_time: "Avg Response Time"
|
|
@@ -29,6 +36,18 @@ en:
|
|
|
29
36
|
request_id: "Request ID"
|
|
30
37
|
ip: "IP"
|
|
31
38
|
common:
|
|
39
|
+
copy: "Copy"
|
|
40
|
+
close: "Close"
|
|
41
|
+
apply: "Apply"
|
|
42
|
+
skip_content: "Skip to content"
|
|
43
|
+
missing_title: "Record unavailable"
|
|
44
|
+
missing_hint: "No record was retained for this date. Choose another date or return to the list."
|
|
45
|
+
back_actions: "Back to actions"
|
|
46
|
+
back_requests: "Back to slow requests"
|
|
47
|
+
status: "HTTP Status"
|
|
48
|
+
unknown: "Not recorded"
|
|
49
|
+
duration: "Duration"
|
|
50
|
+
no_samples: "No request samples retained for this date."
|
|
32
51
|
db: "DB"
|
|
33
52
|
http: "HTTP"
|
|
34
53
|
running: "Running"
|
|
@@ -39,6 +58,10 @@ en:
|
|
|
39
58
|
url: "URL"
|
|
40
59
|
view: "View"
|
|
41
60
|
dashboard:
|
|
61
|
+
daily_avg_response: "Avg Response Time"
|
|
62
|
+
weighted_daily_average: "Weighted by request count"
|
|
63
|
+
no_data: "No requests for this date"
|
|
64
|
+
no_data_hint: "Select a date with collected data, or check collection status."
|
|
42
65
|
title: "Performance Overview"
|
|
43
66
|
subtitle: "Review response time and traffic trends in 10-minute intervals."
|
|
44
67
|
stat_points: "Data Points"
|
|
@@ -56,6 +79,15 @@ en:
|
|
|
56
79
|
hit_count: "Hit Count"
|
|
57
80
|
hit_count_subtitle: "Request count for each interval."
|
|
58
81
|
data:
|
|
82
|
+
retained_days: "Retained Days"
|
|
83
|
+
retained_requests: "Retained Requests"
|
|
84
|
+
weighted_avg_response: "Avg Response Time"
|
|
85
|
+
summary_hint: "Across all retained dates"
|
|
86
|
+
view_dashboard: "View dashboard"
|
|
87
|
+
view_actions: "View actions"
|
|
88
|
+
view_slow_requests: "View slow requests"
|
|
89
|
+
no_data: "No historical data"
|
|
90
|
+
no_data_hint: "Historical data will appear after requests have been collected."
|
|
59
91
|
title: "Data Management"
|
|
60
92
|
subtitle: "Manage collection status and historical Redis data."
|
|
61
93
|
collection_status: "Collection Status"
|
|
@@ -84,14 +116,18 @@ en:
|
|
|
84
116
|
unknown_action: "Unknown action."
|
|
85
117
|
updated: "Updated successfully."
|
|
86
118
|
index:
|
|
119
|
+
sample_limit: "Sample limit"
|
|
120
|
+
refresh: "Refresh"
|
|
121
|
+
refresh_loading: "Loading…"
|
|
122
|
+
load_error: "Unable to load request samples. Refresh to try again."
|
|
87
123
|
title: "Slow Requests"
|
|
88
124
|
subtitle: "Sort by response duration to locate DB, SQL, View, and external request cost."
|
|
89
125
|
samples_title: "Request Samples"
|
|
90
|
-
samples_subtitle: "
|
|
126
|
+
samples_subtitle: "Shows the slowest retained requests for the selected date."
|
|
91
127
|
request_time: "Request Time"
|
|
92
128
|
action_name: "Action Name"
|
|
93
129
|
total_time: "Total Time"
|
|
94
|
-
memory_mb: "Memory (
|
|
130
|
+
memory_mb: "Memory Delta (MB)"
|
|
95
131
|
ip: "IP"
|
|
96
132
|
layout:
|
|
97
133
|
collected: "Collecting data"
|
|
@@ -112,6 +148,16 @@ en:
|
|
|
112
148
|
en: "English"
|
|
113
149
|
zh-CN: "中文"
|
|
114
150
|
show:
|
|
151
|
+
request_id: "Request ID"
|
|
152
|
+
format_method: "Method / Format"
|
|
153
|
+
sql_name: "Name"
|
|
154
|
+
sql_cached: "Cache"
|
|
155
|
+
cache_hit: "Hit"
|
|
156
|
+
cache_miss: "Miss"
|
|
157
|
+
timing_title: "Recorded Timing"
|
|
158
|
+
timing_hint: "Timings may overlap; DB, View and HTTP do not necessarily add up to the total."
|
|
159
|
+
no_sql: "No SQL statements retained. SQL below the configured threshold is not recorded."
|
|
160
|
+
no_http: "No external HTTP calls retained."
|
|
115
161
|
title: "Request Details"
|
|
116
162
|
cached: "Cached"
|
|
117
163
|
basic_info: "Basic Info"
|
|
@@ -129,3 +175,26 @@ en:
|
|
|
129
175
|
sql_list_subtitle: "Click SQL text to view the complete statement."
|
|
130
176
|
time_ms: "Time (ms)"
|
|
131
177
|
location: "Location"
|
|
178
|
+
diagnostics:
|
|
179
|
+
title: "AI Diagnostic Context"
|
|
180
|
+
hint: "Copy metrics, retained samples, SQL, external calls and code locations as JSON. Common credential fields are filtered; expand to review the content."
|
|
181
|
+
copy: "Copy for AI"
|
|
182
|
+
preview: "Preview diagnostic context"
|
|
183
|
+
copied: "Copied to clipboard."
|
|
184
|
+
copy_failed: "Copy failed. Select the text and copy it manually."
|
|
185
|
+
table:
|
|
186
|
+
search: "Search:"
|
|
187
|
+
length_menu: "Show _MENU_ rows"
|
|
188
|
+
info: "_START_–_END_ of _TOTAL_ rows"
|
|
189
|
+
info_empty: "0 rows"
|
|
190
|
+
info_filtered: "(filtered from _MAX_ rows)"
|
|
191
|
+
zero_records: "No matching records. Try a different search."
|
|
192
|
+
empty: "No records for this date."
|
|
193
|
+
loading: "Loading…"
|
|
194
|
+
processing: "Processing…"
|
|
195
|
+
first: "First"
|
|
196
|
+
last: "Last"
|
|
197
|
+
next: "Next"
|
|
198
|
+
previous: "Previous"
|
|
199
|
+
sort_ascending: ": activate to sort ascending"
|
|
200
|
+
sort_descending: ": activate to sort descending"
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
zh-CN:
|
|
2
2
|
simple_apm:
|
|
3
3
|
actions:
|
|
4
|
+
action_count: "Action 数量"
|
|
5
|
+
total_hits: "请求总数"
|
|
6
|
+
weighted_avg_response: "平均响应时间"
|
|
7
|
+
summary_hint: "当前日期全部 Action"
|
|
4
8
|
title: "Action 性能"
|
|
5
9
|
subtitle: "按 Controller#Action 聚合访问次数、响应时间和 SQL 行为。"
|
|
6
10
|
list_title: "Action 列表"
|
|
7
11
|
list_subtitle: "点击 Action 名称查看该接口的慢请求样本。"
|
|
8
|
-
name: "
|
|
9
|
-
click_count: "
|
|
12
|
+
name: "Action 名称"
|
|
13
|
+
click_count: "请求次数"
|
|
10
14
|
avg_response_time: "平均响应时间"
|
|
11
15
|
avg_db_time: "平均 DB 时间"
|
|
12
16
|
avg_sql_count: "平均 SQL 次数"
|
|
@@ -14,8 +18,11 @@ zh-CN:
|
|
|
14
18
|
fastest_response_time: "最快响应时间"
|
|
15
19
|
slowest_response_time: "最慢响应时间"
|
|
16
20
|
action_info:
|
|
21
|
+
avg_http_time: "平均 HTTP 耗时"
|
|
22
|
+
cached_queries: "平均缓存 SQL"
|
|
23
|
+
sample_status: "HTTP 状态"
|
|
17
24
|
title: "Action 概况"
|
|
18
|
-
daily_hits: "
|
|
25
|
+
daily_hits: "当日请求次数"
|
|
19
26
|
avg_response_time: "平均响应时间"
|
|
20
27
|
avg_db_time: "平均 DB 时间"
|
|
21
28
|
avg_sql_count: "平均 SQL 次数"
|
|
@@ -29,16 +36,32 @@ zh-CN:
|
|
|
29
36
|
request_id: "请求 ID"
|
|
30
37
|
ip: "访问 IP"
|
|
31
38
|
common:
|
|
39
|
+
copy: "复制"
|
|
40
|
+
close: "关闭"
|
|
41
|
+
apply: "应用"
|
|
42
|
+
skip_content: "跳转到主要内容"
|
|
43
|
+
missing_title: "记录不可用"
|
|
44
|
+
missing_hint: "该日期没有保留此记录,请选择其他日期或返回列表。"
|
|
45
|
+
back_actions: "返回 Action 列表"
|
|
46
|
+
back_requests: "返回慢请求列表"
|
|
47
|
+
status: "HTTP 状态"
|
|
48
|
+
unknown: "未记录"
|
|
49
|
+
duration: "耗时"
|
|
50
|
+
no_samples: "该日期没有保留请求样本。"
|
|
32
51
|
db: "DB"
|
|
33
52
|
http: "HTTP"
|
|
34
53
|
running: "运行中"
|
|
35
54
|
paused: "已暂停"
|
|
36
|
-
server: "
|
|
55
|
+
server: "服务器"
|
|
37
56
|
sql: "SQL"
|
|
38
|
-
total: "
|
|
57
|
+
total: "总耗时"
|
|
39
58
|
url: "URL"
|
|
40
|
-
view: "
|
|
59
|
+
view: "视图"
|
|
41
60
|
dashboard:
|
|
61
|
+
daily_avg_response: "平均响应时间"
|
|
62
|
+
weighted_daily_average: "按请求次数加权统计"
|
|
63
|
+
no_data: "该日期没有请求数据"
|
|
64
|
+
no_data_hint: "请选择有采集数据的日期,或检查采集状态。"
|
|
42
65
|
title: "性能概览"
|
|
43
66
|
subtitle: "按 10 分钟粒度观察响应时间和访问量趋势。"
|
|
44
67
|
stat_points: "统计点"
|
|
@@ -56,6 +79,15 @@ zh-CN:
|
|
|
56
79
|
hit_count: "访问次数"
|
|
57
80
|
hit_count_subtitle: "每个时间段的请求数量。"
|
|
58
81
|
data:
|
|
82
|
+
retained_days: "保留天数"
|
|
83
|
+
retained_requests: "保留请求数"
|
|
84
|
+
weighted_avg_response: "平均响应时间"
|
|
85
|
+
summary_hint: "全部保留日期的统计"
|
|
86
|
+
view_dashboard: "查看概览"
|
|
87
|
+
view_actions: "查看 Action"
|
|
88
|
+
view_slow_requests: "查看慢请求"
|
|
89
|
+
no_data: "暂无历史数据"
|
|
90
|
+
no_data_hint: "采集到请求后,将在这里显示历史数据。"
|
|
59
91
|
title: "数据管理"
|
|
60
92
|
subtitle: "管理采集开关和历史 Redis 数据。"
|
|
61
93
|
collection_status: "采集状态"
|
|
@@ -84,14 +116,18 @@ zh-CN:
|
|
|
84
116
|
unknown_action: "未知操作!"
|
|
85
117
|
updated: "设置成功!"
|
|
86
118
|
index:
|
|
119
|
+
sample_limit: "样本数量上限"
|
|
120
|
+
refresh: "刷新"
|
|
121
|
+
refresh_loading: "加载中…"
|
|
122
|
+
load_error: "请求样本加载失败,请点击刷新重试。"
|
|
87
123
|
title: "慢事务列表"
|
|
88
124
|
subtitle: "按响应耗时排序,快速定位 DB、SQL、View 和外部请求占比。"
|
|
89
125
|
samples_title: "请求样本"
|
|
90
|
-
samples_subtitle: "
|
|
126
|
+
samples_subtitle: "展示当前日期保留的最慢请求,可排序和搜索。"
|
|
91
127
|
request_time: "请求时间"
|
|
92
|
-
action_name: "Action
|
|
93
|
-
total_time: "
|
|
94
|
-
memory_mb: "
|
|
128
|
+
action_name: "Action 名称"
|
|
129
|
+
total_time: "总耗时"
|
|
130
|
+
memory_mb: "内存变化 (MB)"
|
|
95
131
|
ip: "IP"
|
|
96
132
|
layout:
|
|
97
133
|
collected: "数据收集中"
|
|
@@ -112,6 +148,16 @@ zh-CN:
|
|
|
112
148
|
en: "English"
|
|
113
149
|
zh-CN: "中文"
|
|
114
150
|
show:
|
|
151
|
+
request_id: "请求 ID"
|
|
152
|
+
format_method: "请求方法 / 格式"
|
|
153
|
+
sql_name: "名称"
|
|
154
|
+
sql_cached: "缓存"
|
|
155
|
+
cache_hit: "命中"
|
|
156
|
+
cache_miss: "未命中"
|
|
157
|
+
timing_title: "记录的耗时"
|
|
158
|
+
timing_hint: "各项耗时可能重叠,DB、View 和 HTTP 的合计不一定等于总耗时。"
|
|
159
|
+
no_sql: "没有保留 SQL 明细,低于配置阈值的 SQL 不会记录。"
|
|
160
|
+
no_http: "没有保留外部 HTTP 调用。"
|
|
115
161
|
title: "请求详情"
|
|
116
162
|
cached: "缓存"
|
|
117
163
|
basic_info: "基础信息"
|
|
@@ -129,3 +175,26 @@ zh-CN:
|
|
|
129
175
|
sql_list_subtitle: "点击 SQL 文本查看完整语句。"
|
|
130
176
|
time_ms: "时间 (ms)"
|
|
131
177
|
location: "位置"
|
|
178
|
+
diagnostics:
|
|
179
|
+
title: "AI 排查上下文"
|
|
180
|
+
hint: "以 JSON 复制指标、保留的请求样本、SQL、外部调用与代码位置。常见凭据字段已过滤,可展开预览内容。"
|
|
181
|
+
copy: "复制给 AI"
|
|
182
|
+
preview: "预览排查信息"
|
|
183
|
+
copied: "已复制到剪贴板。"
|
|
184
|
+
copy_failed: "复制失败,请选中文本后手动复制。"
|
|
185
|
+
table:
|
|
186
|
+
search: "搜索:"
|
|
187
|
+
length_menu: "每页 _MENU_ 条"
|
|
188
|
+
info: "第 _START_–_END_ 条,共 _TOTAL_ 条"
|
|
189
|
+
info_empty: "共 0 条"
|
|
190
|
+
info_filtered: "(从 _MAX_ 条记录筛选)"
|
|
191
|
+
zero_records: "没有匹配记录,请尝试其他关键词。"
|
|
192
|
+
empty: "该日期暂无记录。"
|
|
193
|
+
loading: "加载中…"
|
|
194
|
+
processing: "处理中…"
|
|
195
|
+
first: "首页"
|
|
196
|
+
last: "末页"
|
|
197
|
+
next: "下一页"
|
|
198
|
+
previous: "上一页"
|
|
199
|
+
sort_ascending: ":激活以升序排列"
|
|
200
|
+
sort_descending: ":激活以降序排列"
|
data/config/routes.rb
CHANGED
|
@@ -5,7 +5,7 @@ SimpleApm::Engine.routes.draw do
|
|
|
5
5
|
get 'action_info', to: 'apm#action_info'
|
|
6
6
|
get 'actions', to: 'apm#actions'
|
|
7
7
|
get 'data', to: 'apm#data'
|
|
8
|
-
|
|
8
|
+
post 'data_delete', to: 'apm#data_delete'
|
|
9
9
|
get 'set_apm_date', to: 'apm#set_apm_date'
|
|
10
10
|
get 'set_locale', to: 'apm#set_locale'
|
|
11
11
|
root 'apm#dashboard'
|
data/lib/simple_apm/version.rb
CHANGED