simple_apm 1.1.0 → 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.
@@ -1,15 +1,34 @@
1
1
  <div class="apm-page-header">
2
2
  <div>
3
- <h1 class="apm-page-title">Action 性能</h1>
4
- <p class="apm-page-subtitle">按 Controller#Action 聚合访问次数、响应时间和 SQL 行为。</p>
3
+ <h1 class="apm-page-title"><%= t("simple_apm.actions.title") %></h1>
4
+ <p class="apm-page-subtitle"><%= t("simple_apm.actions.subtitle") %></p>
5
+ </div>
6
+ </div>
7
+
8
+ <% total_hits = @actions.sum { |action| action.click_count.to_i } %>
9
+ <div class="apm-metrics apm-metrics-compact">
10
+ <div class="apm-stat">
11
+ <p class="apm-stat-label"><%= t("simple_apm.actions.action_count") %></p>
12
+ <div class="apm-stat-value"><%= number_with_delimiter(@actions.length) %></div>
13
+ <div class="apm-stat-meta"><%= apm_date %></div>
14
+ </div>
15
+ <div class="apm-stat">
16
+ <p class="apm-stat-label"><%= t("simple_apm.actions.total_hits") %></p>
17
+ <div class="apm-stat-value"><%= number_with_delimiter(total_hits) %></div>
18
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.current_day_total") %></div>
19
+ </div>
20
+ <div class="apm-stat">
21
+ <p class="apm-stat-label"><%= t("simple_apm.actions.weighted_avg_response") %></p>
22
+ <div class="apm-stat-value"><%= total_hits.positive? ? sec_str(@actions.sum { |action| action.time.to_f } / total_hits) : '—' %></div>
23
+ <div class="apm-stat-meta"><%= t("simple_apm.actions.summary_hint") %></div>
5
24
  </div>
6
25
  </div>
7
26
 
8
27
  <section class="apm-panel">
9
28
  <div class="apm-panel-header">
10
29
  <div>
11
- <h2 class="apm-panel-title">Action 列表</h2>
12
- <p class="apm-panel-subtitle">点击 Action 名称查看该接口的慢请求样本。</p>
30
+ <h2 class="apm-panel-title"><%= t("simple_apm.actions.list_title") %></h2>
31
+ <p class="apm-panel-subtitle"><%= t("simple_apm.actions.list_subtitle") %></p>
13
32
  </div>
14
33
  </div>
15
34
  <div class="apm-panel-body">
@@ -17,27 +36,28 @@
17
36
  <table id="actions-table" class="table">
18
37
  <thead>
19
38
  <tr>
20
- <th>Name</th>
21
- <th>点击次数</th>
22
- <th>平均响应时间</th>
23
- <th>平均DB时间</th>
24
- <th>平均SQL次数</th>
25
- <th>平均http访问时间</th>
26
- <th>最快响应时间</th>
27
- <th>最慢响应时间</th>
39
+ <th scope="col"><%= t("simple_apm.actions.name") %></th>
40
+ <th scope="col"><%= t("simple_apm.actions.click_count") %></th>
41
+ <th scope="col"><%= t("simple_apm.actions.avg_response_time") %></th>
42
+ <th scope="col"><%= t("simple_apm.actions.avg_db_time") %></th>
43
+ <th scope="col"><%= t("simple_apm.actions.avg_sql_count") %></th>
44
+ <th scope="col"><%= t("simple_apm.actions.avg_http_time") %></th>
45
+ <th scope="col"><%= t("simple_apm.actions.fastest_response_time") %></th>
46
+ <th scope="col"><%= t("simple_apm.actions.slowest_response_time") %></th>
28
47
  </tr>
29
48
  </thead>
30
49
  <tbody>
31
50
  <% @actions.each do |action| %>
51
+ <% has_hits = action.click_count.to_i.positive? %>
32
52
  <tr>
33
- <td><%= link_to action.name, action_info_path(action_name: action.name) %></td>
34
- <td><%= action.click_count %></td>
35
- <td><%= sec_str action.avg_time %></td>
36
- <td><%= sec_str action.avg_db_time %></td>
37
- <td><%= action.avg_queries_count.round(1) %></td>
38
- <td><%= sec_str action.avg_http_time %></td>
39
- <td><%= link_to sec_str(action.fast_time), show_path(id: action.fast_id) %></td>
40
- <td><%= link_to sec_str(action.slow_time), show_path(id: action.slow_id) %></td>
53
+ <td class="apm-mono"><%= link_to action.name, action_info_path(action_name: action.name, apm_date: apm_date) %></td>
54
+ <td data-order="<%= action.click_count.to_i %>"><%= number_with_delimiter(action.click_count.to_i) %></td>
55
+ <td data-order="<%= has_hits ? action.avg_time : 0 %>"><%= has_hits ? sec_str(action.avg_time) : '—' %></td>
56
+ <td data-order="<%= has_hits ? action.avg_db_time : 0 %>"><%= has_hits ? sec_str(action.avg_db_time) : '—' %></td>
57
+ <td data-order="<%= has_hits ? action.avg_queries_count : 0 %>"><%= has_hits ? action.avg_queries_count.round(1) : '—' %></td>
58
+ <td data-order="<%= has_hits ? action.avg_http_time : 0 %>"><%= has_hits ? sec_str(action.avg_http_time) : '—' %></td>
59
+ <td data-order="<%= action.fast_time.to_f %>"><%= action.fast_id.present? ? link_to(sec_str(action.fast_time), show_path(id: action.fast_id, apm_date: apm_date)) : '—' %></td>
60
+ <td data-order="<%= action.slow_time.to_f %>"><%= action.slow_id.present? ? link_to(sec_str(action.slow_time), show_path(id: action.slow_id, apm_date: apm_date)) : '—' %></td>
41
61
  </tr>
42
62
  <% end %>
43
63
  </tbody>
@@ -47,11 +67,10 @@
47
67
  </section>
48
68
  <script type="text/javascript">
49
69
  $(document).ready(function(){
50
- $('#actions-table').DataTable({
51
- iDisplayLength: 25,
52
- // 自定义的排序方法
53
- aoColumnDefs: [ {sType: "sec", aTargets: [2,3,5,6]}]
54
- })
70
+ $('#actions-table').DataTable(window.SimpleApmUI.tableOptions({
71
+ order: [[2, 'desc']],
72
+ columnDefs: [{type: 'num', targets: [1, 2, 3, 4, 5, 6, 7]}]
73
+ }))
55
74
 
56
75
  })
57
76
  </script>
@@ -1,76 +1,91 @@
1
1
  <div class="apm-page-header">
2
2
  <div>
3
- <h1 class="apm-page-title">性能概览</h1>
4
- <p class="apm-page-subtitle">按 10 分钟粒度观察响应时间和访问量趋势。</p>
3
+ <h1 class="apm-page-title"><%= t("simple_apm.dashboard.title") %></h1>
4
+ <p class="apm-page-subtitle"><%= t("simple_apm.dashboard.subtitle") %></p>
5
+ </div>
6
+ <div class="apm-toolbar-actions">
7
+ <%= link_to t("simple_apm.layout.nav_actions"), actions_path(apm_date: apm_date), class: 'btn apm-button-secondary' %>
8
+ <%= link_to t("simple_apm.layout.nav_slow_requests"), index_path(apm_date: apm_date), class: 'btn btn-primary' %>
5
9
  </div>
6
10
  </div>
7
11
 
8
12
  <div class="apm-metrics">
9
13
  <div class="apm-stat">
10
- <p class="apm-stat-label">统计点</p>
11
- <div class="apm-stat-value"><%= @x_names.length %></div>
12
- <div class="apm-stat-meta">10 分钟区间</div>
14
+ <p class="apm-stat-label"><%= t("simple_apm.dashboard.daily_avg_response") %></p>
15
+ <div class="apm-stat-value"><%= @daily_stats[:hits].positive? ? sec_str(@daily_stats[:avg_time]) : '—' %></div>
16
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.weighted_daily_average") %></div>
13
17
  </div>
14
18
  <div class="apm-stat">
15
- <p class="apm-stat-label">访问次数</p>
16
- <div class="apm-stat-value"><%= @hits_arr.map(&:to_i).sum %></div>
17
- <div class="apm-stat-meta">当前日期累计</div>
19
+ <p class="apm-stat-label"><%= t("simple_apm.dashboard.hits") %></p>
20
+ <div class="apm-stat-value"><%= number_with_delimiter(@daily_stats[:hits]) %></div>
21
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.current_day_total") %></div>
18
22
  </div>
19
23
  <div class="apm-stat">
20
- <p class="apm-stat-label">最高平均响应</p>
21
- <div class="apm-stat-value"><%= sec_str(@time_arr.map(&:to_f).max.to_f) %></div>
22
- <div class="apm-stat-meta">区间峰值</div>
24
+ <p class="apm-stat-label"><%= t("simple_apm.dashboard.peak_avg_response") %></p>
25
+ <div class="apm-stat-value"><%= @daily_stats[:hits].positive? ? sec_str(@time_arr.map(&:to_f).max.to_f) : '—' %></div>
26
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.interval_peak") %></div>
23
27
  </div>
24
28
  <div class="apm-stat">
25
- <p class="apm-stat-label">当前采集</p>
29
+ <p class="apm-stat-label"><%= t("simple_apm.dashboard.current_collection") %></p>
26
30
  <div class="apm-stat-value">
27
31
  <% if SimpleApm::Redis.running? %>
28
- <span class="apm-status apm-status-ok">运行中</span>
32
+ <span class="apm-status apm-status-ok"><%= t("simple_apm.common.running") %></span>
29
33
  <% else %>
30
- <span class="apm-status apm-status-danger">已暂停</span>
34
+ <span class="apm-status apm-status-danger"><%= t("simple_apm.common.paused") %></span>
31
35
  <% end %>
32
36
  </div>
33
- <div class="apm-stat-meta">Redis 状态</div>
37
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.redis_status") %></div>
34
38
  </div>
35
39
  <div class="apm-stat">
36
- <p class="apm-stat-label">查询日期</p>
37
- <div class="apm-stat-value"><%= SimpleApm::RedisKey.query_date || Time.now.strftime('%Y-%m-%d') %></div>
38
- <div class="apm-stat-meta">可在右上角切换</div>
40
+ <p class="apm-stat-label"><%= t("simple_apm.dashboard.query_date") %></p>
41
+ <div class="apm-stat-value"><%= apm_date %></div>
42
+ <div class="apm-stat-meta"><%= t("simple_apm.dashboard.switch_in_top_right") %></div>
39
43
  </div>
40
44
  </div>
41
45
 
46
+ <% if @daily_stats[:hits].zero? %>
47
+ <section class="apm-panel">
48
+ <div class="apm-empty-state">
49
+ <h2 class="apm-panel-title"><%= t("simple_apm.dashboard.no_data") %></h2>
50
+ <p><%= t("simple_apm.dashboard.no_data_hint") %></p>
51
+ <%= link_to t("simple_apm.layout.nav_data"), data_path, class: 'btn apm-button-secondary' %>
52
+ </div>
53
+ </section>
54
+ <% else %>
42
55
  <div class="apm-grid">
43
56
  <section class="apm-panel apm-col-6">
44
57
  <div class="apm-panel-header">
45
58
  <div>
46
- <h2 class="apm-panel-title">响应时间</h2>
47
- <p class="apm-panel-subtitle">每个时间段的平均响应耗时。</p>
59
+ <h2 class="apm-panel-title"><%= t("simple_apm.dashboard.response_time") %></h2>
60
+ <p class="apm-panel-subtitle"><%= t("simple_apm.dashboard.response_time_subtitle") %></p>
48
61
  </div>
49
62
  </div>
50
63
  <div class="apm-panel-body">
51
- <div id="time_chart" class="apm-chart"></div>
64
+ <div id="time_chart" class="apm-chart" role="img" aria-label="<%= t("simple_apm.dashboard.response_time") %> · <%= apm_date %>"></div>
52
65
  </div>
53
66
  </section>
54
67
 
55
68
  <section class="apm-panel apm-col-6">
56
69
  <div class="apm-panel-header">
57
70
  <div>
58
- <h2 class="apm-panel-title">访问次数</h2>
59
- <p class="apm-panel-subtitle">每个时间段的请求数量。</p>
71
+ <h2 class="apm-panel-title"><%= t("simple_apm.dashboard.hit_count") %></h2>
72
+ <p class="apm-panel-subtitle"><%= t("simple_apm.dashboard.hit_count_subtitle") %></p>
60
73
  </div>
61
74
  </div>
62
75
  <div class="apm-panel-body">
63
- <div id="hits_chart" class="apm-chart"></div>
76
+ <div id="hits_chart" class="apm-chart" role="img" aria-label="<%= t("simple_apm.dashboard.hit_count") %> · <%= apm_date %>"></div>
64
77
  </div>
65
78
  </section>
66
79
  </div>
67
80
 
68
81
  <script>
69
- var time_chart = echarts.init(document.getElementById('time_chart')),
82
+ (function () {
83
+ var time_chart = echarts.init(document.getElementById('time_chart')),
70
84
  hits_chart = echarts.init(document.getElementById('hits_chart'));
71
85
  time_chart.setOption({
86
+ animation: false,
72
87
  color: ['#0f766e'],
73
- grid: {left: 48, right: 18, top: 24, bottom: 36},
88
+ grid: {left: 16, right: 18, top: 32, bottom: 16, containLabel: true},
74
89
  tooltip: {trigger: 'axis'},
75
90
  xAxis: {
76
91
  data: <%= @x_names.to_json.html_safe %>,
@@ -79,22 +94,25 @@
79
94
  },
80
95
  yAxis: {
81
96
  type: 'value',
97
+ name: 's',
82
98
  axisLine: {show: false},
83
99
  splitLine: {lineStyle: {color: '#eef2f7'}},
84
100
  axisLabel: {color: '#667085'}
85
101
  },
86
102
  series: [{
103
+ name: '<%= j t("simple_apm.dashboard.response_time") %> (s)',
87
104
  type: 'line',
88
- smooth: true,
89
- symbolSize: 6,
105
+ showSymbol: true,
106
+ symbolSize: 4,
90
107
  areaStyle: {color: 'rgba(15, 118, 110, 0.10)'},
91
- data: <%= @time_arr.to_json.html_safe %>
108
+ data: <%= @time_arr.each_with_index.map { |time, i| @hits_arr[i].to_i.positive? ? time : nil }.to_json.html_safe %>
92
109
  }]
93
110
  })
94
111
 
95
112
  hits_chart.setOption({
113
+ animation: false,
96
114
  color: ['#2563eb'],
97
- grid: {left: 48, right: 18, top: 24, bottom: 36},
115
+ grid: {left: 16, right: 18, top: 32, bottom: 16, containLabel: true},
98
116
  tooltip: {trigger: 'axis'},
99
117
  xAxis: {
100
118
  data: <%= @x_names.to_json.html_safe %>,
@@ -103,21 +121,22 @@
103
121
  },
104
122
  yAxis: {
105
123
  type: 'value',
124
+ minInterval: 1,
106
125
  axisLine: {show: false},
107
126
  splitLine: {lineStyle: {color: '#eef2f7'}},
108
127
  axisLabel: {color: '#667085'}
109
128
  },
110
129
  series: [{
111
- type: 'line',
112
- smooth: true,
113
- symbolSize: 6,
114
- areaStyle: {color: 'rgba(37, 99, 235, 0.10)'},
130
+ name: '<%= j t("simple_apm.dashboard.hit_count") %>',
131
+ type: 'bar',
115
132
  data: <%= @hits_arr.to_json.html_safe %>
116
133
  }]
117
134
  })
118
135
 
119
- $(window).on('resize', function () {
136
+ $(window).on('resize.simpleApmCharts', function () {
120
137
  time_chart.resize()
121
138
  hits_chart.resize()
122
139
  })
140
+ })();
123
141
  </script>
142
+ <% end %>
@@ -1,35 +1,54 @@
1
1
  <div class="apm-page-header">
2
2
  <div>
3
- <h1 class="apm-page-title">数据管理</h1>
4
- <p class="apm-page-subtitle">管理采集开关和历史 Redis 数据。</p>
3
+ <h1 class="apm-page-title"><%= t("simple_apm.data.title") %></h1>
4
+ <p class="apm-page-subtitle"><%= t("simple_apm.data.subtitle") %></p>
5
+ </div>
6
+ </div>
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>
5
24
  </div>
6
25
  </div>
7
26
 
8
27
  <section class="apm-panel">
9
28
  <div class="apm-panel-header">
10
29
  <div>
11
- <h2 class="apm-panel-title">采集状态</h2>
12
- <p class="apm-panel-subtitle">暂停后 middleware 不再记录新的请求性能数据。</p>
30
+ <h2 class="apm-panel-title"><%= t("simple_apm.data.collection_status") %></h2>
31
+ <p class="apm-panel-subtitle"><%= t("simple_apm.data.collection_subtitle") %></p>
13
32
  </div>
14
33
  <div class="apm-toolbar-actions">
15
34
  <% if SimpleApm::Redis.running? %>
16
- <span class="apm-status apm-status-ok">运行中</span>
17
- <%= link_to '暂停收集数据', data_delete_path(type: 'stop_data'), class: 'btn btn-warning btn-sm', 'data-confirm'=>'确定暂停吗?' %>
35
+ <span class="apm-status apm-status-ok"><%= t("simple_apm.common.running") %></span>
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
- <span class="apm-status apm-status-danger">已暂停</span>
20
- <%= link_to '继续收集数据', data_delete_path(type: 'rerun_data'), class: 'btn btn-primary btn-sm' %>
38
+ <span class="apm-status apm-status-danger"><%= t("simple_apm.common.paused") %></span>
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>
24
43
  <div class="apm-panel-body">
25
44
  <div class="apm-toolbar">
26
45
  <div>
27
- <strong>删除数据</strong>
28
- <p class="apm-page-subtitle">按保留周期清理历史数据,或删除单日数据。</p>
46
+ <strong><%= t("simple_apm.data.delete_data") %></strong>
47
+ <p class="apm-page-subtitle"><%= t("simple_apm.data.delete_subtitle") %></p>
29
48
  </div>
30
49
  <div class="apm-toolbar-actions">
31
- <%= link_to '保留一周数据', data_delete_path(type: 'week'), class: 'btn btn-danger', 'data-confirm' => '确定删除所有一周以前的数据?' %>
32
- <%= link_to '保留一个月数据', data_delete_path(type: 'month'), class: 'btn btn-danger', 'data-confirm' => '确定删除所有一个月以前的数据?' %>
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>
@@ -38,33 +57,58 @@
38
57
  <section class="apm-panel">
39
58
  <div class="apm-panel-header">
40
59
  <div>
41
- <h2 class="apm-panel-title">历史数据</h2>
42
- <p class="apm-panel-subtitle">以日期为单位查看采集量和平均响应时间。</p>
60
+ <h2 class="apm-panel-title"><%= t("simple_apm.data.history_title") %></h2>
61
+ <p class="apm-panel-subtitle"><%= t("simple_apm.data.history_subtitle") %></p>
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 class="table table-bordered">
72
+ <table id="history-table" class="table">
48
73
  <thead>
49
74
  <tr>
50
- <th>日期</th>
51
- <th>请求数量</th>
52
- <th>平均响应时间</th>
53
- <th>操作</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
- <!-- {day: date_str, hits: hits, time: time, avg_time: avg_time}-->
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 d[:avg_time] %></td>
63
- <td><%= link_to '删除', data_delete_path(date: d[:day]), class: 'apm-danger-link', 'data-confirm' => '确定删除?' %></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 %>
@@ -1,32 +1,40 @@
1
1
  <div class="apm-page-header">
2
2
  <div>
3
- <h1 class="apm-page-title">慢事务列表</h1>
4
- <p class="apm-page-subtitle">按响应耗时排序,快速定位 DB、SQL、View 和外部请求占比。</p>
3
+ <h1 class="apm-page-title"><%= t("simple_apm.index.title") %></h1>
4
+ <p class="apm-page-subtitle"><%= t("simple_apm.index.subtitle") %></p>
5
5
  </div>
6
6
  </div>
7
7
 
8
8
  <section class="apm-panel">
9
9
  <div class="apm-panel-header">
10
10
  <div>
11
- <h2 class="apm-panel-title">请求样本</h2>
12
- <p class="apm-panel-subtitle">默认加载最近的慢请求记录。</p>
11
+ <h2 class="apm-panel-title"><%= t("simple_apm.index.samples_title") %></h2>
12
+ <p class="apm-panel-subtitle"><%= t("simple_apm.index.samples_subtitle") %></p>
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>
13
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>请求时间</th>
21
- <th>ActionName</th>
22
- <th>TotalTime</th>
23
- <th>DB</th>
24
- <th>SQL</th>
25
- <th>View</th>
26
- <th>HTTP</th>
27
- <th>Memory(Mb)</th>
28
- <th>server</th>
29
- <th>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
- $('#slow-requests').DataTable({
40
- ajax: '<%= index_path %>.json',
41
- iDisplayLength: 25,
42
- ordering: false
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>