test-prof 0.4.9 → 0.5.0.pre1
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/CHANGELOG.md +63 -20
- data/README.md +10 -57
- data/assets/tagprof.demo.html +447 -0
- data/assets/tagprof.template.html +447 -0
- data/lib/minitest/event_prof_formatter.rb +18 -16
- data/lib/test_prof.rb +2 -1
- data/lib/test_prof/any_fixture.rb +80 -4
- data/lib/test_prof/any_fixture/dsl.rb +18 -0
- data/lib/test_prof/event_prof.rb +10 -108
- data/lib/test_prof/event_prof/custom_events.rb +30 -0
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -1
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +1 -1
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +1 -1
- data/lib/test_prof/event_prof/minitest.rb +6 -0
- data/lib/test_prof/event_prof/profiler.rb +129 -0
- data/lib/test_prof/event_prof/rspec.rb +20 -11
- data/lib/test_prof/factory_all_stub.rb +32 -0
- data/lib/test_prof/factory_all_stub/factory_bot_patch.rb +13 -0
- data/lib/test_prof/factory_doctor/rspec.rb +3 -2
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +9 -13
- data/lib/test_prof/recipes/active_record_shared_connection.rb +55 -0
- data/lib/test_prof/recipes/logging.rb +37 -0
- data/lib/test_prof/recipes/rspec/any_fixture.rb +4 -1
- data/lib/test_prof/recipes/rspec/factory_all_stub.rb +10 -0
- data/lib/test_prof/rspec_dissect/rspec.rb +4 -2
- data/lib/test_prof/rspec_stamp/rspec.rb +3 -2
- data/lib/test_prof/tag_prof.rb +4 -0
- data/lib/test_prof/tag_prof/printers/html.rb +24 -0
- data/lib/test_prof/tag_prof/printers/simple.rb +82 -0
- data/lib/test_prof/tag_prof/result.rb +38 -0
- data/lib/test_prof/tag_prof/rspec.rb +43 -40
- data/lib/test_prof/utils/html_builder.rb +21 -0
- data/lib/test_prof/version.rb +1 -1
- metadata +20 -24
- data/assets/logo.svg +0 -1
- data/assets/testprof.png +0 -0
- data/guides/.rubocop.yml +0 -1
- data/guides/any_fixture.md +0 -114
- data/guides/before_all.md +0 -98
- data/guides/event_prof.md +0 -177
- data/guides/factory_default.md +0 -111
- data/guides/factory_doctor.md +0 -119
- data/guides/factory_prof.md +0 -86
- data/guides/let_it_be.md +0 -97
- data/guides/rspec_dissect.md +0 -60
- data/guides/rspec_stamp.md +0 -52
- data/guides/rubocop.md +0 -48
- data/guides/ruby_prof.md +0 -63
- data/guides/stack_prof.md +0 -47
- data/guides/tag_prof.md +0 -51
- data/guides/tests_sampling.md +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8953166be33111ca0da788c4a867d5bda07d8df917cd486dda045d5464ce44ab
|
4
|
+
data.tar.gz: fbfb78a5ff1e616f0d31af9d581193d5be8e2623615c55e7ceeb785d2e5ade75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c1f8760b6579505b15a5866491719002d46adb2a9b7706352f41d626d4cfb813a15540aa699ccd3220333f12ec44fbbbd98f42ec46f8bf862f82595b0dad241
|
7
|
+
data.tar.gz: 3bf3d97c16cd4793729b9f03d3891c127f8560a83c06881d3ccd627ae8d3714650721a09e106ad6cc7ba8130300f917e5bc3482e80165a738701fb23419c9494
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,50 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
-
|
5
|
+
- Add events support to TagProf. ([@palkan][])
|
6
|
+
|
7
|
+
Example usage:
|
8
|
+
|
9
|
+
```sh
|
10
|
+
TAG_PROF=type TAG_PROF_EVENT=sql.active_record rspec
|
11
|
+
```
|
12
|
+
|
13
|
+
- Add logging helpers for Rails. ([@palkan][])
|
14
|
+
|
15
|
+
- Add ability to track multiple events at the same time with `EventProf`. ([@palkan][])
|
16
|
+
|
17
|
+
- Add HTML report for `TagProf`. ([@palkan][])
|
18
|
+
|
19
|
+
Generate HTML report by setting `TAG_PROF_FORMAT` to `html`.
|
20
|
+
|
21
|
+
- Add `AnyFixture` DSL. ([@palkan][])
|
22
|
+
|
23
|
+
Example:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Enable DSL
|
27
|
+
using TestProf::AnyFixture::DSL
|
28
|
+
|
29
|
+
# and then you can use `fixture` method (which is just an alias for `TestProf::AnyFixture.register`)
|
30
|
+
before(:all) { fixture(:account) }
|
31
|
+
|
32
|
+
# You can also use it to fetch the record (instead of storing it in instance variable)
|
33
|
+
let(:account) { fixture(:account) }
|
34
|
+
```
|
35
|
+
|
36
|
+
- Add `AnyFixture` usage report. ([@palkan][])
|
37
|
+
|
38
|
+
Enable `AnyFixture` usage reporting with:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
TestProf::AnyFixture.reporting_enabled = true
|
42
|
+
```
|
43
|
+
|
44
|
+
- Add `ActiveRecordSharedConnection` recipe. ([@palkan][])
|
45
|
+
|
46
|
+
- [#70](https://github.com/palkan/test-prof/pull/70) Add `FactoryAllStub` recipe. ([@palkan][])
|
47
|
+
|
48
|
+
## 0.4.9 (2018-03-20)
|
6
49
|
|
7
50
|
- [Fix [#64](https://github.com/palkan/test-prof/issues/64)] Fix dependencies requiring for FactoryDefault. ([@palkan][])
|
8
51
|
|
@@ -11,7 +54,7 @@
|
|
11
54
|
Consider only `example_failed` and `example_passed` to ensure that the `run_time`
|
12
55
|
is available.
|
13
56
|
|
14
|
-
## 0.4.8
|
57
|
+
## 0.4.8 (2018-01-17)
|
15
58
|
|
16
59
|
- Add `minitest` 5.11 support. ([@palkan][])
|
17
60
|
|
@@ -24,36 +67,36 @@
|
|
24
67
|
|
25
68
|
Possibly fixes [#47](https://github.com/palkan/test-prof/issues/47).
|
26
69
|
|
27
|
-
## 0.4.7
|
70
|
+
## 0.4.7 (2017-12-25)
|
28
71
|
|
29
72
|
- [#57](https://github.com/palkan/test-prof/pull/57) Fix RubyProf Printers Support ([@rabotyaga][])
|
30
73
|
|
31
|
-
## 0.4.6
|
74
|
+
## 0.4.6 (2017-12-17)
|
32
75
|
|
33
76
|
- Upgrade RSpec/AggregateFailures to RuboCop 0.52.0. ([@palkan][])
|
34
77
|
|
35
78
|
RuboCop < 0.51.0 is not supported anymore.
|
36
79
|
|
37
|
-
- [Fixes [#49](https://github.com/palkan/test-prof/issues/49)]
|
80
|
+
- [Fixes [#49](https://github.com/palkan/test-prof/issues/49)] Correctly detect RSpec version in `let_it_be`. ([@desoleary][])
|
38
81
|
|
39
|
-
## 0.4.5
|
82
|
+
## 0.4.5 (2017-12-09)
|
40
83
|
|
41
84
|
- Fix circular require in `lib/factory_doctor/minitest`. ([@palkan][])
|
42
85
|
|
43
|
-
## 0.4.4
|
86
|
+
## 0.4.4 (2017-11-08)
|
44
87
|
|
45
88
|
- [Fixes [#48](https://github.com/palkan/test-prof/issues/48)] Respect RubyProf reports files extensions. ([@palkan][])
|
46
89
|
|
47
|
-
## 0.4.3
|
90
|
+
## 0.4.3 (2017-10-26)
|
48
91
|
|
49
92
|
- [#46](https://github.com/palkan/test-prof/pull/46) Support FactoryBot, which is [former FactoryGirl](https://github.com/thoughtbot/factory_bot/pull/1051),
|
50
93
|
while maintaining compatibility with latter. ([@Shkrt][])
|
51
94
|
|
52
|
-
## 0.4.2
|
95
|
+
## 0.4.2 (2017-10-23)
|
53
96
|
|
54
97
|
- Fix bug with multiple `before_all` within one group. ([@palkan][])
|
55
98
|
|
56
|
-
## 0.4.1
|
99
|
+
## 0.4.1 (2017-10-18)
|
57
100
|
|
58
101
|
- [#44](https://github.com/palkan/test-prof/pull/44) Support older versions of RSpec. ([@palkan][])
|
59
102
|
|
@@ -67,7 +110,7 @@ RSpecDissect `let` tracking supports only RSpec 3.3.0+.
|
|
67
110
|
|
68
111
|
It is possible now to use Factory Doctor with Minitest
|
69
112
|
|
70
|
-
## 0.4.0
|
113
|
+
## 0.4.0 (2017-10-03)
|
71
114
|
|
72
115
|
### Features:
|
73
116
|
|
@@ -79,7 +122,7 @@ It is possible now to use Event Prof with Minitest
|
|
79
122
|
|
80
123
|
FactoryProf now also accounts objects created by Fabrication gem (in addition to FactoryGirl)
|
81
124
|
|
82
|
-
## 0.3.0
|
125
|
+
## 0.3.0 (2017-09-21)
|
83
126
|
|
84
127
|
### Features:
|
85
128
|
|
@@ -116,21 +159,21 @@ Just like `let`, but persist the result for the whole group (i.e. `let` + `befor
|
|
116
159
|
|
117
160
|
- Use RubyProf `FlatPrinter` by default (was `CallStackPrinter`). ([@palkan][])
|
118
161
|
|
119
|
-
## 0.2.5
|
162
|
+
## 0.2.5 (2017-08-30)
|
120
163
|
|
121
164
|
- [#16](https://github.com/palkan/test-prof/pull/16) Support Ruby >= 2.2.0 (was >= 2.3.0). ([@palkan][])
|
122
165
|
|
123
|
-
## 0.2.4
|
166
|
+
## 0.2.4 (2017-08-29)
|
124
167
|
|
125
168
|
- EventProf: Fix regression bug with examples profiling. ([@palkan][])
|
126
169
|
|
127
170
|
There was a bug when an event occurs before the example has started (e.g. in `before(:context)` hook).
|
128
171
|
|
129
|
-
## 0.2.3
|
172
|
+
## 0.2.3 (2017-08-28)
|
130
173
|
|
131
174
|
- Minor improvements. ([@palkan][])
|
132
175
|
|
133
|
-
## 0.2.2
|
176
|
+
## 0.2.2 (2017-08-23)
|
134
177
|
|
135
178
|
- Fix time calculation when Time class is monkey-patched. ([@palkan][])
|
136
179
|
|
@@ -139,13 +182,13 @@ use it everywhere.
|
|
139
182
|
|
140
183
|
Fixes [#10](https://github.com/palkan/test-prof/issues/10).
|
141
184
|
|
142
|
-
## 0.2.1
|
185
|
+
## 0.2.1 (2017-08-19)
|
143
186
|
|
144
187
|
- Detect `RSpec` by checking the presence of `RSpec::Core`. ([@palkan][])
|
145
188
|
|
146
189
|
Fixes [#8](https://github.com/palkan/test-prof/issues/8).
|
147
190
|
|
148
|
-
## 0.2.0
|
191
|
+
## 0.2.0 (2017-08-18)
|
149
192
|
|
150
193
|
- Ensure output directory exists. ([@danielwestendorf][])
|
151
194
|
|
@@ -157,11 +200,11 @@ Ensure output dir exists in `#artifact_path` method.
|
|
157
200
|
|
158
201
|
- FactoryDoctor: print success message when no bad examples found. ([@palkan][])
|
159
202
|
|
160
|
-
## 0.1.1
|
203
|
+
## 0.1.1 (2017-08-17)
|
161
204
|
|
162
205
|
- AnyFixture: clean tables in reverse order to not fail when foreign keys exist. ([@marshall-lee][])
|
163
206
|
|
164
|
-
## 0.1.0
|
207
|
+
## 0.1.0 (2017-08-15)
|
165
208
|
|
166
209
|
- Initial version. ([@palkan][])
|
167
210
|
|
data/README.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
[](https://rubygems.org/gems/test-prof) [](https://travis-ci.org/palkan/test-prof) [](https://rubygems.org/gems/test-prof) [](https://travis-ci.org/palkan/test-prof) [](https://www.codetriage.com/palkan/test-prof)
|
2
|
+
[](https://test-prof.evilmartians.io)
|
2
3
|
|
3
4
|
# Ruby Tests Profiling Toolbox
|
4
5
|
|
5
6
|
<img align="right" height="150" width="129"
|
6
|
-
title="TestProf logo" src="./assets/logo.svg">
|
7
|
+
title="TestProf logo" src="./docs/assets/images/logo.svg">
|
7
8
|
|
8
9
|
TestProf is a collection of different tools to analyze your test suite performance.
|
9
10
|
|
@@ -23,11 +24,11 @@ TestProf toolbox aims to help you identify bottlenecks in your test suite. It co
|
|
23
24
|
|
24
25
|
- etc.
|
25
26
|
|
26
|
-
Of course, we have some [solutions](
|
27
|
+
Of course, we have some [solutions](https://test-prof.evilmartians.io/#/?id=recipes) for common performance issues too, bundled into the gem.
|
27
28
|
|
28
|
-
[](http://bit.ly/test-prof-map)
|
29
30
|
|
30
|
-
|
31
|
+
📑 [Documentation](https://test-prof.evilmartians.io)
|
31
32
|
|
32
33
|
Supported Ruby versions:
|
33
34
|
|
@@ -60,65 +61,17 @@ end
|
|
60
61
|
|
61
62
|
And that's it)
|
62
63
|
|
63
|
-
##
|
64
|
+
## Usage
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
- [RubyProf Integration](https://github.com/palkan/test-prof/tree/master/guides/ruby_prof.md)
|
68
|
-
|
69
|
-
- [StackProf Integration](https://github.com/palkan/test-prof/tree/master/guides/stack_prof.md)
|
70
|
-
|
71
|
-
- [Event Profiler](https://github.com/palkan/test-prof/tree/master/guides/event_prof.md) (e.g. ActiveSupport notifications)
|
72
|
-
|
73
|
-
- [Tag Profiler](https://github.com/palkan/test-prof/tree/master/guides/tag_prof.md)
|
74
|
-
|
75
|
-
- [Factory Doctor](https://github.com/palkan/test-prof/tree/master/guides/factory_doctor.md)
|
76
|
-
|
77
|
-
- [Factory Profiler](https://github.com/palkan/test-prof/tree/master/guides/factory_prof.md)
|
78
|
-
|
79
|
-
- [RSpecDissect Profiler](https://github.com/palkan/test-prof/tree/master/guides/rspec_dissect.md)
|
80
|
-
|
81
|
-
- [RuboCop cops](https://github.com/palkan/test-prof/tree/master/guides/rubocop.md)
|
82
|
-
|
83
|
-
## Tips and Tricks (or _Recipes_)
|
84
|
-
|
85
|
-
We also want to share some small code tricks which can help you to improve your test suite performance and efficiency:
|
86
|
-
|
87
|
-
- [`before_all` Hook](https://github.com/palkan/test-prof/tree/master/guides/before_all.md)
|
88
|
-
|
89
|
-
- [`let_it_be` Helper](https://github.com/palkan/test-prof/tree/master/guides/let_it_be.md)
|
90
|
-
|
91
|
-
- [AnyFixture](https://github.com/palkan/test-prof/tree/master/guides/any_fixture.md)
|
92
|
-
|
93
|
-
- [FactoryDefault](https://github.com/palkan/test-prof/tree/master/guides/factory_default.md)
|
94
|
-
|
95
|
-
- [RSpec Stamp](https://github.com/palkan/test-prof/tree/master/guides/rspec_stamp.md)
|
96
|
-
|
97
|
-
- [Tests Sampling](https://github.com/palkan/test-prof/tree/master/guides/tests_sampling.md)
|
98
|
-
|
99
|
-
## Configuration
|
100
|
-
|
101
|
-
TestProf global configuration is used by most of the profilers:
|
102
|
-
|
103
|
-
```ruby
|
104
|
-
TestProf.configure do |config|
|
105
|
-
# the directory to put artifacts (reports) in ("tmp/test_prof" by default)
|
106
|
-
config.output_dir = "tmp/test_prof"
|
107
|
-
|
108
|
-
# use unique filenames for reports (by simply appending current timestamp)
|
109
|
-
config.timestamps = true
|
110
|
-
|
111
|
-
# color output
|
112
|
-
config.color = true
|
113
|
-
end
|
114
|
-
```
|
66
|
+
Check out our [docs][].
|
115
67
|
|
116
68
|
## What's next?
|
117
69
|
|
118
|
-
|
119
70
|
Have an idea? [Propose](https://github.com/palkan/test-prof/issues/new) a feature request!
|
120
71
|
|
121
72
|
|
122
73
|
## License
|
123
74
|
|
124
75
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
76
|
+
|
77
|
+
[docs]: https://test-prof.evilmartians.io
|
@@ -0,0 +1,447 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>TestProf: TagProf report</title>
|
5
|
+
<meta name="viewport" content="width=device-width">
|
6
|
+
<meta charset="UTF-8">
|
7
|
+
<style>
|
8
|
+
html, body {
|
9
|
+
height: 100%;
|
10
|
+
width: 100%;
|
11
|
+
min-width: 300px;
|
12
|
+
}
|
13
|
+
|
14
|
+
body {
|
15
|
+
background: #f9f9f9;
|
16
|
+
color: #363636;
|
17
|
+
font: 18px/30px "Arial",sans-serif;
|
18
|
+
margin: 0;
|
19
|
+
padding: 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
a {
|
23
|
+
text-decoration: none;
|
24
|
+
color: #ff5e5e
|
25
|
+
}
|
26
|
+
|
27
|
+
a:visited, a:active{
|
28
|
+
color: #ff5e5e;
|
29
|
+
}
|
30
|
+
|
31
|
+
a:hover{
|
32
|
+
opacity: 0.8;
|
33
|
+
}
|
34
|
+
|
35
|
+
h1 {
|
36
|
+
font-size: 30px;
|
37
|
+
line-height: 32px;
|
38
|
+
letter-spacing: 2px;
|
39
|
+
font-weight: bold;
|
40
|
+
padding: 30px 0 30px 0;
|
41
|
+
margin: 0;
|
42
|
+
}
|
43
|
+
|
44
|
+
.main {
|
45
|
+
height: 100%;
|
46
|
+
width: 100%;
|
47
|
+
margin: 0;
|
48
|
+
padding: 0;
|
49
|
+
}
|
50
|
+
|
51
|
+
header {
|
52
|
+
position: relative;
|
53
|
+
text-align: center;
|
54
|
+
background: #fff;
|
55
|
+
overflow: hidden;
|
56
|
+
display: flex;
|
57
|
+
align-items: center;
|
58
|
+
flex-direction: column;
|
59
|
+
}
|
60
|
+
|
61
|
+
.chart {
|
62
|
+
display: flex;
|
63
|
+
justify-content: center;
|
64
|
+
position: relative;
|
65
|
+
box-sizing: border-box;
|
66
|
+
flex-direction: row;
|
67
|
+
padding: 20px;
|
68
|
+
}
|
69
|
+
|
70
|
+
.tooltip {
|
71
|
+
background: #eee;
|
72
|
+
box-shadow: 0 0 5px #999999;
|
73
|
+
color: #333;
|
74
|
+
display: none;
|
75
|
+
font-size: 14px;
|
76
|
+
left: 130px;
|
77
|
+
padding: 10px;
|
78
|
+
position: absolute;
|
79
|
+
text-align: left;
|
80
|
+
top: 95px;
|
81
|
+
z-index: 10;
|
82
|
+
}
|
83
|
+
|
84
|
+
.tooltip .label.active {
|
85
|
+
color: #ff5e5e;
|
86
|
+
}
|
87
|
+
|
88
|
+
.tooltip .value-label {
|
89
|
+
font-weight: bold;
|
90
|
+
margin-right: 10px;
|
91
|
+
}
|
92
|
+
|
93
|
+
.legend, .totals {
|
94
|
+
font-size: 14px;
|
95
|
+
}
|
96
|
+
|
97
|
+
#selector {
|
98
|
+
font-size: 14px;
|
99
|
+
display: flex;
|
100
|
+
align-items: flex-start;
|
101
|
+
position: relative;
|
102
|
+
box-sizing: border-box;
|
103
|
+
flex-direction: column;
|
104
|
+
padding: 20px;
|
105
|
+
}
|
106
|
+
|
107
|
+
rect {
|
108
|
+
stroke-width: 2;
|
109
|
+
}
|
110
|
+
|
111
|
+
rect.disabled { /* NEW */
|
112
|
+
fill: transparent !important; /* NEW */
|
113
|
+
}
|
114
|
+
|
115
|
+
.d3-donut-path {
|
116
|
+
transition: opacity 200ms;
|
117
|
+
opacity: 1;
|
118
|
+
cursor: pointer;
|
119
|
+
}
|
120
|
+
|
121
|
+
.d3-donut-path:hover {
|
122
|
+
opacity: 0.8;
|
123
|
+
}
|
124
|
+
|
125
|
+
.humanoids__link {
|
126
|
+
width: 130px;
|
127
|
+
}
|
128
|
+
|
129
|
+
.humanoids{
|
130
|
+
position: absolute;
|
131
|
+
bottom: -23px;
|
132
|
+
width: 150px;
|
133
|
+
height: 60px;
|
134
|
+
margin: 0 auto 0 -10px;
|
135
|
+
font-size: 0;
|
136
|
+
transform: scale(0.6);
|
137
|
+
}
|
138
|
+
.humanoids circle{
|
139
|
+
transform: scaleY(1);
|
140
|
+
transform-origin: 50%;
|
141
|
+
animation-duration: 8s;
|
142
|
+
animation-name: humanoids-blink;
|
143
|
+
animation-iteration-count: infinite;
|
144
|
+
}
|
145
|
+
.humanoids svg{
|
146
|
+
height: 60px;
|
147
|
+
}
|
148
|
+
.humanoids__human, .humanoids__martian{
|
149
|
+
position: absolute;
|
150
|
+
width: 80px;
|
151
|
+
height: 90px;
|
152
|
+
transition: transform 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
153
|
+
transform: translateY(0);
|
154
|
+
}
|
155
|
+
.humanoids__human:hover, .humanoids__martian:hover{
|
156
|
+
transform: translateY(-12px);
|
157
|
+
}
|
158
|
+
.humanoids__martian{
|
159
|
+
left: 0;
|
160
|
+
}
|
161
|
+
.humanoids__human{
|
162
|
+
right: 0;
|
163
|
+
}
|
164
|
+
.humanoids__human circle{
|
165
|
+
animation-delay: 0.5s;
|
166
|
+
}
|
167
|
+
|
168
|
+
[name="root"] .label {
|
169
|
+
text-align: center;
|
170
|
+
}
|
171
|
+
</style>
|
172
|
+
</head>
|
173
|
+
<body>
|
174
|
+
<div class="main">
|
175
|
+
<header>
|
176
|
+
<h1>TagProf Report</h1>
|
177
|
+
<a class="humanoids__link" href="https://evilmartians.com">
|
178
|
+
<div class="humanoids">
|
179
|
+
<div class="humanoids__martian"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 108 92"><path fill="#f64242" d="M26 88L8 78l18-10"/><path fill="#f64242" d="M94 92v-6H44c-5.5 0-10-4.5-10-10s4.5-10 10-10h50V32c0-14-7.9-22-22-22H48c-14.1 0-22 8-22 22v60h68z"/><circle fill="#FFF" cx="48" cy="50" r="8"/><circle fill="#FFF" cx="72" cy="50" r="8"/><circle fill="#BF6C35" cx="48" cy="50" r="4"/><circle fill="#BF6C35" cx="72" cy="50" r="4"/><g fill="#663F4C"><path d="M48 60c-5.5 0-10-4.5-10-10s4.5-10 10-10 10 4.5 10 10-4.5 10-10 10zm0-16c-3.3 0-6 2.7-6 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zM82 50c0 5.5-4.5 10-10 10s-10-4.5-10-10 4.5-10 10-10 10 4.5 10 10zm-16 0c0 3.3 2.7 6 6 6s6-2.7 6-6-2.7-6-6-6-6 2.7-6 6z"/><path d="M102 8c-3.8 0-6-2.2-6-6 0-1.1-.9-2-2-2s-2 .9-2 2c0 2.2.5 4.1 1.5 5.7L88.2 13c-4-3.3-9.5-5-16.2-5H48c-6.7 0-12.2 1.7-16.2 4.9l-5.3-5.3C27.5 6.1 28 4.2 28 2c0-1.1-.9-2-2-2s-2 .9-2 2c0 3.8-2.2 6-6 6-1.1 0-2 .9-2 2s.9 2 2 2c2.2 0 4.1-.5 5.7-1.5l5.3 5.3c-3.2 4-4.9 9.5-4.9 16.2v34.8L3.9 78 24 89v3h4V32c0-12.9 7.1-20 20-20h24c12.9 0 20 7.1 20 20v32H44c-6.6 0-12 5.4-12 12s5.4 12 12 12h48v4h4v-8h-2l-4-8-4 8h-4l-4-8-4 8h-4l-4-8-4 8h-4l-4-8-4 8h-4l-4-8-3.1 6.2C37.1 80.7 36 78.5 36 76c0-4.4 3.6-8 8-8l4 8 4-8h4l4 8 4-8h4l4 8 4-8h4l4 8 4-8h8V32c0-6.7-1.7-12.2-4.9-16.2l5.3-5.3c1.6 1 3.5 1.5 5.7 1.5 1.1 0 2-.9 2-2s-1-2-2.1-2zM24 84.4L12.1 78 24 71.4v13z"/></g></svg></div>
|
180
|
+
<div class="humanoids__human"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 108 92"><path fill="#FFFFFF" d="M14 62v30h68v-6H32c-5.5 0-10-4.5-10-10s4.5-10 10-10h50v-4c4 0 8-3.6 8-8s-4-8-8-8V32c0-14-7.9-22-22-22H36c-14.1 0-22 8-22 22v14c-4 0-8 3.6-8 8s4 8 8 8z"/><circle fill="#FFF" cx="36" cy="50" r="8"/><circle fill="#FFF" cx="60" cy="50" r="8"/><circle fill="#f64242" cx="36" cy="50" r="4"/><circle fill="#f64242" cx="60" cy="50" r="4"/><path fill="#f64242" d="M60 10H36c-14.1 0-22 8-22 22v2l4-4 6 6 6-6 6 6 6-6 6 6 6-6 6 6 6-6 6 6 6-6 4 4v-2c0-14-7.9-22-22-22z"/><g fill="#663F4C"><path d="M36 60c-5.5 0-10-4.5-10-10s4.5-10 10-10 10 4.5 10 10-4.5 10-10 10zm0-16c-3.3 0-6 2.7-6 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zM60 60c-5.5 0-10-4.5-10-10s4.5-10 10-10 10 4.5 10 10-4.5 10-10 10zm0-16c-3.3 0-6 2.7-6 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6z"/><path d="M12 63.8V92h4V32c0-12.9 7.1-20 20-20h24c12.9 0 20 7.1 20 20v32H32c-6.6 0-12 5.4-12 12s5.4 12 12 12h48v4h4v-8H74v-1c0-1.7-1.3-3-3-3s-3 1.3-3 3v1h-6v-1c0-1.7-1.3-3-3-3s-3 1.3-3 3v1h-6v-1c0-1.7-1.3-3-3-3s-3 1.3-3 3v1h-6v-1c0-1.7-1.3-3-3-3s-3 1.3-3 3v1c-4 0-8-3.6-8-8s3.6-8 8-8h6v1c0 1.7 1.3 3 3 3s3-1.3 3-3v-1h6v1c0 1.7 1.3 3 3 3s3-1.3 3-3v-1h6v1c0 1.7 1.3 3 3 3s3-1.3 3-3v-1h6v1c0 1.7 1.3 3 3 3s3-1.3 3-3v-1h4v-4.2c5-.9 8-5 8-9.8s-3-8.9-8-9.8V32c0-15.3-8.7-24-24-24H36c-15.3 0-24 8.7-24 24v12.2c-5 .9-8 5-8 9.8s3 8.9 8 9.8zm72-15.5c2 .8 4 3 4 5.7s-2 4.8-4 5.7V48.3zm-72 0v11.3c-2-.8-4-3-4-5.7s2-4.7 4-5.6z"/></g></svg></div>
|
181
|
+
</div>
|
182
|
+
</a>
|
183
|
+
</header>
|
184
|
+
<div class="chart">
|
185
|
+
<form id="selector">
|
186
|
+
</form>
|
187
|
+
<div id="chart">
|
188
|
+
</div>
|
189
|
+
<div id="legend">
|
190
|
+
</div>
|
191
|
+
</div>
|
192
|
+
</div>
|
193
|
+
|
194
|
+
<script type="text/javascript" src="src/d3.v4.min.js"></script>
|
195
|
+
|
196
|
+
<script>
|
197
|
+
var report_data;
|
198
|
+
var width = 360;
|
199
|
+
var legendWidth = 240;
|
200
|
+
var height = 360;
|
201
|
+
var radius = Math.min(width, height) / 2;
|
202
|
+
var donutWidth = 75;
|
203
|
+
var legendRectSize = 18;
|
204
|
+
var legendSpacing = 4;
|
205
|
+
|
206
|
+
var color = d3.scaleOrdinal(d3.schemeCategory20);
|
207
|
+
|
208
|
+
function pad(n, size) {
|
209
|
+
if(size == void 0) size = 2;
|
210
|
+
|
211
|
+
var str = n.toString();
|
212
|
+
|
213
|
+
while(str.length < size){
|
214
|
+
str = "0" + str;
|
215
|
+
}
|
216
|
+
|
217
|
+
return str;
|
218
|
+
}
|
219
|
+
|
220
|
+
function duration(t) {
|
221
|
+
return pad(t / 60|0) + ':' + pad((t % 60) |0) + '.' + pad(((t * 1000) % 1000)|0, 3);
|
222
|
+
}
|
223
|
+
|
224
|
+
var svg = d3.select('#chart')
|
225
|
+
.append('svg')
|
226
|
+
.attr('width', width)
|
227
|
+
.attr('height', height)
|
228
|
+
.append('g')
|
229
|
+
.attr('transform', 'translate(' + (width / 2) +
|
230
|
+
',' + (height / 2) + ')');
|
231
|
+
|
232
|
+
var arc = d3.arc()
|
233
|
+
.innerRadius(radius - donutWidth)
|
234
|
+
.outerRadius(radius);
|
235
|
+
|
236
|
+
var labelArc = d3.arc()
|
237
|
+
.outerRadius(radius - donutWidth)
|
238
|
+
.innerRadius(radius);
|
239
|
+
|
240
|
+
var pie = d3.pie()
|
241
|
+
.value(function(d) { return d.time; })
|
242
|
+
.sort(function(a, b) {
|
243
|
+
return b.time - a.time;
|
244
|
+
});
|
245
|
+
|
246
|
+
var tooltip = d3.select('#chart')
|
247
|
+
.append('div')
|
248
|
+
.attr('class', 'tooltip');
|
249
|
+
|
250
|
+
tooltip.append('div')
|
251
|
+
.attr('class', 'label');
|
252
|
+
|
253
|
+
tooltip.append('div')
|
254
|
+
.attr('class', 'stats');
|
255
|
+
|
256
|
+
// var report_data = JSON.parse('{/**REPORT-DATA**/}');
|
257
|
+
var report_data = {
|
258
|
+
tag: "type",
|
259
|
+
events: [
|
260
|
+
"sql.active_record"
|
261
|
+
],
|
262
|
+
data: [
|
263
|
+
{ value: "model", count: 123, time: 324.2, "sql.active_record": 21.54 },
|
264
|
+
{ value: "controller", count: 44, time: 514, "sql.active_record": 121 },
|
265
|
+
{ value: "job", count: 33, time: 122.2 },
|
266
|
+
{ value: "__unknown__", count: 2, time: 44, "sql.active_record": 0 }
|
267
|
+
]
|
268
|
+
};
|
269
|
+
|
270
|
+
var dataset = report_data.data;
|
271
|
+
|
272
|
+
dataset.sort(function(a, b){
|
273
|
+
return b.time - a.time;
|
274
|
+
});
|
275
|
+
|
276
|
+
var totals = {};
|
277
|
+
|
278
|
+
["count", "time"].concat(report_data.events).forEach(function(event) {
|
279
|
+
totals[event] = d3.sum(dataset.map(function(d){
|
280
|
+
return d[event] || 0;
|
281
|
+
}));
|
282
|
+
});
|
283
|
+
|
284
|
+
dataset.forEach(function(d) {
|
285
|
+
d.labels = {};
|
286
|
+
|
287
|
+
if (d.value == "__unknown__") {
|
288
|
+
d.color = "#cccccc";
|
289
|
+
};
|
290
|
+
|
291
|
+
d.labels.count = {
|
292
|
+
value: d.count,
|
293
|
+
percent: Math.round(1000 * d.count / totals.count) / 10
|
294
|
+
};
|
295
|
+
|
296
|
+
["time"].concat(report_data.events).forEach(function(event){
|
297
|
+
d.labels[event] = {
|
298
|
+
value: duration(d[event]),
|
299
|
+
percent: d[event] ? Math.round(1000 * d[event] / totals[event]) / 10 : 0
|
300
|
+
}
|
301
|
+
});
|
302
|
+
});
|
303
|
+
|
304
|
+
var path = svg.selectAll('path')
|
305
|
+
.data(pie(dataset))
|
306
|
+
.enter()
|
307
|
+
.append('path')
|
308
|
+
.attr('d', arc)
|
309
|
+
.attr('class', 'd3-donut-path')
|
310
|
+
.attr('fill', function(d, i) {
|
311
|
+
return d.data.color || color(d.data.value);
|
312
|
+
})
|
313
|
+
.each(function(d) { this._current = d; });
|
314
|
+
|
315
|
+
var currentMeasure = "time";
|
316
|
+
|
317
|
+
pie.value(function(d) {
|
318
|
+
return d[currentMeasure];
|
319
|
+
});
|
320
|
+
|
321
|
+
path.on('mouseover', function(d) {
|
322
|
+
tooltip.select('.label').html("<span class='value-label'>" + report_data.tag + ":</span><span class='value-data'>" + d.data.value + "</span>");
|
323
|
+
|
324
|
+
var str = "";
|
325
|
+
|
326
|
+
["count", "time"].concat(report_data.events).forEach(function(event) {
|
327
|
+
str += "<div class='label " + (event == currentMeasure ? 'active' : '') + "'><span class='value-label'>" + event + ":</span><span class='value-data'>" + d.data.labels[event].value + " ("+d.data.labels[event].percent + "%)</span></div>";
|
328
|
+
});
|
329
|
+
tooltip.select('.stats').html(str);
|
330
|
+
tooltip.style('display', 'block');
|
331
|
+
});
|
332
|
+
|
333
|
+
path.on('mousemove', function(d) {
|
334
|
+
tooltip.style('top', (d3.event.layerY + 10) + 'px')
|
335
|
+
.style('left', (d3.event.layerX + 10) + 'px');
|
336
|
+
});
|
337
|
+
|
338
|
+
path.on('mouseout', function() {
|
339
|
+
tooltip.style('display', 'none');
|
340
|
+
});
|
341
|
+
|
342
|
+
if(report_data.events && report_data.events.length) {
|
343
|
+
var selectOptions = ["time"].concat(report_data.events);
|
344
|
+
|
345
|
+
var selector = d3.select("form").selectAll("label")
|
346
|
+
.data(selectOptions)
|
347
|
+
.enter().append("label");
|
348
|
+
|
349
|
+
selector.append("input")
|
350
|
+
.attr("type", "radio")
|
351
|
+
.attr("name", "measurement")
|
352
|
+
.attr("value", function(d) { return d; })
|
353
|
+
.property("checked", function(d, i) { return i === 0 });
|
354
|
+
|
355
|
+
d3.select("form").style('width', legendWidth + 'px');
|
356
|
+
|
357
|
+
d3.selectAll(("input[name='measurement']")).on("change", function(e) {
|
358
|
+
render(e);
|
359
|
+
});
|
360
|
+
|
361
|
+
selector.append("span")
|
362
|
+
.text(function(d) { return d; });
|
363
|
+
} else {
|
364
|
+
d3.select("form").remove();
|
365
|
+
}
|
366
|
+
|
367
|
+
var legendContainer = d3.select('#legend')
|
368
|
+
.append('svg')
|
369
|
+
.attr('height', height)
|
370
|
+
.attr('width', legendWidth);
|
371
|
+
|
372
|
+
var legend = legendContainer.selectAll('legend')
|
373
|
+
.data(color.domain())
|
374
|
+
.enter()
|
375
|
+
.append('g')
|
376
|
+
.attr('class', 'legend')
|
377
|
+
.attr('transform', function(d, i) {
|
378
|
+
var height = legendRectSize + legendSpacing;
|
379
|
+
var horz = 2 * legendRectSize;
|
380
|
+
var vert = i * height;
|
381
|
+
return 'translate(' + horz + ',' + vert + ')';
|
382
|
+
});
|
383
|
+
|
384
|
+
legend.append('rect')
|
385
|
+
.attr('width', legendRectSize)
|
386
|
+
.attr('height', legendRectSize)
|
387
|
+
.style('fill', color)
|
388
|
+
.style('stroke', color);
|
389
|
+
|
390
|
+
legend.append('text')
|
391
|
+
.attr('x', legendRectSize + legendSpacing)
|
392
|
+
.attr('y', legendRectSize - legendSpacing)
|
393
|
+
.text(function(d) { return d; });
|
394
|
+
|
395
|
+
var totalsContainer = svg.append('g')
|
396
|
+
.attr('class', 'totals')
|
397
|
+
.attr('transform', 'translate(-' + (radius - 100) +', -'+ (radius - 120) + ')');
|
398
|
+
|
399
|
+
var totalsArray = d3.keys(totals).map(function(key){
|
400
|
+
if(key == "count"){
|
401
|
+
return { key: key, value: totals[key] };
|
402
|
+
} else {
|
403
|
+
return { key: key, value: duration(totals[key]) };
|
404
|
+
}
|
405
|
+
});
|
406
|
+
|
407
|
+
totalsContainer.append('text')
|
408
|
+
.text("TOTALS")
|
409
|
+
.attr('x', 50);
|
410
|
+
|
411
|
+
var totalsLegend = totalsContainer.selectAll('total')
|
412
|
+
.data(totalsArray)
|
413
|
+
.enter()
|
414
|
+
.append('g')
|
415
|
+
.attr('class', 'total')
|
416
|
+
.attr('transform', function(d, i) {
|
417
|
+
var height = legendRectSize + legendSpacing;
|
418
|
+
var horz = 0;
|
419
|
+
var vert = i * height + 20;
|
420
|
+
return 'translate(' + horz + ',' + vert + ')';
|
421
|
+
});
|
422
|
+
|
423
|
+
totalsLegend.append('text')
|
424
|
+
.attr('x', 0)
|
425
|
+
.attr('y', legendRectSize - legendSpacing)
|
426
|
+
.text(function(d) {
|
427
|
+
return d.key + ": " + d.value;
|
428
|
+
});
|
429
|
+
|
430
|
+
var render = function(measurement) {
|
431
|
+
currentMeasure = measurement;
|
432
|
+
|
433
|
+
path = path.data(pie(dataset));
|
434
|
+
|
435
|
+
path.transition()
|
436
|
+
.duration(750)
|
437
|
+
.attrTween('d', function(d) {
|
438
|
+
var interpolate = d3.interpolate(this._current, d);
|
439
|
+
this._current = interpolate(0);
|
440
|
+
return function(t) {
|
441
|
+
return arc(interpolate(t));
|
442
|
+
};
|
443
|
+
});
|
444
|
+
}
|
445
|
+
</script>
|
446
|
+
</body>
|
447
|
+
</html>
|