simple_apm 1.0.14 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eb5367e4179faa354aa59c16c8bd9f13ef706e8f
4
- data.tar.gz: f46424a7e5257d7b29821b5b055e4e8068c51f8d
2
+ SHA256:
3
+ metadata.gz: 20c4854a122796cdb1c34546e8808f04ad6137c8d3d5e1936b547d329822fa9f
4
+ data.tar.gz: 74a75a66e084d2d5464a42a1e594fe74575c9d5bba915570c1196b66e99eb5c7
5
5
  SHA512:
6
- metadata.gz: 0d3f3a4be257b6148bf1baa872f39774166e021a3926333c372cd9122f735e2e0271b24d5d091d6dfd1262306800dcd3b9ebf76d49c17a825884a9be9b4db647
7
- data.tar.gz: ac480c8f99332d9fe00b3c82bc14d685589633754d96ac4e6703722ab2c8e6d85d3d5e3d60da4cae3fbe1a773ed48be5b3d88c057dcca1b8e443158d8fc8628f
6
+ metadata.gz: 8253d3b452494e21d4fed612fd6f1076435296ba689750ac6ea72055931bd56909968e99707fb3d448aacd9f1c6829cf28ff78c9e2d56a7b90f9125e1a296aa7
7
+ data.tar.gz: 2617e187209c01c3d3eb7413aef561dd80c295b95dd8ca10a7b1282cc918847afef4bb3b1decd5dbc85ebf0e6beddbce769b8ba6a3aecfb92260173e6d0a3a40
data/Rakefile CHANGED
@@ -17,11 +17,6 @@ end
17
17
  APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
18
  load 'rails/tasks/engine.rake'
19
19
 
20
-
21
- load 'rails/tasks/statistics.rake'
22
-
23
-
24
-
25
20
  require 'bundler/gem_tasks'
26
21
 
27
22
  require 'rake/testtask'
@@ -12,4 +12,575 @@
12
12
  *
13
13
  *= require_tree .
14
14
  *= require_self
15
- */
15
+ */
16
+
17
+ :root {
18
+ --apm-bg: #f4f7fb;
19
+ --apm-surface: #ffffff;
20
+ --apm-surface-soft: #f8fafc;
21
+ --apm-ink: #172033;
22
+ --apm-muted: #667085;
23
+ --apm-border: #dce3ee;
24
+ --apm-border-strong: #c8d2df;
25
+ --apm-brand: #0f766e;
26
+ --apm-brand-dark: #0b4f4a;
27
+ --apm-accent: #2563eb;
28
+ --apm-danger: #dc2626;
29
+ --apm-warning: #d97706;
30
+ --apm-success: #15803d;
31
+ --apm-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
32
+ }
33
+
34
+ body.simple-apm {
35
+ margin: 0;
36
+ background: var(--apm-bg);
37
+ color: var(--apm-ink);
38
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
39
+ font-size: 14px;
40
+ letter-spacing: 0;
41
+ }
42
+
43
+ .simple-apm a {
44
+ color: var(--apm-accent);
45
+ }
46
+
47
+ .simple-apm a:hover {
48
+ color: #1d4ed8;
49
+ }
50
+
51
+ .apm-shell {
52
+ min-height: calc(100vh - 96px);
53
+ }
54
+
55
+ .apm-topbar {
56
+ position: sticky;
57
+ top: 0;
58
+ z-index: 1000;
59
+ background: #101827;
60
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
61
+ box-shadow: 0 10px 30px rgba(15, 23, 42, 0.18);
62
+ }
63
+
64
+ .apm-topbar-inner {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 24px;
68
+ min-height: 64px;
69
+ width: min(1440px, calc(100% - 48px));
70
+ margin: 0 auto;
71
+ }
72
+
73
+ .apm-brand {
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 10px;
77
+ color: #ffffff;
78
+ flex: 0 0 auto;
79
+ }
80
+
81
+ .apm-brand-mark {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ width: 34px;
86
+ height: 34px;
87
+ border-radius: 8px;
88
+ background: #14b8a6;
89
+ color: #052e2b;
90
+ font-weight: 800;
91
+ font-size: 13px;
92
+ }
93
+
94
+ .apm-brand-name {
95
+ font-weight: 700;
96
+ font-size: 16px;
97
+ }
98
+
99
+ .apm-nav {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 6px;
103
+ flex: 1 1 auto;
104
+ }
105
+
106
+ .apm-nav .navbar-brand {
107
+ float: none;
108
+ height: auto;
109
+ padding: 9px 12px;
110
+ color: #cbd5e1;
111
+ font-size: 13px;
112
+ line-height: 18px;
113
+ border-radius: 6px;
114
+ }
115
+
116
+ .apm-nav .navbar-brand:hover,
117
+ .apm-nav .navbar-brand:focus {
118
+ color: #ffffff;
119
+ background: rgba(255, 255, 255, 0.08);
120
+ text-decoration: none;
121
+ }
122
+
123
+ .apm-nav .navbar-brand.active {
124
+ color: #ffffff !important;
125
+ background: rgba(20, 184, 166, 0.22);
126
+ }
127
+
128
+ .apm-date-select {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 10px;
132
+ color: #cbd5e1;
133
+ font-size: 13px;
134
+ flex: 0 0 auto;
135
+ }
136
+
137
+ .apm-date-select select.form-control {
138
+ width: auto;
139
+ min-width: 138px;
140
+ height: 34px;
141
+ color: #172033;
142
+ border: 0;
143
+ border-radius: 6px;
144
+ box-shadow: none;
145
+ }
146
+
147
+ .apm-content {
148
+ width: min(1440px, calc(100% - 48px));
149
+ margin: 0 auto;
150
+ padding: 28px 0 40px;
151
+ }
152
+
153
+ .apm-page-header {
154
+ display: flex;
155
+ align-items: flex-end;
156
+ justify-content: space-between;
157
+ gap: 24px;
158
+ margin-bottom: 18px;
159
+ }
160
+
161
+ .apm-page-title {
162
+ margin: 0;
163
+ color: var(--apm-ink);
164
+ font-size: 26px;
165
+ line-height: 1.2;
166
+ font-weight: 700;
167
+ }
168
+
169
+ .apm-page-subtitle {
170
+ margin: 7px 0 0;
171
+ color: var(--apm-muted);
172
+ font-size: 13px;
173
+ }
174
+
175
+ .apm-toolbar {
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: space-between;
179
+ gap: 14px;
180
+ margin-bottom: 18px;
181
+ }
182
+
183
+ .apm-toolbar-actions {
184
+ display: flex;
185
+ align-items: center;
186
+ flex-wrap: wrap;
187
+ gap: 8px;
188
+ }
189
+
190
+ .apm-grid {
191
+ display: grid;
192
+ grid-template-columns: repeat(12, minmax(0, 1fr));
193
+ gap: 18px;
194
+ }
195
+
196
+ .apm-col-6 {
197
+ grid-column: span 6;
198
+ }
199
+
200
+ .apm-col-12 {
201
+ grid-column: span 12;
202
+ }
203
+
204
+ .apm-panel {
205
+ background: var(--apm-surface);
206
+ border: 1px solid var(--apm-border);
207
+ border-radius: 8px;
208
+ box-shadow: var(--apm-shadow);
209
+ }
210
+
211
+ .apm-panel + .apm-panel {
212
+ margin-top: 18px;
213
+ }
214
+
215
+ .apm-panel-header {
216
+ display: flex;
217
+ align-items: center;
218
+ justify-content: space-between;
219
+ gap: 16px;
220
+ padding: 16px 18px 0;
221
+ }
222
+
223
+ .apm-panel-title {
224
+ margin: 0;
225
+ color: var(--apm-ink);
226
+ font-size: 16px;
227
+ line-height: 1.3;
228
+ font-weight: 700;
229
+ }
230
+
231
+ .apm-panel-subtitle {
232
+ margin: 4px 0 0;
233
+ color: var(--apm-muted);
234
+ font-size: 12px;
235
+ }
236
+
237
+ .apm-panel-body {
238
+ padding: 18px;
239
+ }
240
+
241
+ .apm-chart {
242
+ height: 360px;
243
+ width: 100%;
244
+ }
245
+
246
+ .apm-metrics {
247
+ display: grid;
248
+ grid-template-columns: repeat(5, minmax(0, 1fr));
249
+ gap: 12px;
250
+ margin-bottom: 18px;
251
+ }
252
+
253
+ .apm-stat {
254
+ min-width: 0;
255
+ padding: 14px 16px;
256
+ background: var(--apm-surface);
257
+ border: 1px solid var(--apm-border);
258
+ border-radius: 8px;
259
+ box-shadow: 0 10px 24px rgba(15, 23, 42, 0.05);
260
+ }
261
+
262
+ .apm-stat-label {
263
+ margin: 0 0 8px;
264
+ color: var(--apm-muted);
265
+ font-size: 12px;
266
+ line-height: 1.2;
267
+ }
268
+
269
+ .apm-stat-value {
270
+ color: var(--apm-ink);
271
+ font-size: 20px;
272
+ line-height: 1.2;
273
+ font-weight: 700;
274
+ word-break: break-word;
275
+ }
276
+
277
+ .apm-stat-meta {
278
+ margin-top: 6px;
279
+ color: var(--apm-muted);
280
+ font-size: 12px;
281
+ }
282
+
283
+ .apm-detail-list {
284
+ display: grid;
285
+ grid-template-columns: 140px minmax(0, 1fr);
286
+ gap: 10px 16px;
287
+ margin: 0;
288
+ }
289
+
290
+ .apm-detail-list dt {
291
+ color: var(--apm-muted);
292
+ font-weight: 600;
293
+ }
294
+
295
+ .apm-detail-list dd {
296
+ margin: 0;
297
+ min-width: 0;
298
+ word-break: break-word;
299
+ }
300
+
301
+ .apm-table-wrap {
302
+ overflow-x: auto;
303
+ }
304
+
305
+ .simple-apm table.table,
306
+ .simple-apm table.dataTable {
307
+ width: 100% !important;
308
+ margin: 0 !important;
309
+ background: var(--apm-surface);
310
+ border-collapse: separate !important;
311
+ border-spacing: 0;
312
+ }
313
+
314
+ .simple-apm table.table > thead > tr > th,
315
+ .simple-apm table.table > thead > tr > td,
316
+ .simple-apm table.dataTable thead th {
317
+ padding: 12px 14px;
318
+ color: #475467;
319
+ background: var(--apm-surface-soft);
320
+ border-bottom: 1px solid var(--apm-border);
321
+ font-size: 12px;
322
+ font-weight: 700;
323
+ white-space: nowrap;
324
+ }
325
+
326
+ .simple-apm table.table > tbody > tr > td,
327
+ .simple-apm table.dataTable tbody td {
328
+ padding: 12px 14px;
329
+ border-top: 1px solid #eef2f7;
330
+ color: #243044;
331
+ vertical-align: middle;
332
+ }
333
+
334
+ .simple-apm table.table-bordered {
335
+ border: 1px solid var(--apm-border);
336
+ border-radius: 8px;
337
+ overflow: hidden;
338
+ }
339
+
340
+ .simple-apm table.table-bordered > thead > tr > th,
341
+ .simple-apm table.table-bordered > tbody > tr > td,
342
+ .simple-apm table.table-bordered > tbody > tr > th {
343
+ border-color: var(--apm-border);
344
+ }
345
+
346
+ .simple-apm .dataTables_wrapper {
347
+ padding: 0;
348
+ }
349
+
350
+ .simple-apm .dataTables_wrapper .dataTables_length,
351
+ .simple-apm .dataTables_wrapper .dataTables_filter {
352
+ margin: 0 0 12px;
353
+ color: var(--apm-muted);
354
+ }
355
+
356
+ .simple-apm .dataTables_wrapper .dataTables_filter input,
357
+ .simple-apm .dataTables_wrapper .dataTables_length select {
358
+ height: 32px;
359
+ border: 1px solid var(--apm-border);
360
+ border-radius: 6px;
361
+ padding: 4px 8px;
362
+ background: #ffffff;
363
+ color: var(--apm-ink);
364
+ box-shadow: none;
365
+ }
366
+
367
+ .simple-apm .dataTables_wrapper .dataTables_info,
368
+ .simple-apm .dataTables_wrapper .dataTables_paginate {
369
+ margin-top: 12px;
370
+ color: var(--apm-muted);
371
+ font-size: 12px;
372
+ }
373
+
374
+ .simple-apm .dataTables_wrapper .dataTables_paginate .paginate_button {
375
+ border: 1px solid transparent !important;
376
+ border-radius: 6px;
377
+ }
378
+
379
+ .simple-apm .dataTables_wrapper .dataTables_paginate .paginate_button.current {
380
+ background: var(--apm-brand) !important;
381
+ border-color: var(--apm-brand) !important;
382
+ color: #ffffff !important;
383
+ }
384
+
385
+ .simple-apm .btn {
386
+ border-radius: 6px;
387
+ font-weight: 600;
388
+ }
389
+
390
+ .simple-apm a.btn,
391
+ .simple-apm a.btn:hover,
392
+ .simple-apm a.btn:focus {
393
+ color: #ffffff;
394
+ text-decoration: none;
395
+ }
396
+
397
+ .simple-apm .btn-primary,
398
+ .simple-apm .btn-primary:hover,
399
+ .simple-apm .btn-primary:focus {
400
+ background: var(--apm-accent);
401
+ border-color: var(--apm-accent);
402
+ }
403
+
404
+ .simple-apm .btn-warning,
405
+ .simple-apm .btn-warning:hover,
406
+ .simple-apm .btn-warning:focus {
407
+ background: var(--apm-warning);
408
+ border-color: var(--apm-warning);
409
+ }
410
+
411
+ .simple-apm .btn-danger,
412
+ .simple-apm .btn-danger:hover,
413
+ .simple-apm .btn-danger:focus {
414
+ background: var(--apm-danger);
415
+ border-color: var(--apm-danger);
416
+ }
417
+
418
+ .apm-danger-link {
419
+ color: var(--apm-danger);
420
+ font-weight: 600;
421
+ }
422
+
423
+ .apm-status {
424
+ display: inline-flex;
425
+ align-items: center;
426
+ min-height: 24px;
427
+ padding: 3px 9px;
428
+ border-radius: 999px;
429
+ font-size: 12px;
430
+ font-weight: 700;
431
+ }
432
+
433
+ .apm-status-ok {
434
+ color: #065f46;
435
+ background: #d1fae5;
436
+ }
437
+
438
+ .apm-status-danger {
439
+ color: #991b1b;
440
+ background: #fee2e2;
441
+ }
442
+
443
+ .apm-status-warning {
444
+ color: #92400e;
445
+ background: #fef3c7;
446
+ }
447
+
448
+ .sql {
449
+ max-width: 520px;
450
+ white-space: nowrap;
451
+ text-overflow: ellipsis;
452
+ overflow: hidden;
453
+ color: var(--apm-accent);
454
+ cursor: pointer;
455
+ font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace;
456
+ font-size: 12px;
457
+ }
458
+
459
+ pre {
460
+ white-space: pre-wrap;
461
+ }
462
+
463
+ .apm-modal-panel {
464
+ background: #ffffff;
465
+ border-radius: 8px;
466
+ box-shadow: 0 24px 80px rgba(15, 23, 42, 0.24);
467
+ overflow: hidden;
468
+ }
469
+
470
+ .apm-modal-header {
471
+ padding: 14px 18px;
472
+ border-bottom: 1px solid var(--apm-border);
473
+ background: var(--apm-surface-soft);
474
+ }
475
+
476
+ .apm-modal-title {
477
+ color: var(--apm-ink);
478
+ font-size: 15px;
479
+ font-weight: 700;
480
+ }
481
+
482
+ .apm-modal-body {
483
+ padding: 18px;
484
+ }
485
+
486
+ .apm-modal-body pre.modal-content {
487
+ margin: 0;
488
+ padding: 14px;
489
+ border: 1px solid var(--apm-border);
490
+ border-radius: 8px;
491
+ background: #0f172a;
492
+ color: #d1e7ff;
493
+ box-shadow: none;
494
+ }
495
+
496
+ .apm-footer {
497
+ width: min(1440px, calc(100% - 48px));
498
+ margin: 0 auto;
499
+ padding: 18px 0 26px;
500
+ color: var(--apm-muted);
501
+ border-top: 1px solid var(--apm-border);
502
+ }
503
+
504
+ .apm-footer-status {
505
+ margin-bottom: 10px;
506
+ }
507
+
508
+ .apm-footer-meta {
509
+ display: flex;
510
+ flex-wrap: wrap;
511
+ gap: 10px 18px;
512
+ font-size: 12px;
513
+ }
514
+
515
+ .apm-footer-meta label {
516
+ margin: 0;
517
+ color: #475467;
518
+ }
519
+
520
+ @media (max-width: 980px) {
521
+ .apm-topbar-inner,
522
+ .apm-content,
523
+ .apm-footer {
524
+ width: min(100% - 28px, 1440px);
525
+ }
526
+
527
+ .apm-topbar-inner {
528
+ flex-wrap: wrap;
529
+ padding: 12px 0;
530
+ }
531
+
532
+ .apm-nav {
533
+ order: 3;
534
+ width: 100%;
535
+ overflow-x: auto;
536
+ }
537
+
538
+ .apm-date-select {
539
+ margin-left: auto;
540
+ }
541
+
542
+ .apm-page-header,
543
+ .apm-toolbar {
544
+ align-items: flex-start;
545
+ flex-direction: column;
546
+ }
547
+
548
+ .apm-col-6 {
549
+ grid-column: span 12;
550
+ }
551
+
552
+ .apm-metrics {
553
+ grid-template-columns: repeat(2, minmax(0, 1fr));
554
+ }
555
+ }
556
+
557
+ @media (max-width: 640px) {
558
+ .apm-brand-name {
559
+ display: none;
560
+ }
561
+
562
+ .apm-date-select {
563
+ width: 100%;
564
+ justify-content: space-between;
565
+ }
566
+
567
+ .apm-date-select select.form-control {
568
+ flex: 1 1 auto;
569
+ }
570
+
571
+ .apm-content {
572
+ padding-top: 20px;
573
+ }
574
+
575
+ .apm-page-title {
576
+ font-size: 22px;
577
+ }
578
+
579
+ .apm-metrics {
580
+ grid-template-columns: 1fr;
581
+ }
582
+
583
+ .apm-detail-list {
584
+ grid-template-columns: 1fr;
585
+ }
586
+ }
@@ -23,6 +23,7 @@ module SimpleApm
23
23
  link_to(request.action_name, action_info_path(action_name: request.action_name)),
24
24
  sec_str(request.during),
25
25
  sec_str(request.db_runtime),
26
+ request.queries_count,
26
27
  sec_str(request.view_runtime),
27
28
  sec_str(request.net_http_during),
28
29
  request.memory_during.to_f.round(1),
@@ -1,7 +1,8 @@
1
1
  # 请求 Controller#Action
2
2
  module SimpleApm
3
3
  class Action
4
- attr_accessor :name, :click_count, :time, :http_time, :slow_time, :slow_id, :fast_time, :fast_id
4
+ attr_accessor :name, :click_count, :time, :db_time, :queries_count, :cached_queries_count,
5
+ :http_time, :slow_time, :slow_id, :fast_time, :fast_id
5
6
 
6
7
  def initialize(h)
7
8
  h.each do |k, v|
@@ -25,6 +26,18 @@ module SimpleApm
25
26
  http_time.to_f/click_count.to_i
26
27
  end
27
28
 
29
+ def avg_db_time
30
+ db_time.to_f/click_count.to_i
31
+ end
32
+
33
+ def avg_queries_count
34
+ queries_count.to_f/click_count.to_i
35
+ end
36
+
37
+ def avg_cached_queries_count
38
+ cached_queries_count.to_f/click_count.to_i
39
+ end
40
+
28
41
  def avg_time
29
42
  time.to_f/click_count.to_i
30
43
  end
@@ -43,6 +56,12 @@ module SimpleApm
43
56
  SimpleApm::Redis.hincrby _key, 'click_count', 1
44
57
  # 总时间
45
58
  SimpleApm::Redis.hincrbyfloat _key, 'time', h['during']
59
+ # 数据库访问时间
60
+ SimpleApm::Redis.hincrbyfloat _key, 'db_time', h['db_runtime']
61
+ # SQL执行次数
62
+ SimpleApm::Redis.hincrby _key, 'queries_count', h['queries_count'].to_i
63
+ # SQL缓存命中次数
64
+ SimpleApm::Redis.hincrby _key, 'cached_queries_count', h['cached_queries_count'].to_i
46
65
  # 外部http访问时间
47
66
  SimpleApm::Redis.hincrbyfloat _key, 'http_time', h['net_http_during']
48
67
  _slow = SimpleApm::Redis.hget _key, 'slow_time'
@@ -3,6 +3,7 @@ module SimpleApm
3
3
  class Request
4
4
  attr_accessor :request_id, :action_name,
5
5
  :during, :started, :db_runtime, :view_runtime,
6
+ :queries_count, :cached_queries_count,
6
7
  :controller, :action, :format, :method,
7
8
  :host, :remote_addr, :url, :completed_memory, :memory_during,
8
9
  :exception, :status, :net_http_during