Skip to content

Commit

Permalink
Added ability to give an instrumentation callback
Browse files Browse the repository at this point in the history
  • Loading branch information
Burke Libbey committed Mar 5, 2012
1 parent 28d52de commit 3b10b72
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 11 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ Available configuration options:

* `Wolverine.config.redis` (default `Redis.new`)
* `Wolverine.config.script_path` (default `Rails.root + 'app/wolverine'`)
* `Wolverine.config.instrumentation` (default none)

If you want to override one or both of these, doing so in an initializer is recommended but not required.
If you want to override one or more of these, doing so in an initializer is recommended but not required. See the [full documentation](http://shopify.github.com/wolverine/Wolverine/Configuration.html) for more details.

## More information

Expand Down
23 changes: 22 additions & 1 deletion lib/wolverine/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
module Wolverine
class Configuration < Struct.new(:redis, :script_path)
class Configuration < Struct.new(:redis, :script_path, :instrumentation)

# @return [Redis] the redis connection actively in use by Wolverine
def redis
super || @redis ||= Redis.new
end

# Wolverine.config.instrumentation can be used to specify a callback to
# fire with the runtime of each script. This can be useful for analyzing
# scripts to make sure they aren't running for an unreasonable amount of
# time.
#
# The proc will receive three parameters:
#
# * +script_name+: A unique identifier for the script, based on its
# location in the file system
# * +runtime+: A float, the total execution time of the script
# * +eval_type+: Either +eval+ or +evalsha+, the method used to run
# the script
# @return [#call] the proc or other callable to be triggered on completion
# of a script.
def instrumentation
super || @instrumentation ||= proc { |script_name, runtime, eval_type| nil }
end

# @return [Pathname] the path wolverine will check for scripts
def script_path
super || @script_path ||= Rails.root + 'app/wolverine'
end
Expand Down
23 changes: 20 additions & 3 deletions lib/wolverine/script.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'pathname'
require 'benchmark'
require 'digest/sha1'

module Wolverine
Expand All @@ -10,7 +12,7 @@ class Script
#
# @param file [Pathname] the full path to the indicated file
def initialize file
@file = file
@file = Pathname.new(file)
@content = load_lua file
@digest = Digest::SHA1.hexdigest @content
end
Expand Down Expand Up @@ -43,11 +45,26 @@ def call redis, *args
private

def run_evalsha redis, *args
redis.evalsha @digest, args.size, *args
instrument :evalsha do
redis.evalsha @digest, args.size, *args
end
end

def run_eval redis, *args
redis.eval @content, args.size, *args
instrument :eval do
redis.eval @content, args.size, *args
end
end

def instrument eval_type
ret = nil
runtime = Benchmark.realtime { ret = yield }
Wolverine.config.instrumentation.call relative_path.to_s, runtime, eval_type
ret
end

def relative_path
path = @file.relative_path_from(Wolverine.config.script_path)
end

def load_lua file
Expand Down
2 changes: 1 addition & 1 deletion lib/wolverine/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Wolverine
VERSION = "0.2.2"
VERSION = "0.2.3"
end
11 changes: 11 additions & 0 deletions test/wolverine/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ def test_default_script_path
assert_equal Pathname.new('foo/app/wolverine'), actual
end

def test_default_instrumentation
config = Wolverine::Configuration.new
assert_equal nil, config.instrumentation.call(1, 2, 3)
end

def test_setting_redis
config = Wolverine::Configuration.new
config.redis = :foo
Expand All @@ -31,5 +36,11 @@ def test_setting_script_path
assert_equal :foo, config.script_path
end

def test_setting_instrumentation
config = Wolverine::Configuration.new
config.instrumentation = proc { |a, b, c| :omg }
assert_equal :omg, config.instrumentation.call(1,2,3)
end

end
end
30 changes: 25 additions & 5 deletions test/wolverine/script_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ class ScriptTest < MiniTest::Unit::TestCase
DIGEST = Digest::SHA1.hexdigest(CONTENT)

def setup
base = Pathname.new('/a/b/c/d')
Wolverine.config.script_path = base
Wolverine::Script.any_instance.stubs(:load_lua => CONTENT)
end

def teardown
Wolverine.config.instrumentation = proc{}
end

def script
@script ||= Wolverine::Script.new('file1')
@script ||= Wolverine::Script.new('/a/b/c/d/e/file1.lua')
end

def test_error
base = Pathname.new('/a/b/c/d')
file = Pathname.new('/a/b/c/d/e/file1.lua')
Wolverine.config.script_path = base
redis = stub
redis.expects(:evalsha).raises(%q{ERR Error running script (call to f_178d75adaa46af3d8237cfd067c9fdff7b9d504f): [string "func definition"]:1: attempt to compare nil with number})
begin
script = Wolverine::Script.new(file)
script.call(redis)
rescue Wolverine::LuaError => e
assert_equal "attempt to compare nil with number", e.message
Expand All @@ -30,6 +32,24 @@ def test_error
end
end

def test_instrumentation
callback = Object.new
tc = self
meta = class << callback ; self ; end
meta.send(:define_method, :call) { |a, b, c|
tc.assert_equal "e/file1.lua", a
tc.assert_operator b, :<, 1
tc.assert_equal :evalsha, c
}
Wolverine.config.instrumentation = callback
redis = Class.new do
define_method(:evalsha) do |digest, size, *args|
nil
end
end
script.call(redis.new, :a, :b)
end

def test_call_with_cache_hit
tc = self
redis = Class.new do
Expand Down

0 comments on commit 3b10b72

Please sign in to comment.