mongo_profiler 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +22 -1
- data/.travis.yml +13 -0
- data/Gemfile.lock +32 -20
- data/README.md +53 -64
- data/lib/mongo_profiler.rb +9 -95
- data/lib/mongo_profiler/caller.rb +4 -6
- data/lib/mongo_profiler/extensions/moped.rb +17 -0
- data/lib/mongo_profiler/models/profile.rb +107 -0
- data/lib/mongo_profiler/models/profile_group.rb +39 -0
- data/lib/mongo_profiler/util.rb +21 -0
- data/lib/mongo_profiler/version.rb +1 -1
- data/lib/mongo_profiler/web.rb +8 -55
- data/lib/mongo_profiler/web_helpers.rb +0 -56
- data/mongo_profiler.gemspec +3 -4
- data/spec/mongo_profiler/caller_spec.rb +5 -50
- data/spec/mongo_profiler/models/profile_spec.rb +60 -0
- data/spec/mongo_profiler/util_spec.rb +49 -0
- data/spec/mongo_profiler/web_helpers_spec.rb +0 -44
- data/spec/mongo_profiler/web_spec.rb +0 -30
- data/spec/mongo_profiler_spec.rb +0 -109
- data/spec/mongoid.yml +20 -0
- data/spec/spec_helper.rb +13 -12
- data/web/views/index.erb +29 -25
- data/web/views/layout.erb +6 -10
- data/web/views/show.erb +74 -74
- metadata +29 -32
- data/config.ru +0 -13
- data/lib/mongo_profiler/extensions/mongo/cursor.rb +0 -38
- data/lib/mongo_profiler/payload.rb +0 -33
- data/lib/mongo_profiler/profiler.rb +0 -4
- data/lib/mongo_profiler/stats.rb +0 -25
- data/spec/mongo_profiler/extensions/mongo/cursor_spec.rb +0 -42
- data/spec/mongo_profiler/payload_spec.rb +0 -111
- data/spec/mongo_profiler/profiler_spec.rb +0 -8
- data/spec/mongo_profiler/stats_spec.rb +0 -29
- data/web/views/group_id.erb +0 -53
@@ -0,0 +1,17 @@
|
|
1
|
+
Moped::Node.class_eval do
|
2
|
+
alias_method :original_query, :query
|
3
|
+
|
4
|
+
def query(database, collection, selector, options = {})
|
5
|
+
started_at = Time.now
|
6
|
+
|
7
|
+
result = original_query(database, collection, selector, options)
|
8
|
+
|
9
|
+
begin
|
10
|
+
MongoProfiler::Profile.register(started_at, database, collection, selector, options)
|
11
|
+
rescue => e
|
12
|
+
p "MongoProfiler: #{e.message}"
|
13
|
+
end
|
14
|
+
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module MongoProfiler
|
4
|
+
class Profile
|
5
|
+
include Mongoid::Document
|
6
|
+
include Mongoid::Timestamps
|
7
|
+
|
8
|
+
field :total_time, type: Float
|
9
|
+
field :command_database, type: String
|
10
|
+
field :command_collection, type: String
|
11
|
+
field :command, type: String
|
12
|
+
field :explain, type: String
|
13
|
+
field :file, type: String
|
14
|
+
field :line, type: Integer
|
15
|
+
field :method, type: String
|
16
|
+
field :profile_md5, type: String
|
17
|
+
|
18
|
+
belongs_to :profile_group
|
19
|
+
|
20
|
+
index group_id: 1, profile_md5: 1
|
21
|
+
|
22
|
+
def score
|
23
|
+
explain = JSON.parse(self.explain)
|
24
|
+
|
25
|
+
n = explain['n']
|
26
|
+
ns_scanned = explain['nscanned']
|
27
|
+
cursor = explain['cursor']
|
28
|
+
scan_and_order = explain['scanAndOrder']
|
29
|
+
|
30
|
+
case
|
31
|
+
when cursor == 'BasicCursor'
|
32
|
+
:no_index
|
33
|
+
when n == 0
|
34
|
+
:no_docs_found
|
35
|
+
when ns_scanned == n
|
36
|
+
:perfect
|
37
|
+
when ns_scanned > n
|
38
|
+
:scanned_more_than_returned
|
39
|
+
when scan_and_order
|
40
|
+
:had_to_order
|
41
|
+
end
|
42
|
+
rescue => e
|
43
|
+
e.message
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def register(started_at, database, collection, selector, options = {})
|
48
|
+
return if collection =~ /mongo_profiler/ || collection =~ /system/
|
49
|
+
return if selector['$explain']
|
50
|
+
|
51
|
+
_caller = MongoProfiler::Caller.new(caller)
|
52
|
+
|
53
|
+
group = ProfileGroup.find_or_create_by(name: MongoProfiler.current_group_name)
|
54
|
+
|
55
|
+
group.touch
|
56
|
+
|
57
|
+
profile_md5 = generate_profile_md5(database, collection, selector, _caller)
|
58
|
+
|
59
|
+
return if Profile.where(profile_md5: profile_md5, profile_group_id: group.id).any?
|
60
|
+
|
61
|
+
result = {}
|
62
|
+
result[:profile_md5] = profile_md5
|
63
|
+
result[:profile_group_id] = group.id
|
64
|
+
|
65
|
+
result[:total_time] = elapsed(started_at)
|
66
|
+
result[:command_database] = database
|
67
|
+
result[:command_collection] = collection
|
68
|
+
result[:command] = JSON.dump(selector)
|
69
|
+
result[:file] = _caller.file
|
70
|
+
result[:line] = _caller.line
|
71
|
+
result[:method] = _caller.method
|
72
|
+
|
73
|
+
# TODO do it in background
|
74
|
+
result[:explain] = JSON.dump(generate_explain(collection, selector))
|
75
|
+
|
76
|
+
self.create(result)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def generate_explain(collection, selector)
|
82
|
+
query = if selector.has_key?('$query')
|
83
|
+
selector['$query']
|
84
|
+
else
|
85
|
+
selector
|
86
|
+
end
|
87
|
+
self.collection.database[collection].find(query).explain
|
88
|
+
end
|
89
|
+
|
90
|
+
def generate_profile_md5(database, collection, selector, _caller)
|
91
|
+
profile_key = [
|
92
|
+
database,
|
93
|
+
collection,
|
94
|
+
MongoProfiler::Util.deep_keys(selector).join,
|
95
|
+
_caller.file,
|
96
|
+
_caller.line.to_s
|
97
|
+
].join
|
98
|
+
|
99
|
+
Digest::MD5.hexdigest(profile_key)
|
100
|
+
end
|
101
|
+
|
102
|
+
def elapsed(started_at)
|
103
|
+
(Time.now - started_at) * 1000
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MongoProfiler
|
2
|
+
class ProfileGroup
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
|
6
|
+
field :name, type: String
|
7
|
+
|
8
|
+
has_many :profiles, dependent: :delete
|
9
|
+
|
10
|
+
index name: 1
|
11
|
+
|
12
|
+
def total_time
|
13
|
+
profiles.sum(&:total_time)
|
14
|
+
end
|
15
|
+
|
16
|
+
def avg_time
|
17
|
+
return 0 if (count = profiles.count) == 0
|
18
|
+
total_time / count
|
19
|
+
end
|
20
|
+
|
21
|
+
def min_time
|
22
|
+
profiles.collect(&:total_time).min
|
23
|
+
end
|
24
|
+
|
25
|
+
def max_time
|
26
|
+
profiles.collect(&:total_time).max
|
27
|
+
end
|
28
|
+
|
29
|
+
def filter_by_score(score)
|
30
|
+
profiles.select do |p|
|
31
|
+
p.score == score
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def count_by_score(score)
|
36
|
+
filter_by_score(score).size
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MongoProfiler
|
2
|
+
class Util
|
3
|
+
class << self
|
4
|
+
def deep_keys(hash)
|
5
|
+
return [] unless hash.is_a? Hash
|
6
|
+
|
7
|
+
hash.inject([]) do |keys, (key, value)|
|
8
|
+
keys << key
|
9
|
+
case value
|
10
|
+
when Hash
|
11
|
+
keys.concat deep_keys(value)
|
12
|
+
when Array
|
13
|
+
value.each { |vvalue| keys.concat deep_keys(vvalue) }
|
14
|
+
end
|
15
|
+
|
16
|
+
keys
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/mongo_profiler/web.rb
CHANGED
@@ -17,69 +17,22 @@ module MongoProfiler
|
|
17
17
|
|
18
18
|
|
19
19
|
get '/' do
|
20
|
-
@
|
21
|
-
group({ key: %i[method file application_name group_id],
|
22
|
-
reduce: 'function(curr, result) { result.total_time += curr.total_time; result.total += 1 }',
|
23
|
-
initial: { total: 0, total_time: 0 } })
|
20
|
+
@groups = MongoProfiler::ProfileGroup.order(:updated_at.desc)
|
24
21
|
|
25
|
-
|
26
|
-
@grouped_profiles = @profiles.group_by { |profile| profile['group_id'] }.to_a.reverse
|
27
|
-
|
28
|
-
erb :index
|
22
|
+
erb :index
|
29
23
|
end
|
30
24
|
|
31
|
-
|
32
|
-
MongoProfiler.
|
25
|
+
get '/groups/:id' do
|
26
|
+
@group = MongoProfiler::ProfileGroup.find(params[:id])
|
33
27
|
|
34
|
-
|
28
|
+
erb :show
|
35
29
|
end
|
36
30
|
|
37
|
-
|
38
|
-
|
31
|
+
post '/clear' do
|
32
|
+
MongoProfiler::ProfileGroup.delete_all
|
33
|
+
MongoProfiler::Profile.delete_all
|
39
34
|
|
40
35
|
redirect to('/')
|
41
36
|
end
|
42
|
-
|
43
|
-
get '/profiler/groups/:group_id' do
|
44
|
-
@group_id = params[:group_id]
|
45
|
-
@profiles = MongoProfiler.collection.find(group_id: @group_id).to_a
|
46
|
-
|
47
|
-
@sample_profile = @profiles.first
|
48
|
-
|
49
|
-
@profiles_count = @profiles.count
|
50
|
-
@profiles_total_time = @profiles.reduce(0) { |sum, p| sum + p['total_time'] }
|
51
|
-
|
52
|
-
@grouped_profiles = @profiles.group_by { |profile| profile['method'] }
|
53
|
-
|
54
|
-
erb :group_id
|
55
|
-
end
|
56
|
-
|
57
|
-
get '/profiler/:_id' do
|
58
|
-
@profile_id = BSON::ObjectId(params[:_id])
|
59
|
-
@profile = MongoProfiler.collection.find_one(_id: @profile_id)
|
60
|
-
@instrument_payload = JSON.parse(@profile['instrument_payload'])
|
61
|
-
|
62
|
-
@collection_name = @instrument_payload['collection']
|
63
|
-
@selector = @instrument_payload['selector']
|
64
|
-
|
65
|
-
begin
|
66
|
-
@selector.each_pair do |key, value|
|
67
|
-
if value.is_a? Hash
|
68
|
-
if value.first[0] == '$oid'
|
69
|
-
@selector[key] = BSON::ObjectId(value.first[1])
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
@explain = MongoProfiler.database[@collection_name].find(@selector).explain
|
74
|
-
rescue => e
|
75
|
-
@explain = { error: "Unable to generate explain: #{e.message}" }
|
76
|
-
end
|
77
|
-
|
78
|
-
# http://docs.mongodb.org/manual/core/capped-collections/
|
79
|
-
# You can update documents in a collection after inserting them. However, these updates cannot cause the documents to grow. If the update operation causes the document to grow beyond their original size, the update operation will fail.
|
80
|
-
# If you plan to update documents in a capped collection, create an index so that these update operations do not require a table scan.
|
81
|
-
# MongoRubyProfiler.collection.update({ _id: BSON::ObjectId(params[:_id]) }, '$set' => { explain: explain } )
|
82
|
-
erb :show
|
83
|
-
end
|
84
37
|
end
|
85
38
|
end
|
@@ -5,61 +5,5 @@ module MongoProfiler
|
|
5
5
|
def root_path
|
6
6
|
"#{env['SCRIPT_NAME']}/"
|
7
7
|
end
|
8
|
-
|
9
|
-
def graphite_graph_timers_url(profile, from, size, title)
|
10
|
-
file = profile['file']
|
11
|
-
method = profile['method']
|
12
|
-
application_name = profile['application_name']
|
13
|
-
|
14
|
-
URI.escape(["#{MongoProfiler.graphite_url}/render?",
|
15
|
-
"from=#{from}&",
|
16
|
-
'until=now&width=400&height=250&',
|
17
|
-
"target=#{graphite_timers_target(application_name, file, method, size)}",
|
18
|
-
"&title=#{title}"].join)
|
19
|
-
end
|
20
|
-
|
21
|
-
def graphite_graph_count_url(profile, from, size, title)
|
22
|
-
file = profile['file']
|
23
|
-
method = profile['method']
|
24
|
-
application_name = profile['application_name']
|
25
|
-
|
26
|
-
URI.escape(["#{MongoProfiler.graphite_url}/render?",
|
27
|
-
"from=#{from}&",
|
28
|
-
'until=now&width=400&height=250&',
|
29
|
-
"target=#{graphite_count_target(application_name, file, method, size)}",
|
30
|
-
"&title=#{title}"].join)
|
31
|
-
end
|
32
|
-
|
33
|
-
def print_backtrace_entry(entry)
|
34
|
-
if entry.include?('gem/ruby') || entry.include?('rubies/ruby') || entry.include?('bundle/ruby')
|
35
|
-
entry
|
36
|
-
else
|
37
|
-
%{<span class="btn-info">#{entry}</span>}
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def graphite_timers_target(application_name, file, method, size)
|
44
|
-
file = file.split('/').last
|
45
|
-
file_key = sanitaze_stat_key(file)
|
46
|
-
method_key = sanitaze_stat_key(method)
|
47
|
-
|
48
|
-
"alias(summarize(stats.timers.#{MongoProfiler.stats_prefix}mongo_profiler.#{application_name}.#{file_key}.#{method_key}.mean, '#{size}', 'mean'), '#{file}##{method}')"
|
49
|
-
end
|
50
|
-
|
51
|
-
def graphite_count_target(application_name, file, method, size)
|
52
|
-
file = file.split('/').last
|
53
|
-
file_key = sanitaze_stat_key(file)
|
54
|
-
method_key = sanitaze_stat_key(method)
|
55
|
-
|
56
|
-
binding.pry
|
57
|
-
|
58
|
-
"alias(summarize(stats_counts.#{MongoProfiler.stats_prefix}mongo_profiler.#{application_name}.#{file_key}.#{method_key}, '#{size}', 'sum'), '#{file}##{method}')"
|
59
|
-
end
|
60
|
-
|
61
|
-
def sanitaze_stat_key(key)
|
62
|
-
key.gsub(/\W/, '_')
|
63
|
-
end
|
64
8
|
end
|
65
9
|
end
|
data/mongo_profiler.gemspec
CHANGED
@@ -8,8 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = MongoProfiler::VERSION
|
9
9
|
spec.authors = ["Pablo Cantero"]
|
10
10
|
spec.email = ["pablo@pablocantero.com"]
|
11
|
-
spec.summary
|
12
|
-
spec.description = %q{A Ruby profiling tool for MongoDB}
|
11
|
+
spec.summary = spec.description = %q{Ruby profiling tool for MongoDB}
|
13
12
|
spec.homepage = "https://github.com/phstc/mongo_profiler"
|
14
13
|
spec.license = "MIT"
|
15
14
|
|
@@ -21,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
21
20
|
spec.add_dependency "activesupport"
|
22
21
|
|
23
22
|
spec.add_development_dependency "rake"
|
24
|
-
spec.add_development_dependency "
|
25
|
-
spec.add_development_dependency "bson_ext"
|
23
|
+
spec.add_development_dependency "mongoid"
|
26
24
|
spec.add_development_dependency "rspec", "~> 2.14.1"
|
27
25
|
spec.add_development_dependency "pry-byebug"
|
28
26
|
spec.add_development_dependency "sinatra"
|
29
27
|
spec.add_development_dependency "shotgun"
|
30
28
|
spec.add_development_dependency "rack-test"
|
29
|
+
spec.add_development_dependency "database_cleaner"
|
31
30
|
end
|
@@ -6,78 +6,33 @@ module MongoProfiler
|
|
6
6
|
|
7
7
|
let(:_caller) {
|
8
8
|
[
|
9
|
-
"/Users/pablo/workspace/project/
|
9
|
+
"/Users/pablo/workspace/project/test.rb:7:in `new'",
|
10
10
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
11
11
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `fetch'",
|
12
12
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block in let'"
|
13
13
|
]
|
14
14
|
}
|
15
15
|
|
16
|
-
its(:file) { should end_with('project/
|
16
|
+
its(:file) { should end_with('project/test.rb') }
|
17
17
|
its(:line) { should eq 7 }
|
18
18
|
its(:method) { should eq 'new' }
|
19
19
|
its(:_caller) { should eq _caller }
|
20
20
|
|
21
|
-
context 'when
|
21
|
+
context 'when backtrace starts with bundle or gem' do
|
22
22
|
let(:_caller) {
|
23
23
|
[
|
24
24
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
25
25
|
"/Users/pablo/bundle/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
26
|
-
"/Users/pablo/workspace/project/
|
26
|
+
"/Users/pablo/workspace/project/test.rb:7:in `new'",
|
27
27
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `fetch'",
|
28
28
|
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block in let'"
|
29
29
|
]
|
30
30
|
}
|
31
31
|
|
32
|
-
its(:file) { should end_with('project/
|
32
|
+
its(:file) { should end_with('project/test.rb') }
|
33
33
|
its(:line) { should eq 7 }
|
34
34
|
its(:method) { should eq 'new' }
|
35
35
|
its(:_caller) { should eq _caller }
|
36
36
|
end
|
37
|
-
|
38
|
-
describe '#mongo_profiler_caller' do
|
39
|
-
|
40
|
-
context 'when mongo_profiler' do
|
41
|
-
let(:_caller) {
|
42
|
-
[
|
43
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
44
|
-
"/Users/pablo/bundle/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
45
|
-
"/Users/pablo/workspace/project/spec/mongo_profiler.rb:7:in `new'",
|
46
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `fetch'",
|
47
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block in let'"
|
48
|
-
]
|
49
|
-
}
|
50
|
-
|
51
|
-
its(:mongo_profiler_caller?) { should be_true }
|
52
|
-
|
53
|
-
context 'when _spec' do
|
54
|
-
let(:_caller) {
|
55
|
-
[
|
56
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
57
|
-
"/Users/pablo/bundle/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
58
|
-
"/Users/pablo/workspace/project/spec/mongo_profiler_spec.rb:7:in `new'",
|
59
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `fetch'",
|
60
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block in let'"
|
61
|
-
]
|
62
|
-
}
|
63
|
-
|
64
|
-
its(:mongo_profiler_caller?) { should be_false }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context 'when external' do
|
69
|
-
let(:_caller) {
|
70
|
-
[
|
71
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
72
|
-
"/Users/pablo/bundle/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block (2 levels) in let'",
|
73
|
-
"/Users/pablo/workspace/project/file.rb:7:in `new'",
|
74
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `fetch'",
|
75
|
-
"/Users/pablo/.gem/ruby/2.0.0/gems/rspec-core-2.14.4/lib/rspec/core/memoized_helpers.rb:199:in `block in let'"
|
76
|
-
]
|
77
|
-
}
|
78
|
-
|
79
|
-
its(:mongo_profiler_caller?) { should be_false }
|
80
|
-
end
|
81
|
-
end
|
82
37
|
end
|
83
38
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module MongoProfiler
|
4
|
+
describe Caller do
|
5
|
+
it 'creates a profile' do
|
6
|
+
test = TestModel.create(name: 'Pablo')
|
7
|
+
|
8
|
+
expect(TestModel.where(name: 'Pablo').first.name).to eq 'Pablo'
|
9
|
+
|
10
|
+
expect(MongoProfiler::ProfileGroup.count).to eq 1
|
11
|
+
|
12
|
+
group = MongoProfiler::ProfileGroup.first
|
13
|
+
expect(group.name).to eq 'Undefined group name'
|
14
|
+
|
15
|
+
expect(MongoProfiler::Profile.count).to eq 1
|
16
|
+
|
17
|
+
profile = MongoProfiler::Profile.first
|
18
|
+
|
19
|
+
expect(profile.attributes).to include('profile_group_id' => group.id,
|
20
|
+
'file' => __FILE__,
|
21
|
+
'command_database' => 'mongo_profiler_test',
|
22
|
+
'command_collection' => 'test_models')
|
23
|
+
|
24
|
+
expect(JSON.parse(profile.command)).to eq('$query' => { 'name' => 'Pablo' }, '$orderby' => { '_id' => 1 })
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does not duplicate profiles' do
|
28
|
+
test = TestModel.create
|
29
|
+
|
30
|
+
# To guarantee the same line number
|
31
|
+
TestModel.where(name: 'Pablo').first || TestModel.where(name: 'Pablo').first
|
32
|
+
|
33
|
+
expect(MongoProfiler::ProfileGroup.count).to eq 1
|
34
|
+
expect(MongoProfiler::Profile.count).to eq 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'creates a new profile if the query keys change' do
|
38
|
+
test = TestModel.create
|
39
|
+
|
40
|
+
TestModel.where(name: 'Pablo').first
|
41
|
+
TestModel.where(last_name: 'Cantero').first
|
42
|
+
|
43
|
+
expect(MongoProfiler::ProfileGroup.count).to eq 1
|
44
|
+
expect(MongoProfiler::Profile.count).to eq 2
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'uses supplied group name' do
|
48
|
+
MongoProfiler.current_group_name = 'Test'
|
49
|
+
|
50
|
+
test = TestModel.create(name: 'Pablo')
|
51
|
+
|
52
|
+
TestModel.where(name: 'Pablo').first
|
53
|
+
|
54
|
+
expect(MongoProfiler::ProfileGroup.count).to eq 1
|
55
|
+
|
56
|
+
group = MongoProfiler::ProfileGroup.first
|
57
|
+
expect(group.name).to eq 'Test'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|