nunes 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.md +14 -0
- data/Gemfile +4 -0
- data/README.md +63 -33
- data/lib/nunes.rb +0 -1
- data/lib/nunes/adapter.rb +40 -20
- data/lib/nunes/adapters/memory.rb +6 -2
- data/lib/nunes/adapters/timing_aliased.rb +7 -1
- data/lib/nunes/instrumentable.rb +7 -51
- data/lib/nunes/subscriber.rb +7 -12
- data/lib/nunes/subscribers/action_controller.rb +8 -8
- data/lib/nunes/subscribers/action_mailer.rb +2 -2
- data/lib/nunes/subscribers/action_view.rb +8 -9
- data/lib/nunes/subscribers/active_support.rb +8 -8
- data/lib/nunes/subscribers/nunes.rb +1 -3
- data/lib/nunes/version.rb +1 -1
- data/script/bench.rb +48 -0
- data/script/release +42 -0
- data/test/adapter_test.rb +77 -1
- data/test/cache_instrumentation_test.rb +13 -13
- data/test/controller_instrumentation_test.rb +20 -20
- data/test/instrumentable_test.rb +36 -9
- data/test/mailer_instrumentation_test.rb +2 -2
- data/test/namespaced_controller_instrumentation_test.rb +25 -0
- data/test/rails_app/app/controllers/admin/posts_controller.rb +11 -0
- data/test/rails_app/app/views/admin/posts/index.html.erb +5 -0
- data/test/rails_app/config/routes.rb +4 -0
- data/test/view_instrumentation_test.rb +2 -2
- metadata +11 -5
- data/lib/nunes/adapters/default.rb +0 -10
- data/test/adapters/default_test.rb +0 -26
data/Changelog.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# 0.2.0
|
2
|
+
|
3
|
+
## Backwards Compatibility Break
|
4
|
+
|
5
|
+
* No longer using the inflector to pretty up metric names. This means that when you upgrade from 0.1 and 0.2 some metrics will change names.
|
6
|
+
* Namespaced several of the stats to make them easier to graph.
|
7
|
+
|
8
|
+
## Fixed
|
9
|
+
|
10
|
+
* Instrumenting namespaced controllers
|
11
|
+
|
12
|
+
# 0.1.0
|
13
|
+
|
14
|
+
* Initial release.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# nunes
|
2
2
|
|
3
3
|
The friendly gem that instruments everything for you, like I would if I could.
|
4
4
|
|
@@ -10,7 +10,7 @@ Because I don't work for you, but even that could not stop me from trying to mak
|
|
10
10
|
|
11
11
|
Add this line to your application's Gemfile:
|
12
12
|
|
13
|
-
gem
|
13
|
+
gem "nunes"
|
14
14
|
|
15
15
|
Or install it yourself as:
|
16
16
|
|
@@ -18,28 +18,31 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
nunes works out of the box with
|
21
|
+
nunes works out of the box with [instrumental app](http://instrumentalapp.com) (my person favorite) and [statsd](https://github.com/reinh/statsd). All you need to do is subscribe using an instance of statsd or instrumental's agent and you are good to go.
|
22
22
|
|
23
|
-
### With
|
23
|
+
### With Instrumental
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
require
|
26
|
+
require "nunes"
|
27
|
+
I = Instrument::Agent.new(...)
|
28
|
+
Nunes.subscribe(I)
|
29
|
+
```
|
30
|
+
|
31
|
+
### With Statsd
|
27
32
|
|
33
|
+
```ruby
|
34
|
+
require "nunes"
|
28
35
|
statsd = Statsd.new(...)
|
29
36
|
Nunes.subscribe(statsd)
|
30
37
|
```
|
31
38
|
|
32
|
-
### With
|
39
|
+
### With Some Other Service
|
33
40
|
|
34
|
-
|
35
|
-
require 'nunes'
|
36
|
-
I = Instrument::Agent.new(...)
|
37
|
-
Nunes.subscribe(I)
|
38
|
-
```
|
41
|
+
If you would like for nunes to work with some other service, you can easily make an adapter. Check out the [existing adapters](https://github.com/jnunemaker/nunes/tree/master/lib/nunes/adapters) for examples. The key is to inherit from `Nunes::Adapter` and then convert the `increment` and `timing` methods to whatever the service requires.
|
39
42
|
|
40
43
|
## What Can I Do For You?
|
41
44
|
|
42
|
-
If you are using nunes with
|
45
|
+
If you are using nunes with Rails, I will subscribe to the following events:
|
43
46
|
|
44
47
|
* `process_action.action_controller`
|
45
48
|
* `render_template.action_view`
|
@@ -56,39 +59,44 @@ If you are using nunes with rails, out of the box, I'll subscribe to Actve Suppo
|
|
56
59
|
|
57
60
|
Whoa! You would do all that for me? Yep, I would. Because I care. Deeply.
|
58
61
|
|
59
|
-
Based on those events, you'll get metrics like this in
|
62
|
+
Based on those events, you'll get metrics like this in instrumental and statsd:
|
60
63
|
|
61
64
|
#### Counters
|
62
65
|
|
63
66
|
* `action_controller.status.200`
|
64
67
|
* `action_controller.format.html`
|
65
68
|
* `action_controller.exception.RuntimeError` - where RuntimeError is the class of any exceptions that occur while processing a controller's action.
|
66
|
-
* `active_support.
|
67
|
-
* `active_support.
|
69
|
+
* `active_support.cache.hit`
|
70
|
+
* `active_support.cache.miss`
|
68
71
|
|
69
72
|
#### Timers
|
70
73
|
|
71
|
-
* `action_controller.runtime`
|
72
|
-
* `action_controller.
|
73
|
-
* `action_controller.
|
74
|
-
* `action_controller.
|
75
|
-
* `
|
76
|
-
* `
|
77
|
-
* `
|
78
|
-
* `
|
74
|
+
* `action_controller.runtime.total`
|
75
|
+
* `action_controller.runtime.view`
|
76
|
+
* `action_controller.runtime.db`
|
77
|
+
* `action_controller.controller.PostsController.index.runtime.total`
|
78
|
+
* `action_controller.controller.PostsController.index.runtime.view`
|
79
|
+
* `action_controller.controller.PostsController.index.runtime.db`
|
80
|
+
* `action_view.template.app.views.posts.index.html.erb` - where `app.views.posts.index.html.erb` is the path of the view file
|
81
|
+
* `action_view.partial.app.views.posts._post.html.erb` - I can even do partials! woot woot!
|
82
|
+
* `action_mailer.deliver.PostMailer`
|
83
|
+
* `action_mailer.receive.PostMailer`
|
79
84
|
* `active_record.sql`
|
80
|
-
* `active_record.sql.select`
|
81
|
-
* `
|
82
|
-
* `
|
83
|
-
* `
|
84
|
-
* `active_support.
|
85
|
-
* `active_support.
|
86
|
-
* `active_support.
|
87
|
-
* `active_support.
|
85
|
+
* `active_record.sql.select`
|
86
|
+
* `active_record.sql.insert`
|
87
|
+
* `active_record.sql.update`
|
88
|
+
* `active_record.sql.delete`
|
89
|
+
* `active_support.cache.read`
|
90
|
+
* `active_support.cache.fetch`
|
91
|
+
* `active_support.cache.fetch_hit`
|
92
|
+
* `active_support.cache.fetch_generate`
|
93
|
+
* `active_support.cache.write`
|
94
|
+
* `active_support.cache.delete`
|
95
|
+
* `active_support.cache.exist`
|
88
96
|
|
89
97
|
### But wait, there's more!!!
|
90
98
|
|
91
|
-
In addition to doing all that work for you
|
99
|
+
In addition to doing all that automagical work for you, I also allow you to wrap your own code with instrumentation. I know, I know, sounds too good to be true.
|
92
100
|
|
93
101
|
```ruby
|
94
102
|
class User < ActiveRecord::Base
|
@@ -106,7 +114,7 @@ user = User.new(name: 'NUNES!')
|
|
106
114
|
user.save
|
107
115
|
```
|
108
116
|
|
109
|
-
An event named `instrument_method_time.nunes` will be generated, which in turn is subscribed to and sent to whatever you used to send instrumentation to (statsd, instrumental, etc.). The metric name will default to class.method. For the example above, the metric name would be `
|
117
|
+
An event named `instrument_method_time.nunes` will be generated, which in turn is subscribed to and sent to whatever you used to send instrumentation to (statsd, instrumental, etc.). The metric name will default to class.method. For the example above, the metric name would be `User.save`. No fear, you can customize this.
|
110
118
|
|
111
119
|
```ruby
|
112
120
|
class User < ActiveRecord::Base
|
@@ -141,6 +149,28 @@ end
|
|
141
149
|
|
142
150
|
If you subscribe to the event on your own, say to log some things, you'll get a key named `:pay` with a value of `"loading"` in the event's payload. Pretty neat, eh?
|
143
151
|
|
152
|
+
## `script/bootstrap`
|
153
|
+
|
154
|
+
This script will get all the dependencies ready so you can start hacking on nunes.
|
155
|
+
|
156
|
+
```
|
157
|
+
# to learn more about script/bootstrap
|
158
|
+
script/bootstrap help
|
159
|
+
```
|
160
|
+
|
161
|
+
## `script/test`
|
162
|
+
|
163
|
+
For your convenience, there is a script to run the tests. It will also perform `script/bootstrap`, which bundles and all that jazz.
|
164
|
+
|
165
|
+
```
|
166
|
+
# to learn more about script test
|
167
|
+
script/test help
|
168
|
+
```
|
169
|
+
|
170
|
+
## `script/watch`
|
171
|
+
|
172
|
+
If you are like me, you are too lazy to continually run `script/test`. For this scenario, I have included `script/watch`, which will run `script/test` automatically anytime a relevant file changes.
|
173
|
+
|
144
174
|
## Contributing
|
145
175
|
|
146
176
|
1. Fork it
|
data/lib/nunes.rb
CHANGED
data/lib/nunes/adapter.rb
CHANGED
@@ -6,29 +6,27 @@ module Nunes
|
|
6
6
|
#
|
7
7
|
# Returns Nunes::Adapter instance.
|
8
8
|
def self.wrap(client)
|
9
|
-
if client.nil?
|
10
|
-
|
11
|
-
end
|
9
|
+
raise ArgumentError, "client cannot be nil" if client.nil?
|
10
|
+
return client if client.is_a?(self)
|
12
11
|
|
13
|
-
|
14
|
-
return client
|
15
|
-
end
|
12
|
+
adapter = adapters.detect { |adapter| adapter.wraps?(client) }
|
16
13
|
|
17
|
-
if
|
18
|
-
|
14
|
+
if adapter.nil?
|
15
|
+
raise ArgumentError,
|
16
|
+
"I have no clue how to wrap what you've given me (#{client.inspect})"
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
has_gauge = client.respond_to?(:gauge)
|
19
|
+
adapter.new(client)
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
# Private
|
23
|
+
def self.wraps?(client)
|
24
|
+
client.respond_to?(:increment) && client.respond_to?(:timing)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Private
|
28
|
+
def self.adapters
|
29
|
+
[Nunes::Adapter, *subclasses]
|
32
30
|
end
|
33
31
|
|
34
32
|
# Private
|
@@ -44,13 +42,35 @@ module Nunes
|
|
44
42
|
# Internal: Increment a metric by a value. Override in subclass if client
|
45
43
|
# interface does not match.
|
46
44
|
def increment(metric, value = 1)
|
47
|
-
@client.increment metric, value
|
45
|
+
@client.increment prepare(metric), value
|
48
46
|
end
|
49
47
|
|
50
48
|
# Internal: Record a metric's duration. Override in subclass if client
|
51
49
|
# interface does not match.
|
52
50
|
def timing(metric, duration)
|
53
|
-
@client.timing metric, duration
|
51
|
+
@client.timing prepare(metric), duration
|
52
|
+
end
|
53
|
+
|
54
|
+
# Private: What Ruby uses to separate namespaces.
|
55
|
+
ReplaceRegex = /[^a-z0-9\-_]+/i
|
56
|
+
|
57
|
+
# Private: The default metric namespace separator.
|
58
|
+
Separator = "."
|
59
|
+
|
60
|
+
RegexSeparator = Regexp.escape(Separator)
|
61
|
+
|
62
|
+
# Private: Regex to match metric ending with separator.
|
63
|
+
StartsOrEndsWithSeparator = /\A#{RegexSeparator}|#{RegexSeparator}\Z/
|
64
|
+
|
65
|
+
# Private
|
66
|
+
Nothing = ""
|
67
|
+
|
68
|
+
# Private: Prepare a metric name before it is sent to the adapter's client.
|
69
|
+
def prepare(metric)
|
70
|
+
metric = metric.to_s.gsub(ReplaceRegex, Separator)
|
71
|
+
metric.squeeze!(Separator)
|
72
|
+
metric.gsub!(StartsOrEndsWithSeparator, Nothing)
|
73
|
+
metric
|
54
74
|
end
|
55
75
|
end
|
56
76
|
end
|
@@ -5,17 +5,21 @@ module Nunes
|
|
5
5
|
# Internal: Memory backend for recording instrumentation calls. This should
|
6
6
|
# never need to be used directly by a user of the gem.
|
7
7
|
class Memory < ::Nunes::Adapter
|
8
|
+
def self.wraps?(client)
|
9
|
+
client.is_a?(Hash)
|
10
|
+
end
|
11
|
+
|
8
12
|
def initialize(client = nil)
|
9
13
|
@client = client || {}
|
10
14
|
clear
|
11
15
|
end
|
12
16
|
|
13
17
|
def increment(metric, value = 1)
|
14
|
-
counters << [metric, value]
|
18
|
+
counters << [prepare(metric), value]
|
15
19
|
end
|
16
20
|
|
17
21
|
def timing(metric, value)
|
18
|
-
timers << [metric, value]
|
22
|
+
timers << [prepare(metric), value]
|
19
23
|
end
|
20
24
|
|
21
25
|
# Internal: Returns Array of any recorded timers with durations.
|
@@ -8,9 +8,15 @@ module Nunes
|
|
8
8
|
# adapter their gauge interface to the timing one used internally in the
|
9
9
|
# gem. This should never need to be used directly by a user of the gem.
|
10
10
|
class TimingAliased < ::Nunes::Adapter
|
11
|
+
def self.wraps?(client)
|
12
|
+
client.respond_to?(:increment) &&
|
13
|
+
client.respond_to?(:gauge) &&
|
14
|
+
!client.respond_to?(:timing)
|
15
|
+
end
|
16
|
+
|
11
17
|
# Internal: Adapter timing to gauge.
|
12
18
|
def timing(metric, duration)
|
13
|
-
@client.gauge metric, duration
|
19
|
+
@client.gauge prepare(metric), duration
|
14
20
|
end
|
15
21
|
end
|
16
22
|
end
|
data/lib/nunes/instrumentable.rb
CHANGED
@@ -1,49 +1,6 @@
|
|
1
1
|
require "active_support/notifications"
|
2
2
|
|
3
3
|
module Nunes
|
4
|
-
# Extend and instrument. Simple class that makes it easy to instrument method
|
5
|
-
# timing using ActiveSupport::Notifications.
|
6
|
-
#
|
7
|
-
# The event name is the name of the method being instrumented and the event
|
8
|
-
# namespace is the name of the class the method is in.
|
9
|
-
#
|
10
|
-
# Examples
|
11
|
-
#
|
12
|
-
# # To instrument an instance method, extend the module and instrument it.
|
13
|
-
# class User
|
14
|
-
# # Only need to do this once.
|
15
|
-
# extend Nunes::Instrumentable
|
16
|
-
#
|
17
|
-
# def something
|
18
|
-
# # ...
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# instrument_method_time :something
|
22
|
-
#
|
23
|
-
# # you can customize the event and namespace by providing the name option
|
24
|
-
# instrument_method_time :something, {
|
25
|
-
# name: "something.else.User",
|
26
|
-
# }
|
27
|
-
#
|
28
|
-
# # you can also add additional payload items
|
29
|
-
# instrument_method_time :something, {
|
30
|
-
# payload: {some: 'thing'},
|
31
|
-
# }
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# # To instrument a class method, you need to extend the module on the
|
35
|
-
# # singleton class and use the same to call the method.
|
36
|
-
# class User
|
37
|
-
# # Only need to do this once.
|
38
|
-
# singleton_class.extend Nunes::Instrumentable
|
39
|
-
#
|
40
|
-
# def self.something_class_level
|
41
|
-
# # ...
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# singleton_class.instrument_method_time :someting_class_level
|
45
|
-
# end
|
46
|
-
#
|
47
4
|
module Instrumentable
|
48
5
|
# Private
|
49
6
|
MethodTimeEventName = "instrument_method_time.nunes".freeze
|
@@ -64,18 +21,17 @@ module Nunes
|
|
64
21
|
instrumenter = options.fetch(:instrumenter) { ActiveSupport::Notifications }
|
65
22
|
|
66
23
|
payload[:metric] = options.fetch(:name) {
|
67
|
-
|
68
|
-
|
24
|
+
if name.nil?
|
25
|
+
raise ArgumentError, "For class methods you must provide the full name of the metric."
|
26
|
+
else
|
27
|
+
"#{name}.#{method_name}"
|
28
|
+
end
|
29
|
+
}
|
69
30
|
|
70
31
|
nunes_wrap_method(method_name, action) do |old_method_name, new_method_name|
|
71
32
|
define_method(new_method_name) do |*args, &block|
|
72
33
|
instrumenter.instrument(MethodTimeEventName, payload) {
|
73
|
-
|
74
|
-
|
75
|
-
payload[:arguments] = args
|
76
|
-
payload[:result] = result
|
77
|
-
|
78
|
-
result
|
34
|
+
send(old_method_name, *args, &block)
|
79
35
|
}
|
80
36
|
end
|
81
37
|
end
|
data/lib/nunes/subscriber.rb
CHANGED
@@ -32,38 +32,33 @@ module Nunes
|
|
32
32
|
def call(name, start, ending, transaction_id, payload)
|
33
33
|
# rails doesn't recommend instrumenting methods that start with bang
|
34
34
|
# when in production
|
35
|
-
return if name.
|
35
|
+
return if name.start_with?(BANG)
|
36
36
|
|
37
37
|
method_name = name.split('.').first
|
38
38
|
|
39
39
|
if respond_to?(method_name)
|
40
40
|
send(method_name, start, ending, transaction_id, payload)
|
41
|
-
else
|
42
|
-
$stderr.puts "#{self.class.name} did not respond to #{method_name} therefore it cannot instrument the event named #{name}."
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
# Internal: Increment a metric for the client.
|
47
45
|
#
|
48
46
|
# metric - The String name of the metric to increment.
|
47
|
+
# value - The Integer value to increment by.
|
49
48
|
#
|
50
49
|
# Returns nothing.
|
51
|
-
def increment(metric)
|
52
|
-
|
53
|
-
@adapter.increment metric
|
54
|
-
end
|
50
|
+
def increment(metric, value = 1)
|
51
|
+
@adapter.increment metric, value
|
55
52
|
end
|
56
53
|
|
57
54
|
# Internal: Track the timing of a metric for the client.
|
58
55
|
#
|
59
56
|
# metric - The String name of the metric.
|
60
|
-
#
|
57
|
+
# value - The Integer duration of the event in milliseconds.
|
61
58
|
#
|
62
59
|
# Returns nothing.
|
63
|
-
def timing(metric,
|
64
|
-
|
65
|
-
@adapter.timing metric, duration_in_ms
|
66
|
-
end
|
60
|
+
def timing(metric, value)
|
61
|
+
@adapter.timing metric, value
|
67
62
|
end
|
68
63
|
end
|
69
64
|
end
|
@@ -12,7 +12,7 @@ module Nunes
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def process_action(start, ending, transaction_id, payload)
|
15
|
-
controller = payload[:controller]
|
15
|
+
controller = payload[:controller]
|
16
16
|
action = payload[:action]
|
17
17
|
status = payload[:status]
|
18
18
|
exception_info = payload[:exception]
|
@@ -28,19 +28,19 @@ module Nunes
|
|
28
28
|
|
29
29
|
runtime = ((ending - start) * 1_000).round
|
30
30
|
|
31
|
-
timing "action_controller.runtime",
|
32
|
-
timing "action_controller.
|
33
|
-
timing "action_controller.
|
31
|
+
timing "action_controller.runtime.total", runtime
|
32
|
+
timing "action_controller.runtime.view", view_runtime if view_runtime
|
33
|
+
timing "action_controller.runtime.db", db_runtime if db_runtime
|
34
34
|
|
35
35
|
increment "action_controller.format.#{format}" if format
|
36
36
|
increment "action_controller.status.#{status}" if status
|
37
37
|
|
38
38
|
if controller && action
|
39
|
-
namespace = "action_controller.#{controller}.#{action}"
|
39
|
+
namespace = "action_controller.controller.#{controller}.#{action}"
|
40
40
|
|
41
|
-
timing "#{namespace}.runtime", runtime
|
42
|
-
timing "#{namespace}.
|
43
|
-
timing "#{namespace}.
|
41
|
+
timing "#{namespace}.runtime.total", runtime
|
42
|
+
timing "#{namespace}.runtime.view", view_runtime if view_runtime
|
43
|
+
timing "#{namespace}.runtime.db", db_runtime if db_runtime
|
44
44
|
end
|
45
45
|
|
46
46
|
if exception_info
|
@@ -16,7 +16,7 @@ module Nunes
|
|
16
16
|
mailer = payload[:mailer]
|
17
17
|
|
18
18
|
if mailer
|
19
|
-
timing "action_mailer.deliver.#{mailer
|
19
|
+
timing "action_mailer.deliver.#{mailer}", runtime
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,7 +25,7 @@ module Nunes
|
|
25
25
|
mailer = payload[:mailer]
|
26
26
|
|
27
27
|
if mailer
|
28
|
-
timing "action_mailer.receive.#{mailer
|
28
|
+
timing "action_mailer.receive.#{mailer}", runtime
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -12,20 +12,20 @@ module Nunes
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def render_template(start, ending, transaction_id, payload)
|
15
|
-
instrument_identifier payload[:identifier], start, ending
|
15
|
+
instrument_identifier :template, payload[:identifier], start, ending
|
16
16
|
end
|
17
17
|
|
18
18
|
def render_partial(start, ending, transaction_id, payload)
|
19
|
-
instrument_identifier payload[:identifier], start, ending
|
19
|
+
instrument_identifier :partial, payload[:identifier], start, ending
|
20
20
|
end
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
24
|
# Private: Sends timing information about identifier event.
|
25
|
-
def instrument_identifier(identifier, start, ending)
|
26
|
-
if identifier
|
25
|
+
def instrument_identifier(kind, identifier, start, ending)
|
26
|
+
if identifier
|
27
27
|
runtime = ((ending - start) * 1_000).round
|
28
|
-
timing identifier_to_metric(identifier), runtime
|
28
|
+
timing identifier_to_metric(kind, identifier), runtime
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -33,11 +33,10 @@ module Nunes
|
|
33
33
|
# root from the full path.
|
34
34
|
#
|
35
35
|
# identifier - The String full path to the template or partial.
|
36
|
-
def identifier_to_metric(identifier)
|
37
|
-
rails_root = ::Rails.root.to_s +
|
36
|
+
def identifier_to_metric(kind, identifier)
|
37
|
+
rails_root = ::Rails.root.to_s + File::SEPARATOR
|
38
38
|
view_path = identifier.gsub(rails_root, '')
|
39
|
-
|
40
|
-
"action_view.#{metric}"
|
39
|
+
"action_view.#{kind}.#{view_path}" if view_path
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -17,41 +17,41 @@ module Nunes
|
|
17
17
|
|
18
18
|
case super_operation
|
19
19
|
when Symbol
|
20
|
-
timing "active_support.
|
20
|
+
timing "active_support.cache.#{super_operation}", runtime
|
21
21
|
else
|
22
|
-
timing "active_support.
|
22
|
+
timing "active_support.cache.read", runtime
|
23
23
|
end
|
24
24
|
|
25
25
|
hit = payload[:hit]
|
26
26
|
unless hit.nil?
|
27
27
|
hit_type = hit ? :hit : :miss
|
28
|
-
increment "active_support.
|
28
|
+
increment "active_support.cache.#{hit_type}"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
def cache_generate(start, ending, transaction_id, payload)
|
33
33
|
runtime = ((ending - start) * 1_000).round
|
34
|
-
timing "active_support.
|
34
|
+
timing "active_support.cache.fetch_generate", runtime
|
35
35
|
end
|
36
36
|
|
37
37
|
def cache_fetch_hit(start, ending, transaction_id, payload)
|
38
38
|
runtime = ((ending - start) * 1_000).round
|
39
|
-
timing "active_support.
|
39
|
+
timing "active_support.cache.fetch_hit", runtime
|
40
40
|
end
|
41
41
|
|
42
42
|
def cache_write(start, ending, transaction_id, payload)
|
43
43
|
runtime = ((ending - start) * 1_000).round
|
44
|
-
timing "active_support.
|
44
|
+
timing "active_support.cache.write", runtime
|
45
45
|
end
|
46
46
|
|
47
47
|
def cache_delete(start, ending, transaction_id, payload)
|
48
48
|
runtime = ((ending - start) * 1_000).round
|
49
|
-
timing "active_support.
|
49
|
+
timing "active_support.cache.delete", runtime
|
50
50
|
end
|
51
51
|
|
52
52
|
def cache_exist?(start, ending, transaction_id, payload)
|
53
53
|
runtime = ((ending - start) * 1_000).round
|
54
|
-
timing "active_support.
|
54
|
+
timing "active_support.cache.exist", runtime
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/lib/nunes/version.rb
CHANGED
data/script/bench.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "benchmark"
|
2
|
+
require "securerandom"
|
3
|
+
require "active_support/notifications"
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup :default, :bench
|
6
|
+
|
7
|
+
require_relative "../lib/nunes"
|
8
|
+
|
9
|
+
adapter = Nunes::Adapter.wrap({})
|
10
|
+
Nunes::Subscribers::ActionController.subscribe(adapter)
|
11
|
+
|
12
|
+
require "rblineprof"
|
13
|
+
$profile = lineprof(/./) do
|
14
|
+
puts Benchmark.realtime {
|
15
|
+
1_000.times do
|
16
|
+
ActiveSupport::Notifications.instrument("process_action.action_controller")
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def show_file(file)
|
22
|
+
file = File.expand_path(file)
|
23
|
+
File.readlines(file).each_with_index do |line, num|
|
24
|
+
wall, cpu, calls = $profile[file][num+1]
|
25
|
+
if calls && calls > 0
|
26
|
+
printf "% 8.1fms + % 8.1fms (% 5d) | %s", cpu/1000.0, (wall-cpu)/1000.0, calls, line
|
27
|
+
# printf "% 8.1fms (% 5d) | %s", wall/1000.0, calls, line
|
28
|
+
else
|
29
|
+
printf " | %s", line
|
30
|
+
# printf " | %s", line
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
puts
|
36
|
+
$profile.each do |file, data|
|
37
|
+
total, child, exclusive = data[0]
|
38
|
+
puts file
|
39
|
+
printf " % 10.1fms in this file\n", exclusive/1000.0
|
40
|
+
printf " % 10.1fms in this file + children\n", total/1000.0
|
41
|
+
printf " % 10.1fms in children\n", child/1000.0
|
42
|
+
|
43
|
+
if file =~ /nunes\/lib/
|
44
|
+
show_file(file)
|
45
|
+
end
|
46
|
+
|
47
|
+
puts
|
48
|
+
end
|
data/script/release
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#/ Usage: release
|
3
|
+
#/
|
4
|
+
#/ Tag the version in the repo and push the gem.
|
5
|
+
#/
|
6
|
+
|
7
|
+
set -e
|
8
|
+
cd $(dirname "$0")/..
|
9
|
+
|
10
|
+
[ "$1" = "--help" -o "$1" = "-h" -o "$1" = "help" ] && {
|
11
|
+
grep '^#/' <"$0"| cut -c4-
|
12
|
+
exit 0
|
13
|
+
}
|
14
|
+
|
15
|
+
gem_name=nunes
|
16
|
+
|
17
|
+
# Build a new gem archive.
|
18
|
+
rm -rf $gem_name-*.gem
|
19
|
+
gem build -q $gem_name.gemspec
|
20
|
+
|
21
|
+
# Make sure we're on the master branch.
|
22
|
+
(git branch | grep -q '* master') || {
|
23
|
+
echo "Only release from the master branch."
|
24
|
+
exit 1
|
25
|
+
}
|
26
|
+
|
27
|
+
# Figure out what version we're releasing.
|
28
|
+
tag=v`ls $gem_name-*.gem | sed "s/^$gem_name-\(.*\)\.gem$/\1/"`
|
29
|
+
|
30
|
+
echo "Releasing $tag"
|
31
|
+
|
32
|
+
# Make sure we haven't released this version before.
|
33
|
+
git fetch -t origin
|
34
|
+
|
35
|
+
(git tag -l | grep -q "$tag") && {
|
36
|
+
echo "Whoops, there's already a '${tag}' tag."
|
37
|
+
exit 1
|
38
|
+
}
|
39
|
+
|
40
|
+
# Tag it and bag it.
|
41
|
+
gem push $gem_name-*.gem && git tag "$tag" &&
|
42
|
+
git push origin master && git push origin "$tag"
|
data/test/adapter_test.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require "helper"
|
2
|
+
require "minitest/mock"
|
2
3
|
|
3
4
|
class AdapterTest < ActiveSupport::TestCase
|
5
|
+
def separator
|
6
|
+
Nunes::Adapter::Separator
|
7
|
+
end
|
8
|
+
|
4
9
|
test "wrap for statsd" do
|
5
10
|
client_with_gauge_and_timing = Class.new do
|
6
11
|
def increment(*args); end
|
@@ -9,7 +14,7 @@ class AdapterTest < ActiveSupport::TestCase
|
|
9
14
|
end.new
|
10
15
|
|
11
16
|
adapter = Nunes::Adapter.wrap(client_with_gauge_and_timing)
|
12
|
-
assert_instance_of Nunes::
|
17
|
+
assert_instance_of Nunes::Adapter, adapter
|
13
18
|
end
|
14
19
|
|
15
20
|
test "wrap for instrumental" do
|
@@ -37,4 +42,75 @@ class AdapterTest < ActiveSupport::TestCase
|
|
37
42
|
test "wrap with nil" do
|
38
43
|
assert_raises(ArgumentError) { Nunes::Adapter.wrap(nil) }
|
39
44
|
end
|
45
|
+
|
46
|
+
test "wrap with straight up gibberish yo" do
|
47
|
+
assert_raises(ArgumentError) { Nunes::Adapter.wrap(Object.new) }
|
48
|
+
end
|
49
|
+
|
50
|
+
test "passes increment along" do
|
51
|
+
mock = MiniTest::Mock.new
|
52
|
+
mock.expect :increment, nil, ["single", 1]
|
53
|
+
mock.expect :increment, nil, ["double", 2]
|
54
|
+
|
55
|
+
client = Nunes::Adapter.new(mock)
|
56
|
+
client.increment("single")
|
57
|
+
client.increment("double", 2)
|
58
|
+
|
59
|
+
mock.verify
|
60
|
+
end
|
61
|
+
|
62
|
+
test "passes timing along" do
|
63
|
+
mock = MiniTest::Mock.new
|
64
|
+
mock.expect :timing, nil, ["foo", 23]
|
65
|
+
|
66
|
+
client = Nunes::Adapter.new(mock)
|
67
|
+
client.timing("foo", 23)
|
68
|
+
|
69
|
+
mock.verify
|
70
|
+
end
|
71
|
+
|
72
|
+
test "prepare leaves good metrics alone" do
|
73
|
+
adapter = Nunes::Adapter.new(nil)
|
74
|
+
|
75
|
+
[
|
76
|
+
"foo",
|
77
|
+
"foo1234",
|
78
|
+
"foo-bar",
|
79
|
+
"foo_bar",
|
80
|
+
"Foo",
|
81
|
+
"FooBar",
|
82
|
+
"FOOBAR",
|
83
|
+
"foo#{separator}bar",
|
84
|
+
"foo#{separator}bar_baz",
|
85
|
+
"foo#{separator}bar_baz-wick",
|
86
|
+
"Foo#{separator}1234",
|
87
|
+
"Foo#{separator}Bar1234",
|
88
|
+
].each do |expected|
|
89
|
+
assert_equal expected, adapter.prepare(expected)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
test "prepare with bad metric names" do
|
94
|
+
adapter = Nunes::Adapter.new(nil)
|
95
|
+
|
96
|
+
{
|
97
|
+
"#{separator}foo" => "foo",
|
98
|
+
"foo#{separator}" => "foo",
|
99
|
+
"foo@bar" => "foo#{separator}bar",
|
100
|
+
"foo@$%^*^&bar" => "foo#{separator}bar",
|
101
|
+
"foo#{separator}#{separator}bar" => "foo#{separator}bar",
|
102
|
+
"app/views/posts" => "app#{separator}views#{separator}posts",
|
103
|
+
"Admin::PostsController#{separator}index" => "Admin#{separator}PostsController#{separator}index",
|
104
|
+
}.each do |metric, expected|
|
105
|
+
assert_equal expected, adapter.prepare(metric)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
test "prepare does not modify original metric" do
|
110
|
+
adapter = Nunes::Adapter.new(nil)
|
111
|
+
original = "app/views/posts"
|
112
|
+
result = adapter.prepare("original")
|
113
|
+
|
114
|
+
assert_equal "app/views/posts", original
|
115
|
+
end
|
40
116
|
end
|
@@ -27,8 +27,8 @@ class CacheInstrumentationTest < ActiveSupport::TestCase
|
|
27
27
|
test "cache_read miss" do
|
28
28
|
cache.read('foo')
|
29
29
|
|
30
|
-
assert_timer "active_support.
|
31
|
-
assert_counter "active_support.
|
30
|
+
assert_timer "active_support.cache.read"
|
31
|
+
assert_counter "active_support.cache.miss"
|
32
32
|
end
|
33
33
|
|
34
34
|
test "cache_read hit" do
|
@@ -36,13 +36,13 @@ class CacheInstrumentationTest < ActiveSupport::TestCase
|
|
36
36
|
adapter.clear
|
37
37
|
cache.read('foo')
|
38
38
|
|
39
|
-
assert_timer "active_support.
|
40
|
-
assert_counter "active_support.
|
39
|
+
assert_timer "active_support.cache.read"
|
40
|
+
assert_counter "active_support.cache.hit"
|
41
41
|
end
|
42
42
|
|
43
43
|
test "cache_generate" do
|
44
44
|
cache.fetch('foo') { |key| :generate_me_please }
|
45
|
-
assert_timer "active_support.
|
45
|
+
assert_timer "active_support.cache.fetch_generate"
|
46
46
|
end
|
47
47
|
|
48
48
|
test "cache_fetch with hit" do
|
@@ -50,30 +50,30 @@ class CacheInstrumentationTest < ActiveSupport::TestCase
|
|
50
50
|
adapter.clear
|
51
51
|
cache.fetch('foo') { |key| :never_gets_here }
|
52
52
|
|
53
|
-
assert_timer "active_support.
|
54
|
-
assert_timer "active_support.
|
53
|
+
assert_timer "active_support.cache.fetch"
|
54
|
+
assert_timer "active_support.cache.fetch_hit"
|
55
55
|
end
|
56
56
|
|
57
57
|
test "cache_fetch with miss" do
|
58
58
|
cache.fetch('foo') { 'foo value set here' }
|
59
59
|
|
60
|
-
assert_timer "active_support.
|
61
|
-
assert_timer "active_support.
|
62
|
-
assert_timer "active_support.
|
60
|
+
assert_timer "active_support.cache.fetch"
|
61
|
+
assert_timer "active_support.cache.fetch_generate"
|
62
|
+
assert_timer "active_support.cache.write"
|
63
63
|
end
|
64
64
|
|
65
65
|
test "cache_write" do
|
66
66
|
cache.write('foo', 'bar')
|
67
|
-
assert_timer "active_support.
|
67
|
+
assert_timer "active_support.cache.write"
|
68
68
|
end
|
69
69
|
|
70
70
|
test "cache_delete" do
|
71
71
|
cache.delete('foo')
|
72
|
-
assert_timer "active_support.
|
72
|
+
assert_timer "active_support.cache.delete"
|
73
73
|
end
|
74
74
|
|
75
75
|
test "cache_exist?" do
|
76
76
|
cache.exist?('foo')
|
77
|
-
assert_timer "active_support.
|
77
|
+
assert_timer "active_support.cache.exist"
|
78
78
|
end
|
79
79
|
end
|
@@ -22,11 +22,11 @@ class ControllerInstrumentationTest < ActionController::TestCase
|
|
22
22
|
assert_counter "action_controller.status.200"
|
23
23
|
assert_counter "action_controller.format.html"
|
24
24
|
|
25
|
-
assert_timer "action_controller.runtime"
|
26
|
-
assert_timer "action_controller.
|
25
|
+
assert_timer "action_controller.runtime.total"
|
26
|
+
assert_timer "action_controller.runtime.view"
|
27
27
|
|
28
|
-
assert_timer "action_controller.
|
29
|
-
assert_timer "action_controller.
|
28
|
+
assert_timer "action_controller.controller.PostsController.index.runtime.total"
|
29
|
+
assert_timer "action_controller.controller.PostsController.index.runtime.view"
|
30
30
|
end
|
31
31
|
|
32
32
|
test "send_data" do
|
@@ -36,11 +36,11 @@ class ControllerInstrumentationTest < ActionController::TestCase
|
|
36
36
|
|
37
37
|
assert_counter "action_controller.status.200"
|
38
38
|
|
39
|
-
assert_timer "action_controller.runtime"
|
40
|
-
assert_timer "action_controller.
|
39
|
+
assert_timer "action_controller.runtime.total"
|
40
|
+
assert_timer "action_controller.runtime.view"
|
41
41
|
|
42
|
-
assert_timer "action_controller.
|
43
|
-
assert_timer "action_controller.
|
42
|
+
assert_timer "action_controller.controller.PostsController.some_data.runtime.total"
|
43
|
+
assert_timer "action_controller.controller.PostsController.some_data.runtime.view"
|
44
44
|
end
|
45
45
|
|
46
46
|
test "send_file" do
|
@@ -50,11 +50,11 @@ class ControllerInstrumentationTest < ActionController::TestCase
|
|
50
50
|
|
51
51
|
assert_counter"action_controller.status.200"
|
52
52
|
|
53
|
-
assert_timer "action_controller.runtime"
|
54
|
-
assert_timer "action_controller.
|
53
|
+
assert_timer "action_controller.runtime.total"
|
54
|
+
assert_timer "action_controller.controller.PostsController.some_file.runtime.total"
|
55
55
|
|
56
|
-
assert ! adapter.timer?("action_controller.
|
57
|
-
assert ! adapter.timer?("action_controller.
|
56
|
+
assert ! adapter.timer?("action_controller.runtime.view")
|
57
|
+
assert ! adapter.timer?("action_controller.controller.PostsController.some_file.runtime.view")
|
58
58
|
end
|
59
59
|
|
60
60
|
test "redirect_to" do
|
@@ -64,11 +64,11 @@ class ControllerInstrumentationTest < ActionController::TestCase
|
|
64
64
|
|
65
65
|
assert_counter "action_controller.status.302"
|
66
66
|
|
67
|
-
assert_timer "action_controller.runtime"
|
68
|
-
assert_timer "action_controller.
|
67
|
+
assert_timer "action_controller.runtime.total"
|
68
|
+
assert_timer "action_controller.controller.PostsController.some_redirect.runtime.total"
|
69
69
|
|
70
|
-
assert_no_timer "action_controller.
|
71
|
-
assert_no_timer "action_controller.
|
70
|
+
assert_no_timer "action_controller.runtime.view"
|
71
|
+
assert_no_timer "action_controller.controller.PostsController.some_redirect.runtime.view"
|
72
72
|
end
|
73
73
|
|
74
74
|
test "action with exception" do
|
@@ -79,10 +79,10 @@ class ControllerInstrumentationTest < ActionController::TestCase
|
|
79
79
|
assert_counter "action_controller.exception.RuntimeError"
|
80
80
|
assert_counter "action_controller.format.html"
|
81
81
|
|
82
|
-
assert_timer "action_controller.runtime"
|
83
|
-
assert_timer "action_controller.
|
82
|
+
assert_timer "action_controller.runtime.total"
|
83
|
+
assert_timer "action_controller.controller.PostsController.some_boom.runtime.total"
|
84
84
|
|
85
|
-
assert_no_timer "action_controller.
|
86
|
-
assert_no_timer "action_controller.
|
85
|
+
assert_no_timer "action_controller.runtime.view"
|
86
|
+
assert_no_timer "action_controller.controller.PostsController.some_boom.runtime.view"
|
87
87
|
end
|
88
88
|
end
|
data/test/instrumentable_test.rb
CHANGED
@@ -18,6 +18,14 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
18
18
|
@thing_class = Class.new {
|
19
19
|
extend Nunes::Instrumentable
|
20
20
|
|
21
|
+
class << self
|
22
|
+
extend Nunes::Instrumentable
|
23
|
+
|
24
|
+
def find(*args)
|
25
|
+
:nope
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
def self.name
|
22
30
|
'Thing'
|
23
31
|
end
|
@@ -50,12 +58,31 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
50
58
|
event = slurp_events { thing_class.new.yo(some: 'thing') }.last
|
51
59
|
|
52
60
|
assert_not_nil event, "No events were found."
|
53
|
-
assert_equal "
|
54
|
-
|
55
|
-
|
61
|
+
assert_equal "Thing.yo", event.payload[:metric]
|
62
|
+
assert_in_delta 0, event.duration, 0.1
|
63
|
+
|
64
|
+
assert_timer "Thing.yo"
|
65
|
+
end
|
66
|
+
|
67
|
+
test "instrument_method_time for class method without full metric name" do
|
68
|
+
# I'd really like to not do this, but I don't have a name for the class
|
69
|
+
# which makes it hard to automatically set the name. If anyone has a fix,
|
70
|
+
# let me know.
|
71
|
+
assert_raises ArgumentError do
|
72
|
+
thing_class.singleton_class.instrument_method_time :find
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
test "instrument_method_time for class method" do
|
77
|
+
thing_class.singleton_class.instrument_method_time :find, "Thing.find"
|
78
|
+
|
79
|
+
event = slurp_events { thing_class.find(1) }.last
|
80
|
+
|
81
|
+
assert_not_nil event, "No events were found."
|
82
|
+
assert_equal "Thing.find", event.payload[:metric]
|
56
83
|
assert_in_delta 0, event.duration, 0.1
|
57
84
|
|
58
|
-
assert_timer "
|
85
|
+
assert_timer "Thing.find"
|
59
86
|
end
|
60
87
|
|
61
88
|
test "instrument_method_time with custom name in hash" do
|
@@ -64,9 +91,9 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
64
91
|
event = slurp_events { thing_class.new.yo(some: 'thing') }.last
|
65
92
|
|
66
93
|
assert_not_nil event, "No events were found."
|
67
|
-
assert_equal "
|
94
|
+
assert_equal "Thingy.yohoho", event.payload[:metric]
|
68
95
|
|
69
|
-
assert_timer "
|
96
|
+
assert_timer "Thingy.yohoho"
|
70
97
|
end
|
71
98
|
|
72
99
|
test "instrument_method_time with custom name as string" do
|
@@ -75,9 +102,9 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
75
102
|
event = slurp_events { thing_class.new.yo(some: 'thing') }.last
|
76
103
|
|
77
104
|
assert_not_nil event, "No events were found."
|
78
|
-
assert_equal "
|
105
|
+
assert_equal "Thingy.yohoho", event.payload[:metric]
|
79
106
|
|
80
|
-
assert_timer "
|
107
|
+
assert_timer "Thingy.yohoho"
|
81
108
|
end
|
82
109
|
|
83
110
|
test "instrument_method_time with custom payload" do
|
@@ -88,7 +115,7 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
88
115
|
assert_not_nil event, "No events were found."
|
89
116
|
assert_equal "loadin", event.payload[:pay]
|
90
117
|
|
91
|
-
assert_timer "
|
118
|
+
assert_timer "Thing.yo"
|
92
119
|
end
|
93
120
|
|
94
121
|
def slurp_events(&block)
|
@@ -16,11 +16,11 @@ class MailerInstrumentationTest < ActionMailer::TestCase
|
|
16
16
|
|
17
17
|
test "deliver" do
|
18
18
|
PostMailer.created.deliver
|
19
|
-
assert_timer "action_mailer.deliver.
|
19
|
+
assert_timer "action_mailer.deliver.PostMailer"
|
20
20
|
end
|
21
21
|
|
22
22
|
test "receive" do
|
23
23
|
PostMailer.receive PostMailer.created
|
24
|
-
assert_timer "action_mailer.receive.
|
24
|
+
assert_timer "action_mailer.receive.PostMailer"
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class NamespacedControllerInstrumentationTest < ActionController::TestCase
|
4
|
+
tests Admin::PostsController
|
5
|
+
|
6
|
+
setup :setup_subscriber
|
7
|
+
teardown :teardown_subscriber
|
8
|
+
|
9
|
+
def setup_subscriber
|
10
|
+
@subscriber = Nunes::Subscribers::ActionController.subscribe(adapter)
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown_subscriber
|
14
|
+
ActiveSupport::Notifications.unsubscribe @subscriber if @subscriber
|
15
|
+
end
|
16
|
+
|
17
|
+
test "process_action" do
|
18
|
+
get :index
|
19
|
+
|
20
|
+
assert_response :success
|
21
|
+
|
22
|
+
assert_timer "action_controller.controller.Admin.PostsController.index.runtime.total"
|
23
|
+
assert_timer "action_controller.controller.Admin.PostsController.index.runtime.view"
|
24
|
+
end
|
25
|
+
end
|
@@ -18,13 +18,13 @@ class ViewInstrumentationTest < ActionController::TestCase
|
|
18
18
|
get :index
|
19
19
|
|
20
20
|
assert_response :success
|
21
|
-
assert_timer "action_view.app.views.posts.index.html.erb"
|
21
|
+
assert_timer "action_view.template.app.views.posts.index.html.erb"
|
22
22
|
end
|
23
23
|
|
24
24
|
test "render_partial" do
|
25
25
|
get :index
|
26
26
|
|
27
27
|
assert_response :success
|
28
|
-
assert_timer "action_view.app.views.posts._post.html.erb"
|
28
|
+
assert_timer "action_view.partial.app.views.posts._post.html.erb"
|
29
29
|
end
|
30
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nunes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -36,12 +36,12 @@ extensions: []
|
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
38
|
- .gitignore
|
39
|
+
- Changelog.md
|
39
40
|
- Gemfile
|
40
41
|
- LICENSE.txt
|
41
42
|
- README.md
|
42
43
|
- lib/nunes.rb
|
43
44
|
- lib/nunes/adapter.rb
|
44
|
-
- lib/nunes/adapters/default.rb
|
45
45
|
- lib/nunes/adapters/memory.rb
|
46
46
|
- lib/nunes/adapters/timing_aliased.rb
|
47
47
|
- lib/nunes/instrumentable.rb
|
@@ -54,11 +54,12 @@ files:
|
|
54
54
|
- lib/nunes/subscribers/nunes.rb
|
55
55
|
- lib/nunes/version.rb
|
56
56
|
- nunes.gemspec
|
57
|
+
- script/bench.rb
|
57
58
|
- script/bootstrap
|
59
|
+
- script/release
|
58
60
|
- script/test
|
59
61
|
- script/watch
|
60
62
|
- test/adapter_test.rb
|
61
|
-
- test/adapters/default_test.rb
|
62
63
|
- test/adapters/timing_aliased_test.rb
|
63
64
|
- test/cache_instrumentation_test.rb
|
64
65
|
- test/controller_instrumentation_test.rb
|
@@ -67,12 +68,14 @@ files:
|
|
67
68
|
- test/instrumentable_test.rb
|
68
69
|
- test/mailer_instrumentation_test.rb
|
69
70
|
- test/model_instrumentation_test.rb
|
71
|
+
- test/namespaced_controller_instrumentation_test.rb
|
70
72
|
- test/nunes_test.rb
|
71
73
|
- test/rails_app/.gitignore
|
72
74
|
- test/rails_app/Rakefile
|
73
75
|
- test/rails_app/app/assets/images/rails.png
|
74
76
|
- test/rails_app/app/assets/javascripts/application.js
|
75
77
|
- test/rails_app/app/assets/stylesheets/application.css
|
78
|
+
- test/rails_app/app/controllers/admin/posts_controller.rb
|
76
79
|
- test/rails_app/app/controllers/application_controller.rb
|
77
80
|
- test/rails_app/app/controllers/posts_controller.rb
|
78
81
|
- test/rails_app/app/helpers/application_helper.rb
|
@@ -80,6 +83,7 @@ files:
|
|
80
83
|
- test/rails_app/app/mailers/post_mailer.rb
|
81
84
|
- test/rails_app/app/models/.gitkeep
|
82
85
|
- test/rails_app/app/models/post.rb
|
86
|
+
- test/rails_app/app/views/admin/posts/index.html.erb
|
83
87
|
- test/rails_app/app/views/layouts/application.html.erb
|
84
88
|
- test/rails_app/app/views/post_mailer/created.text.erb
|
85
89
|
- test/rails_app/app/views/posts/_post.html.erb
|
@@ -144,7 +148,6 @@ specification_version: 3
|
|
144
148
|
summary: The friendly gem that instruments everything for you, like I would if I could.
|
145
149
|
test_files:
|
146
150
|
- test/adapter_test.rb
|
147
|
-
- test/adapters/default_test.rb
|
148
151
|
- test/adapters/timing_aliased_test.rb
|
149
152
|
- test/cache_instrumentation_test.rb
|
150
153
|
- test/controller_instrumentation_test.rb
|
@@ -153,12 +156,14 @@ test_files:
|
|
153
156
|
- test/instrumentable_test.rb
|
154
157
|
- test/mailer_instrumentation_test.rb
|
155
158
|
- test/model_instrumentation_test.rb
|
159
|
+
- test/namespaced_controller_instrumentation_test.rb
|
156
160
|
- test/nunes_test.rb
|
157
161
|
- test/rails_app/.gitignore
|
158
162
|
- test/rails_app/Rakefile
|
159
163
|
- test/rails_app/app/assets/images/rails.png
|
160
164
|
- test/rails_app/app/assets/javascripts/application.js
|
161
165
|
- test/rails_app/app/assets/stylesheets/application.css
|
166
|
+
- test/rails_app/app/controllers/admin/posts_controller.rb
|
162
167
|
- test/rails_app/app/controllers/application_controller.rb
|
163
168
|
- test/rails_app/app/controllers/posts_controller.rb
|
164
169
|
- test/rails_app/app/helpers/application_helper.rb
|
@@ -166,6 +171,7 @@ test_files:
|
|
166
171
|
- test/rails_app/app/mailers/post_mailer.rb
|
167
172
|
- test/rails_app/app/models/.gitkeep
|
168
173
|
- test/rails_app/app/models/post.rb
|
174
|
+
- test/rails_app/app/views/admin/posts/index.html.erb
|
169
175
|
- test/rails_app/app/views/layouts/application.html.erb
|
170
176
|
- test/rails_app/app/views/post_mailer/created.text.erb
|
171
177
|
- test/rails_app/app/views/posts/_post.html.erb
|
@@ -1,10 +0,0 @@
|
|
1
|
-
require "nunes/adapter"
|
2
|
-
|
3
|
-
module Nunes
|
4
|
-
module Adapters
|
5
|
-
# Internal: Default is the assumed interface, so we don't need to override
|
6
|
-
# anything. This should never need to be used directly by a user of the gem.
|
7
|
-
class Default < ::Nunes::Adapter
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require "helper"
|
2
|
-
require "minitest/mock"
|
3
|
-
|
4
|
-
class DefaultAdapterTest < ActiveSupport::TestCase
|
5
|
-
test "passes increment along" do
|
6
|
-
mock = MiniTest::Mock.new
|
7
|
-
mock.expect :increment, nil, ["single", 1]
|
8
|
-
mock.expect :increment, nil, ["double", 2]
|
9
|
-
|
10
|
-
client = Nunes::Adapters::Default.new(mock)
|
11
|
-
client.increment("single")
|
12
|
-
client.increment("double", 2)
|
13
|
-
|
14
|
-
mock.verify
|
15
|
-
end
|
16
|
-
|
17
|
-
test "passes timing along" do
|
18
|
-
mock = MiniTest::Mock.new
|
19
|
-
mock.expect :timing, nil, ["foo", 23]
|
20
|
-
|
21
|
-
client = Nunes::Adapters::Default.new(mock)
|
22
|
-
client.timing("foo", 23)
|
23
|
-
|
24
|
-
mock.verify
|
25
|
-
end
|
26
|
-
end
|