Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongo mapper #34

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--color
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ group :development do
gem "rake"
gem "ruby-debug", :platforms => :ruby_18
gem "debugger", :platforms => :ruby_19
gem "mongo_mapper"
gem "bson_ext"
end

gem "codeclimate-test-reporter", group: :test, require: nil, github: "codeclimate/ruby-test-reporter"
3 changes: 2 additions & 1 deletion lib/oink/instrumentation.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
require 'oink/instrumentation/active_record'
require 'oink/instrumentation/memory_snapshot'
require 'oink/instrumentation/mongo_mapper'
require 'oink/instrumentation/memory_snapshot'
68 changes: 68 additions & 0 deletions lib/oink/instrumentation/mongo_mapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module Oink
def self.extended_mongo_mapper?
@oink_extended_mongo_mapper
end

def self.extended_mongo_mapper!
@oink_extended_mongo_mapper = true
end

def self.extend_mongo_mapper!
return if extended_mongo_mapper?

::MongoMapper::Document.instance_eval do
def included(klass)
super

klass.class_eval do
class << self
alias_method :allocate_before_oink, :allocate

def allocate
value = allocate_before_oink
Oink::Instrumentation::MongoMapper.increment_instance_type_count(self)
value
end
end

alias_method :initialize_before_oink, :initialize

def initialize(*args, &block)
value = initialize_before_oink(*args, &block)
Oink::Instrumentation::MongoMapper.increment_instance_type_count(self.class)
value
end

Oink.extended_mongo_mapper!
end
end
end
end

module Instrumentation
module MongoMapper
def self.reset_instance_type_count
self.instantiated_hash = {}
Thread.current['oink.mongomapper.instantiations_count'] = nil
end

def self.increment_instance_type_count(klass)
self.instantiated_hash ||= {}
self.instantiated_hash[klass.name] ||= 0
self.instantiated_hash[klass.name] += 1
end

def self.instantiated_hash
Thread.current['oink.mongomapper.instantiations'] ||= {}
end

def self.instantiated_hash=(hsh)
Thread.current['oink.mongomapper.instantiations'] = hsh
end

def self.total_objects_instantiated
Thread.current['oink.mongomapper.instantiations_count'] ||= self.instantiated_hash.values.sum
end
end
end
end
20 changes: 17 additions & 3 deletions lib/oink/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def initialize(app, options = {})
@instruments = options[:instruments] ? Array(options[:instruments]) : [:memory, :activerecord]

Oink.extend_active_record! if @instruments.include?(:activerecord)
Oink.extend_mongo_mapper! if @instruments.include?(:mongomapper)
end

def call(env)
Expand All @@ -19,6 +20,7 @@ def call(env)
log_routing(env)
log_memory
log_activerecord
log_mongomapper
log_completed
[status, headers, body]
end
Expand Down Expand Up @@ -47,8 +49,17 @@ def log_activerecord
if @instruments.include?(:activerecord)
sorted_list = Oink::HashUtils.to_sorted_array(ActiveRecord::Base.instantiated_hash)
sorted_list.unshift("Total: #{ActiveRecord::Base.total_objects_instantiated}")
@logger.info("Instantiation Breakdown: #{sorted_list.join(' | ')}")
reset_objects_instantiated
@logger.info("ActiveRecord Instantiation Breakdown: #{sorted_list.join(' | ')}")
reset_active_record_objects_instantiated
end
end

def log_mongomapper
if @instruments.include?(:mongomapper)
sorted_list = Oink::HashUtils.to_sorted_array(Oink::Instrumentation::MongoMapper.instantiated_hash)
sorted_list.unshift("Total: #{Oink::Instrumentation::MongoMapper.total_objects_instantiated}")
@logger.info("MongoMapper Instantiation Breakdown: #{sorted_list.join(' | ')}")
reset_mongo_mapper_objects_instantiated
end
end

Expand All @@ -62,9 +73,12 @@ def rails2_routing_info(env)
env['action_controller.request.path_parameters']
end

def reset_objects_instantiated
def reset_active_record_objects_instantiated
ActiveRecord::Base.reset_instance_type_count
end

def reset_mongo_mapper_objects_instantiated
Oink::Instrumentation::MongoMapper.reset_instance_type_count
end
end
end
4 changes: 4 additions & 0 deletions spec/helpers/database.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'active_record'
require 'mongo_mapper'

def setup_memory_database
ActiveRecord::Base.establish_connection(
Expand All @@ -17,4 +18,7 @@ def setup_memory_database
t.string "location"
end
end

MongoMapper.connection = Mongo::Connection.new('localhost')
MongoMapper.database = "oink"
end
94 changes: 78 additions & 16 deletions spec/oink/middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ def call(env)
Pig.create(:name => "Babe")
Pen.create(:location => "Backyard")
Pig.first

when "/mm_no_pigs"
when "/mm_two_pigs"
MMPig.create(:name => "Babe")
MMPig.first
when "/mm_two_pigs_in_a_pen"
MMPig.create(:name => "Babe")
MMPen.create(:location => "Backyard")
MMPig.first
end
[200, {}, ""]
end
Expand Down Expand Up @@ -58,25 +67,78 @@ def call(env)
end
end

it "reports 0 totals" do
get "/no_pigs"
log_output.string.should include("Instantiation Breakdown: Total: 0")
end
describe "for active record" do
let(:app) { Oink::Middleware.new(SampleApplication.new, :logger => logger, :instruments => [:memory, :activerecord]) }

it "reports totals first even if it's a tie" do
get "/two_pigs"
log_output.string.should include("Instantiation Breakdown: Total: 2 | Pig: 2")
end
it "reports 0 totals" do
get "/no_pigs"
log_output.string.should include("ActiveRecord Instantiation Breakdown: Total: 0")
end

it "reports pigs and pens instantiated" do
get "/two_pigs_in_a_pen"
log_output.string.should include("Instantiation Breakdown: Total: 3 | Pig: 2 | Pen: 1")
end
it "reports totals first even if it's a tie" do
get "/two_pigs"
log_output.string.should include("ActiveRecord Instantiation Breakdown: Total: 2 | Pig: 2")
end

it "logs memory usage" do
Oink::Instrumentation::MemorySnapshot.should_receive(:memory).and_return(4092)
get "/two_pigs_in_a_pen"
log_output.string.should include("Memory usage: 4092 | PID: #{$$}")
it "reports pigs and pens instantiated" do
get "/two_pigs_in_a_pen"
log_output.string.should include("ActiveRecord Instantiation Breakdown: Total: 3 | Pig: 2 | Pen: 1")
end

it "logs memory usage" do
Oink::Instrumentation::MemorySnapshot.should_receive(:memory).and_return(4092)
get "/two_pigs_in_a_pen"
log_output.string.should include("Memory usage: 4092 | PID: #{$$}")
end
end

describe "for mongo mapper" do
def define_class(class_name, &block)
if Object.const_defined?(class_name)
Object.send(:remove_const, class_name)
end

Object.const_set(class_name, Class.new(&block))
end

def define_classes
define_class :MMPig do
include MongoMapper::Document
belongs_to :pen, :class_name => "MMPen"
end

define_class :MMPen do
include MongoMapper::Document
end
end

let(:app) { Oink::Middleware.new(SampleApplication.new, :logger => logger, :instruments => [:memory, :mongomapper]) }

before :each do
define_classes
MMPig.delete_all
MMPen.delete_all
end

it "reports 0 totals" do
get "/mm_no_pigs"
log_output.string.should include("MongoMapper Instantiation Breakdown: Total: 0")
end

it "reports totals first even if it's a tie" do
get "/mm_two_pigs"
log_output.string.should include("MongoMapper Instantiation Breakdown: Total: 2 | MMPig: 2")
end

it "reports pigs and pens instantiated" do
get "/mm_two_pigs_in_a_pen"
log_output.string.should include("MongoMapper Instantiation Breakdown: Total: 3 | MMPig: 2 | MMPen: 1")
end

it "logs memory usage" do
Oink::Instrumentation::MemorySnapshot.should_receive(:memory).and_return(4092)
get "/mm_two_pigs_in_a_pen"
log_output.string.should include("Memory usage: 4092 | PID: #{$$}")
end
end
end
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

config.before :suite do
setup_memory_database

Pig = Class.new(ActiveRecord::Base)
Pen = Class.new(ActiveRecord::Base)
Pig.belongs_to :pen
end

end