instrumental 0.1.4
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.
- data/Gemfile +5 -0
- data/Gemfile.lock +26 -0
- data/MIT-LICENCE +20 -0
- data/README +3 -0
- data/Rakefile +34 -0
- data/TODO +3 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/instrumental.gemspec +66 -0
- data/lib/instrumental.rb +53 -0
- data/lib/instrumental/agent.rb +100 -0
- data/lib/instrumental/configuration.rb +70 -0
- data/lib/instrumental/instrument.rb +19 -0
- data/lib/instrumental/intervalometer.rb +30 -0
- data/lib/tasks/install.rake +23 -0
- data/lib/tasks/templates/instrumental.rb.erb +4 -0
- data/spec/instrumental/agent_spec.rb +20 -0
- data/spec/instrumental/configuration_spec.rb +245 -0
- data/spec/instrumental/instrument_methods_spec.rb +50 -0
- data/spec/instrumental/intervalometer_spec.rb +20 -0
- data/spec/instrumental/setup_methods_spec.rb +24 -0
- data/spec/spec_helper.rb +1 -0
- metadata +132 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.6.2)
|
7
|
+
bundler (~> 1.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rspec (2.6.0)
|
12
|
+
rspec-core (~> 2.6.0)
|
13
|
+
rspec-expectations (~> 2.6.0)
|
14
|
+
rspec-mocks (~> 2.6.0)
|
15
|
+
rspec-core (2.6.2)
|
16
|
+
rspec-expectations (2.6.0)
|
17
|
+
diff-lcs (~> 1.1.2)
|
18
|
+
rspec-mocks (2.6.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
jeweler
|
25
|
+
rake (= 0.8.7)
|
26
|
+
rspec
|
data/MIT-LICENCE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Shearer Consultancy Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
9
|
+
t.pattern = 'spec/**/*_spec.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Generate documentation for the instrumental plugin.'
|
13
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = 'Instrumental'
|
16
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
17
|
+
rdoc.rdoc_files.include('README')
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Default: run the specs"
|
22
|
+
task :default => [:spec]
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'jeweler'
|
26
|
+
Jeweler::Tasks.new do |s|
|
27
|
+
s.name = "instrumental"
|
28
|
+
s.summary = s.description = "Rails instrumentation and client for imperialapp.com"
|
29
|
+
s.email = "support@imperialapp.com"
|
30
|
+
s.homepage = "http://github.com/imperialapp/instrumental"
|
31
|
+
s.authors = ["Douglas F Shearer"]
|
32
|
+
s.files = `git ls-files`.split("\n")
|
33
|
+
end
|
34
|
+
end
|
data/TODO
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.4
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'instrumental'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{instrumental}
|
8
|
+
s.version = "0.1.4"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Douglas F Shearer"]
|
12
|
+
s.date = %q{2011-06-06}
|
13
|
+
s.description = %q{Rails instrumentation and client for imperialapp.com}
|
14
|
+
s.email = %q{support@imperialapp.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README",
|
17
|
+
"TODO"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"MIT-LICENCE",
|
23
|
+
"README",
|
24
|
+
"Rakefile",
|
25
|
+
"TODO",
|
26
|
+
"VERSION",
|
27
|
+
"init.rb",
|
28
|
+
"instrumental.gemspec",
|
29
|
+
"lib/instrumental.rb",
|
30
|
+
"lib/instrumental/agent.rb",
|
31
|
+
"lib/instrumental/configuration.rb",
|
32
|
+
"lib/instrumental/instrument.rb",
|
33
|
+
"lib/instrumental/intervalometer.rb",
|
34
|
+
"lib/tasks/install.rake",
|
35
|
+
"lib/tasks/templates/instrumental.rb.erb",
|
36
|
+
"spec/instrumental/agent_spec.rb",
|
37
|
+
"spec/instrumental/configuration_spec.rb",
|
38
|
+
"spec/instrumental/instrument_methods_spec.rb",
|
39
|
+
"spec/instrumental/intervalometer_spec.rb",
|
40
|
+
"spec/instrumental/setup_methods_spec.rb",
|
41
|
+
"spec/spec_helper.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/imperialapp/instrumental}
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.6.2}
|
46
|
+
s.summary = %q{Rails instrumentation and client for imperialapp.com}
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<rake>, ["= 0.8.7"])
|
53
|
+
s.add_runtime_dependency(%q<rspec>, [">= 0"])
|
54
|
+
s.add_runtime_dependency(%q<jeweler>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
57
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
58
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
62
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
63
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/lib/instrumental.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'instrumental/agent'
|
2
|
+
require 'instrumental/configuration'
|
3
|
+
require 'instrumental/intervalometer'
|
4
|
+
require 'instrumental/instrument'
|
5
|
+
|
6
|
+
module Instrumental
|
7
|
+
|
8
|
+
@config = Configuration.new
|
9
|
+
|
10
|
+
def self.configure
|
11
|
+
yield @config
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.boot!
|
15
|
+
if @config.enabled?
|
16
|
+
|
17
|
+
if defined?(PhusionPassenger)
|
18
|
+
PhusionPassenger.on_event(:starting_worker_process) do
|
19
|
+
@config.logger.debug('Starting a new worker process')
|
20
|
+
Agent.instance.setup_and_run
|
21
|
+
end
|
22
|
+
|
23
|
+
PhusionPassenger.on_event(:stopping_worker_process) do
|
24
|
+
@config.logger.debug('Killing worker process')
|
25
|
+
Agent.instance.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
else
|
29
|
+
@config.logger.debug('Starting a new worker process')
|
30
|
+
Agent.instance.setup_and_run
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.config
|
36
|
+
@config
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.count(name, value=1)
|
40
|
+
Agent.instance.report(:count, name, value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.measure(name, value)
|
44
|
+
Agent.instance.report(:measure, name, value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.timer(name)
|
48
|
+
start_time = Time.now
|
49
|
+
yield
|
50
|
+
self.measure(name, Time.now - start_time)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'net/http'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Instrumental
|
6
|
+
class Agent
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
@@queue = { :count => {}, :measure => {} }
|
10
|
+
@@queue_mutex = Mutex.new
|
11
|
+
|
12
|
+
def report(type, name, value)
|
13
|
+
# TODO: Print this to log?
|
14
|
+
return nil unless config && config.enabled?
|
15
|
+
|
16
|
+
type = type.to_sym
|
17
|
+
@@queue_mutex.synchronize do
|
18
|
+
if type == :count
|
19
|
+
@@queue[:count][name] ||= 0
|
20
|
+
@@queue[:count][name] += value
|
21
|
+
else
|
22
|
+
@@queue[:measure][name] ||= []
|
23
|
+
@@queue[:measure][name] << value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_and_run
|
29
|
+
@intervalometer = Intervalometer.new(config.report_interval)
|
30
|
+
|
31
|
+
config.logger.debug("Starting agent. Reporting every #{config.report_interval} seconds")
|
32
|
+
@thread = Thread.new do
|
33
|
+
begin
|
34
|
+
@intervalometer.run do
|
35
|
+
config.logger.debug('Intervalometer run')
|
36
|
+
new_queue_items = {}
|
37
|
+
@@queue_mutex.synchronize do
|
38
|
+
new_queue_items = @@queue.dup
|
39
|
+
@@queue[:count] = {}
|
40
|
+
@@queue[:measure] = {}
|
41
|
+
config.logger.debug("Queue contains #{new_queue_items.inspect}")
|
42
|
+
end
|
43
|
+
|
44
|
+
new_queue_items[:count].each do |name, value|
|
45
|
+
send_report(:count, name, value)
|
46
|
+
end
|
47
|
+
|
48
|
+
new_queue_items[:measure].each do |name, values|
|
49
|
+
send_report(:measure, name, values.join(','))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
rescue => e
|
53
|
+
config.logger.error e
|
54
|
+
config.logger.error e.backtrace.join("\n")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def stop
|
60
|
+
# If the app crashes, Passenger calls halt as it winds-down the process.
|
61
|
+
# Only call halt if intervalometer exists.
|
62
|
+
@intervalometer && @intervalometer.halt
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def config
|
68
|
+
Instrumental.config
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_report(type, name, value)
|
72
|
+
if type == :measure
|
73
|
+
attributes = { :values => value }
|
74
|
+
else
|
75
|
+
attributes = { :value => value }
|
76
|
+
end
|
77
|
+
|
78
|
+
attributes[:name] = URI.escape("#{ config.name_prefix }#{ name }")
|
79
|
+
attributes[:api_key] = config.api_key
|
80
|
+
|
81
|
+
# attributes_string = attributes.to_a.map{ |a| a.join('=') }.join('&')
|
82
|
+
|
83
|
+
path = "#{ config.path }#{ type }"
|
84
|
+
# config.logger.debug("Calling #{ path }")
|
85
|
+
|
86
|
+
response = post_response(path, attributes)
|
87
|
+
|
88
|
+
unless response.is_a?(Net::HTTPSuccess)
|
89
|
+
config.logger.error "[Instrumental] Unexpected response from server (#{ response.code }): #{ response.message }"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def post_response(path, params)
|
94
|
+
req = Net::HTTP::Post.new(path)
|
95
|
+
req.set_form_data(params)
|
96
|
+
Net::HTTP.new(config.host, config.port).start { |h| h.request(req) }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Instrumental
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
DEFAULT_REPORT_INTERVAL = 15.0
|
7
|
+
|
8
|
+
attr_reader :host
|
9
|
+
attr_reader :port
|
10
|
+
attr_reader :path
|
11
|
+
attr_reader :report_interval
|
12
|
+
attr_accessor :enabled
|
13
|
+
attr_writer :logger
|
14
|
+
attr_accessor :name_prefix
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@enabled = defined?(::Rails.env) ? Rails.env.production? : true
|
18
|
+
@host = 'in.imperialapp.com'
|
19
|
+
@port = 80
|
20
|
+
@name_prefix = ''
|
21
|
+
@path = '/in/'
|
22
|
+
@report_interval = DEFAULT_REPORT_INTERVAL
|
23
|
+
end
|
24
|
+
|
25
|
+
def enabled?
|
26
|
+
!!@enabled
|
27
|
+
end
|
28
|
+
|
29
|
+
def host=(val)
|
30
|
+
@host = val
|
31
|
+
|
32
|
+
raise(ArgumentError, "host is invalid") unless @host =~ /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?)?$/ix
|
33
|
+
end
|
34
|
+
|
35
|
+
def port=(val)
|
36
|
+
@port = val
|
37
|
+
|
38
|
+
raise(ArgumentError, "port must be an integer greater than 0") unless @port.to_i > 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def path=(val)
|
42
|
+
@path = val
|
43
|
+
|
44
|
+
raise(ArgumentError, 'path is invalid') unless @path =~ /^\/(.+\/)?$/
|
45
|
+
end
|
46
|
+
|
47
|
+
def report_interval=(val)
|
48
|
+
@report_interval = val.to_f
|
49
|
+
|
50
|
+
raise(ArgumentError, "report_interval should be greater than or equal to #{DEFAULT_REPORT_INTERVAL}") if @report_interval < DEFAULT_REPORT_INTERVAL
|
51
|
+
end
|
52
|
+
|
53
|
+
def api_key=(val)
|
54
|
+
@api_key = val
|
55
|
+
|
56
|
+
raise(ArgumentError, 'API key is invalid') unless @api_key =~ /^[a-f\d]{32}$/
|
57
|
+
end
|
58
|
+
|
59
|
+
def api_key
|
60
|
+
@api_key || raise(ArgumentError, 'API key must be set in configuration')
|
61
|
+
end
|
62
|
+
|
63
|
+
def logger
|
64
|
+
# The Rails logger is not available in an initializer, so we have to look for on-demand.
|
65
|
+
@logger ||= defined?(::Rails.logger) ? Rails.logger : Logger.new(STDOUT)
|
66
|
+
@logger
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Instrumental
|
2
|
+
module Instrument
|
3
|
+
|
4
|
+
def self.count(name, value=1)
|
5
|
+
Agent.instance.report(:count, name, value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.measure(name, value)
|
9
|
+
Agent.instance.report(:measure, name, value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.timer(name)
|
13
|
+
start_time = Time.now
|
14
|
+
yield
|
15
|
+
self.measure(name, Time.now - start_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Instrumental
|
2
|
+
class Intervalometer
|
3
|
+
|
4
|
+
def initialize(period=60.0)
|
5
|
+
@period = period.to_f
|
6
|
+
@running = true
|
7
|
+
@run_next = Time.now
|
8
|
+
end
|
9
|
+
|
10
|
+
def halt
|
11
|
+
# TODO: See if it would be possible for the intervalometer to do a
|
12
|
+
# final run before the thread exits.
|
13
|
+
@running = false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Runs a passed block at intervals defined by the period set during
|
17
|
+
# initialization. Uses intervalometer to keep reasonably precise intervals.
|
18
|
+
def run
|
19
|
+
while @running
|
20
|
+
if Time.now < @run_next
|
21
|
+
sleep @run_next - Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
@run_next = Time.now + @period
|
25
|
+
yield
|
26
|
+
end
|
27
|
+
end # run
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
namespace :instrumental do
|
2
|
+
|
3
|
+
desc 'Installs the configuration initializer'
|
4
|
+
task :install do
|
5
|
+
unless ENV.include?('api_key')
|
6
|
+
raise "usage: rake instrumental:install api_key=YOUR_API_KEY"
|
7
|
+
end
|
8
|
+
|
9
|
+
api_key = ENV['api_key']
|
10
|
+
template_path = File.expand_path(File.join(File.dirname(__FILE__), 'templates', 'instrumental.rb.erb'))
|
11
|
+
template = ERB.new(File.read(template_path))
|
12
|
+
location = File.join('config', 'initializers', 'instrumental.rb')
|
13
|
+
|
14
|
+
File.open(location, 'w+') do |f|
|
15
|
+
f.write template.result(binding)
|
16
|
+
end
|
17
|
+
|
18
|
+
puts 'Instrumental Installed!'
|
19
|
+
puts "Configuration written to #{location}"
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'instrumental/configuration'
|
3
|
+
|
4
|
+
include Instrumental
|
5
|
+
|
6
|
+
class Rails;end # Used for testing the logger.
|
7
|
+
|
8
|
+
describe Instrumental::Configuration do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@config = Configuration.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "in the default state" do
|
15
|
+
it "should raise an argument error for the missing API key" do
|
16
|
+
lambda { @config.api_key }.should raise_error(ArgumentError, 'API key must be set in configuration')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a host" do
|
20
|
+
@config.host.should == 'in.imperialapp.com'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have a port" do
|
24
|
+
@config.port.should == 80
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have a path" do
|
28
|
+
@config.path.should == '/in/'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should have a report interval" do
|
32
|
+
@config.report_interval.should == 15.0
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should have a logger" do
|
36
|
+
@config.logger.should be_a(Logger)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have enabled set to true" do
|
40
|
+
@config.logger.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have an empty name prefix" do
|
44
|
+
@config.name_prefix.should be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "where Rails is defined" do
|
49
|
+
context "production environment" do
|
50
|
+
before(:each) do
|
51
|
+
Rails.stub(:logger).and_return(@mock_logger = mock(:logger))
|
52
|
+
Rails.stub(:env).and_return(mock(:environment, :production? => true))
|
53
|
+
@rails_config = Configuration.new
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be the mock logger" do
|
57
|
+
@rails_config.logger.should == @mock_logger
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should have enabled as true" do
|
61
|
+
@rails_config.enabled.should be_true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "non-production environment" do
|
66
|
+
before(:each) do
|
67
|
+
Rails.stub(:env).and_return(mock(:environment, :production? => false))
|
68
|
+
@rails_config = Configuration.new
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should have enabled as false" do
|
72
|
+
@rails_config.enabled.should be_false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "Setting the API key" do
|
78
|
+
context "with a valid key" do
|
79
|
+
before(:each) do
|
80
|
+
@config.api_key = '01e694159b73a5f3784bbe9d63412b8d'
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not raise an error" do
|
84
|
+
lambda { @config.api_key }.should_not raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should have an API key" do
|
88
|
+
@config.api_key.should == '01e694159b73a5f3784bbe9d63412b8d'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
%w{cheese 123 01e694159b73a5f3784bbe9d63412b8 01e694159b73a5f3784bbe9d63412b8D}.each do |invalid_key|
|
93
|
+
context "with invalid key, #{invalid_key}," do
|
94
|
+
it "should raise an argument error" do
|
95
|
+
lambda { @config.api_key = invalid_key }.should raise_error(ArgumentError, 'API key is invalid')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "Setting the report_interval" do
|
102
|
+
context "with a valid value" do
|
103
|
+
it "should not raise an error" do
|
104
|
+
lambda { @config.report_interval = 20.1 }.should_not raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should have the report_interval set" do
|
108
|
+
@config.report_interval = 20.1
|
109
|
+
@config.report_interval.should == 20.1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "Setting the host" do
|
115
|
+
%w{in.imperialapp.com foo.bar.com foo.bar.rar.me}.each do |valid_host|
|
116
|
+
context "with a valid host, #{valid_host}" do
|
117
|
+
it "should not raise an error" do
|
118
|
+
lambda { @config.host = valid_host }.should_not raise_error
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should have the host set" do
|
122
|
+
@config.host = valid_host
|
123
|
+
@config.host.should == valid_host
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
%w{in.imperialapp.com/ http://in.imperialapp.com mince}.each do |invalid_host|
|
129
|
+
context "with invalid host, #{invalid_host}," do
|
130
|
+
it "should raise an argument error" do
|
131
|
+
lambda { @config.host = invalid_host }.should raise_error(ArgumentError, 'host is invalid')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "with a blank host" do
|
137
|
+
it "should raise an argument error" do
|
138
|
+
lambda { @config.host = '' }.should raise_error(ArgumentError, 'host is invalid')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "Setting the port" do
|
144
|
+
context "with a valid port" do
|
145
|
+
it "should not raise an error" do
|
146
|
+
lambda { @config.port = 3000 }.should_not raise_error
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should have the port set" do
|
150
|
+
@config.port = 3000
|
151
|
+
@config.port.should == 3000
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "with an invalid port" do
|
156
|
+
it "should raise an argument error for a string" do
|
157
|
+
lambda { @config.port = 'mince' }.should raise_error(ArgumentError, 'port must be an integer greater than 0')
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should raise an argument error for nil" do
|
161
|
+
lambda { @config.port = nil }.should raise_error(ArgumentError, 'port must be an integer greater than 0')
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should raise an argument error for 0" do
|
165
|
+
lambda { @config.port = 0 }.should raise_error(ArgumentError, 'port must be an integer greater than 0')
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "Setting the path" do
|
171
|
+
%w{/ /foo/ /bar/rar/ /23/}.each do |valid_path|
|
172
|
+
context "with a valid path, #{valid_path}" do
|
173
|
+
it "should not raise an error" do
|
174
|
+
lambda { @config.path = valid_path }.should_not raise_error
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should have the path set" do
|
178
|
+
@config.path = valid_path
|
179
|
+
@config.path.should == valid_path
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
%w{// bar/ /bar bar}.each do |invalid_path|
|
185
|
+
context "with invalid path, #{invalid_path}," do
|
186
|
+
it "should raise an argument error" do
|
187
|
+
lambda { @config.path = invalid_path }.should raise_error(ArgumentError, 'path is invalid')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "with a blank path" do
|
193
|
+
it "should raise an argument error" do
|
194
|
+
lambda { @config.path = '' }.should raise_error(ArgumentError, 'path is invalid')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "setting the logger" do
|
200
|
+
it "should have the logger set" do
|
201
|
+
@config.logger = 'foo'
|
202
|
+
@config.logger.should == 'foo'
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "setting enabled" do
|
207
|
+
before(:each) do
|
208
|
+
@config.enabled = 'non nil value'
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should have the enabled status set" do
|
212
|
+
@config.enabled.should == 'non nil value'
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "enabled?" do
|
217
|
+
it "should be false for nil" do
|
218
|
+
@config.enabled = nil
|
219
|
+
@config.should_not be_enabled
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should be false for false" do
|
223
|
+
@config.enabled = false
|
224
|
+
@config.should_not be_enabled
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should be true for true" do
|
228
|
+
@config.enabled = true
|
229
|
+
@config.should be_enabled
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should be true for other values" do
|
233
|
+
@config.enabled = 'non nil value'
|
234
|
+
@config.should be_enabled
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "setting the name_prefix" do
|
239
|
+
it "should have the name_prefix set" do
|
240
|
+
@config.name_prefix = 'my prefix'
|
241
|
+
@config.name_prefix.should == 'my prefix'
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'instrumental'
|
3
|
+
|
4
|
+
class Agent;end
|
5
|
+
|
6
|
+
describe 'public instrument methods' do
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Agent.stub(:instance).and_return(@mock_agent_instance = mock(:agent_instance))
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "count" do
|
13
|
+
context "without a value" do
|
14
|
+
it "should send a value of 1" do
|
15
|
+
@mock_agent_instance.should_receive(:report).with(:count, 'my name', 1)
|
16
|
+
|
17
|
+
Instrument.count('my name')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a value" do
|
22
|
+
it "should send the passed value" do
|
23
|
+
@mock_agent_instance.should_receive(:report).with(:count, 'my name', 23)
|
24
|
+
|
25
|
+
Instrument.count('my name', 23)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "measure" do
|
31
|
+
it "should send the passed value" do
|
32
|
+
@mock_agent_instance.should_receive(:report).with(:measure, 'my name', 19.2)
|
33
|
+
|
34
|
+
Instrument.measure('my name', 19.2)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "timer" do
|
39
|
+
it "should send the calculated time" do
|
40
|
+
delta = 1.574
|
41
|
+
Time.should_receive(:now).and_return(0)
|
42
|
+
Time.should_receive(:now).and_return(delta)
|
43
|
+
|
44
|
+
@mock_agent_instance.should_receive(:report).with(:measure, 'my name', delta)
|
45
|
+
|
46
|
+
Instrument.timer('my name') { 'do stuff' }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'instrumental/intervalometer'
|
3
|
+
|
4
|
+
include Instrumental
|
5
|
+
|
6
|
+
describe Instrumental::Intervalometer do
|
7
|
+
|
8
|
+
describe "initialize" do
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "halt" do
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "run" do
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'instrumental'
|
3
|
+
|
4
|
+
describe 'setup methods' do
|
5
|
+
|
6
|
+
describe "configure" do
|
7
|
+
|
8
|
+
# Speccing yield. http://awesomeful.net/posts/75-spec-your-yields-in-rspec
|
9
|
+
it "should call yield" do
|
10
|
+
# Instrumental.should_receive(:yield).with(instance_of(Instrumental::Configuration))
|
11
|
+
#
|
12
|
+
# Instrumental.configure do |c|
|
13
|
+
# c.api_key = 'foo foo'
|
14
|
+
# end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "boot" do
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rspec/core'
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: instrumental
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 4
|
10
|
+
version: 0.1.4
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Douglas F Shearer
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-06 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - "="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 49
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 8
|
33
|
+
- 7
|
34
|
+
version: 0.8.7
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: jeweler
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
65
|
+
description: Rails instrumentation and client for imperialapp.com
|
66
|
+
email: support@imperialapp.com
|
67
|
+
executables: []
|
68
|
+
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files:
|
72
|
+
- README
|
73
|
+
- TODO
|
74
|
+
files:
|
75
|
+
- Gemfile
|
76
|
+
- Gemfile.lock
|
77
|
+
- MIT-LICENCE
|
78
|
+
- README
|
79
|
+
- Rakefile
|
80
|
+
- TODO
|
81
|
+
- VERSION
|
82
|
+
- init.rb
|
83
|
+
- instrumental.gemspec
|
84
|
+
- lib/instrumental.rb
|
85
|
+
- lib/instrumental/agent.rb
|
86
|
+
- lib/instrumental/configuration.rb
|
87
|
+
- lib/instrumental/instrument.rb
|
88
|
+
- lib/instrumental/intervalometer.rb
|
89
|
+
- lib/tasks/install.rake
|
90
|
+
- lib/tasks/templates/instrumental.rb.erb
|
91
|
+
- spec/instrumental/agent_spec.rb
|
92
|
+
- spec/instrumental/configuration_spec.rb
|
93
|
+
- spec/instrumental/instrument_methods_spec.rb
|
94
|
+
- spec/instrumental/intervalometer_spec.rb
|
95
|
+
- spec/instrumental/setup_methods_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
has_rdoc: true
|
98
|
+
homepage: http://github.com/imperialapp/instrumental
|
99
|
+
licenses: []
|
100
|
+
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
version: "0"
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
hash: 3
|
121
|
+
segments:
|
122
|
+
- 0
|
123
|
+
version: "0"
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.6.2
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Rails instrumentation and client for imperialapp.com
|
131
|
+
test_files: []
|
132
|
+
|