mongo_profiler 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a47fc67c8b76da256d794a635b3e719f783664aa
4
- data.tar.gz: 19b951a31adeebadf0e38de08b2768bac0111e58
3
+ metadata.gz: 04925894971f5f727c372d5dd4ec179e79dcc246
4
+ data.tar.gz: 10b9bee77caae6de62421c7bb8c79750f22a1f41
5
5
  SHA512:
6
- metadata.gz: 8835e0823b0f5b7b008dc714178a3e4412bcc36f6d00eb2eb4b49f1b71fa70f143bc2f261e88bb8b8a9e66cfc5db0514d7c752f6d5407daa5064d1f5080a99f3
7
- data.tar.gz: 4889bf3ffe0465f163b0a13d977747956d2df0c61f3ece6ff38cabdcedef770195768350f7140147209e7c4eed2c262b9a672f3ec27a3e112c8a1e7fbc51a260
6
+ metadata.gz: 12eeac08756764921bda0217f9133908dea3eaf9517adb6fee25007a44d3e26fee101491ea754f8555ed10632eafed30b49c766b2538042137a5543d70959ff0
7
+ data.tar.gz: 996ca8d034bc9469b62b0eac7d6c407d6820b0afed3a36b8bb0dab5114cd17dcfe58bd5a8a0a6ef1c0ab73b653e231f7011f345c71720849373b08f28112c577
data/.gitignore CHANGED
@@ -1 +1,22 @@
1
- web/assets/bower_components
1
+ *#*
2
+ *.bundle
3
+ *.class
4
+ *.gem
5
+ *.log
6
+ *.o
7
+ *.pid
8
+ *.so
9
+ *.swp
10
+ *~
11
+ .DS_Store
12
+ .idea/*
13
+ .yardoc
14
+ coverage
15
+ data
16
+ doc
17
+ Gemfile.lock
18
+ .ruby-gemset
19
+ .ruby-version
20
+ gem-private_key.pem
21
+ nbproject
22
+ tmp
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+
5
+ notifications:
6
+ email:
7
+ on_success: change
8
+ on_failure: always
9
+
10
+ script: bundle exec rspec spec
11
+
12
+ services:
13
+ - mongodb
@@ -1,35 +1,47 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongo_profiler (0.0.1)
4
+ mongo_profiler (0.0.2)
5
5
  activesupport
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (4.0.2)
11
- i18n (~> 0.6, >= 0.6.4)
12
- minitest (~> 4.2)
13
- multi_json (~> 1.3)
10
+ activemodel (4.1.5)
11
+ activesupport (= 4.1.5)
12
+ builder (~> 3.1)
13
+ activesupport (4.1.5)
14
+ i18n (~> 0.6, >= 0.6.9)
15
+ json (~> 1.7, >= 1.7.7)
16
+ minitest (~> 5.1)
14
17
  thread_safe (~> 0.1)
15
- tzinfo (~> 0.3.37)
16
- atomic (1.1.14)
17
- bson (1.9.2)
18
- bson_ext (1.9.2)
19
- bson (~> 1.9.2)
18
+ tzinfo (~> 1.1)
19
+ bson (2.3.0)
20
+ builder (3.2.2)
20
21
  byebug (2.5.0)
21
22
  columnize (~> 0.3.6)
22
23
  debugger-linecache (~> 1.2.0)
23
24
  coderay (1.1.0)
24
25
  columnize (0.3.6)
26
+ connection_pool (2.0.0)
27
+ database_cleaner (1.3.0)
25
28
  debugger-linecache (1.2.0)
26
29
  diff-lcs (1.2.5)
27
- i18n (0.6.9)
30
+ i18n (0.6.11)
31
+ json (1.8.1)
28
32
  method_source (0.8.2)
29
- minitest (4.7.5)
30
- mongo (1.9.2)
31
- bson (~> 1.9.2)
32
- multi_json (1.8.4)
33
+ minitest (5.4.1)
34
+ mongoid (4.0.0)
35
+ activemodel (~> 4.0)
36
+ moped (~> 2.0.0)
37
+ origin (~> 2.1)
38
+ tzinfo (>= 0.3.37)
39
+ moped (2.0.0)
40
+ bson (~> 2.2)
41
+ connection_pool (~> 2.0)
42
+ optionable (~> 0.2.0)
43
+ optionable (0.2.0)
44
+ origin (2.1.1)
33
45
  pry (0.9.12.4)
34
46
  coderay (~> 1.0)
35
47
  method_source (~> 0.8)
@@ -58,18 +70,18 @@ GEM
58
70
  rack-protection (~> 1.4)
59
71
  tilt (~> 1.3, >= 1.3.4)
60
72
  slop (3.4.7)
61
- thread_safe (0.1.3)
62
- atomic
73
+ thread_safe (0.3.4)
63
74
  tilt (1.4.1)
64
- tzinfo (0.3.38)
75
+ tzinfo (1.2.2)
76
+ thread_safe (~> 0.1)
65
77
 
66
78
  PLATFORMS
67
79
  ruby
68
80
 
69
81
  DEPENDENCIES
70
- bson_ext
71
- mongo (= 1.9.2)
82
+ database_cleaner
72
83
  mongo_profiler!
84
+ mongoid
73
85
  pry-byebug
74
86
  rack-test
75
87
  rake
data/README.md CHANGED
@@ -1,112 +1,101 @@
1
1
  # Mongo Profiler
2
2
 
3
- Database profiling tools are awesome and always useful. I love [Mongo Profiling](http://docs.mongodb.org/manual/tutorial/manage-the-database-profiler/). But unfortunately these tools don't match queries and code they are profiling, so sometimes isn't easy to match where the slow queries are performed.
3
+ [![Build Status](https://travis-ci.org/phstc/mongo_profiler.svg)](https://travis-ci.org/phstc/mongo_profiler)
4
4
 
5
- The Mongo Profiler is a <del>refinement</del> patch in the [mongo-ruby-driver](https://github.com/mongodb/mongo-ruby-driver) to log all execute queries and their respective callers in a [capped collections](http://docs.mongodb.org/manual/core/capped-collections/).
5
+ **Mongo profiling tool which matches queries with code**
6
6
 
7
- It isn't competitor for the Mongo's built-in profiling, it is just a complementary tool to help us to profile our queries.
7
+ Database profiling tools are awesome and always useful. I love [Mongo profiling](http://docs.mongodb.org/manual/tutorial/manage-the-database-profiler/). But unfortunately these tools don't match the queries with the source code they are profiling, making hard to find where the slow queries are executed.
8
8
 
9
- An interesting feature in the Mongo Profiler is that we can group queries by "life cycles". For example, in a web application it can be the `request_id`, so you will be able to see how many queries, how long did they take, the explain plans etc for a specific request.
9
+ The Mongo Profiler is a <del>refinement</del> patch in the [moped driver](https://github.com/mongoid/moped) to log all executed queries and their respective callers ([Ruby backtrace](http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-caller)).
10
10
 
11
- First time I used it, I was shocked to see some pages doing lot of duplicated queries, even though some were really fast, they were unnecessary, I could get rid of some of them just by "memorising" some documents.
11
+ It isn't replacement for the Mongo's built-in profiling, it is just a complementary tool to profile the queries with their respective source code.
12
+
13
+ An interesting feature in the Mongo Profiler is that we can group queries by "life cycles". For example, in a web application it can be the `request.uuid` or the `request.url`, so you will be able to see how many queries, how long did they take, the explain plans etc for each request or url.
14
+
15
+ ## Sample App
16
+
17
+ You can see how it works through the [Sample Dashboard](https://mongo-profiler-sample-app.herokuapp.com/mongo_profiler) and [Sample App](https://mongo-profiler-sample-app.herokuapp.com) ([source code](https://github.com/phstc/mongo_profiler_sample_app)).
12
18
 
13
19
  ## Installation
14
20
 
15
21
  Add this line to your application's Gemfile:
16
22
 
17
- gem 'mongo_profiler'
23
+ ```ruby
24
+ gem 'mongo_profiler'
25
+ ```
18
26
 
19
27
  And then execute:
20
28
 
21
- $ bundle
29
+ ```bash
30
+ $ bundle
31
+ ```
22
32
 
23
33
  Or install it yourself as:
24
34
 
25
- $ gem install mongo_profiler
26
-
27
- ## Usage
35
+ ```bash
36
+ $ gem install mongo_profiler
37
+ ```
28
38
 
29
- ### Rails application
39
+ To run the Dashboard you will need also to install [sinatra](https://github.com/sinatra/sinatra).
30
40
 
31
41
  ```ruby
32
- # config/initializers/mongo_profiler_setup.rb
33
-
34
- require 'mongo_profiler'
35
- require 'mongo_profiler/extensions/mongo/cursor'
42
+ gem 'sinatra', require: nil
43
+ ```
36
44
 
37
- MongoProfiler.connect('localhost', 27017, 'my_database')
45
+ ## Usage
38
46
 
39
- MongoProfiler.application_name = 'my_application'
47
+ ### Rails application
40
48
 
41
- # To enable Statsd
42
- # MongoProfiler.stats_client = MyStatsdClientInstance
49
+ ### Gemfile
43
50
 
44
- # To show graphite graphs
45
- # MongoProfiler.graphite_url = 'http://my_graphite'
46
51
  ```
52
+ gem 'mongo_profiler', github: 'phstc/mongo_profiler', require: nil
53
+ gem 'sinatra', require: nil
54
+ ```
55
+
56
+ #### application_controller.rb
47
57
 
48
58
  ```ruby
49
59
  # app/controllers/application_controller.rb
50
60
 
51
61
  class ApplicationController < ActionController::Base
52
- before_filter :mongo_profiler_setup
62
+ before_filter :set_mongo_profile_group_name
53
63
 
54
- private
55
-
56
- def mongo_profiler_setup
57
- # aggregate queries by request
58
- MongoProfiler.group_id = "request-#{request.uuid}"
59
-
60
- # to show the request url
61
- MongoProfiler.extra_attrs[:request_url] = request.url
62
- rescue => e
63
- p "MongoProfiler: #{e.message}"
64
+ def set_mongo_profile_group_name
65
+ unless Rails.env.production?
66
+ require 'mongo_profiler'
67
+ MongoProfiler.current_group_name = request.url
68
+ end
64
69
  end
65
70
  end
66
71
  ```
67
72
 
73
+ #### routes.rb
74
+
68
75
  ```ruby
69
76
  # config/routes.rb
70
77
 
71
- require 'mongo_profiler/web'
72
-
73
78
  MyApplication::Application.routes.draw do
74
- mount MongoProfiler::Web => '/mongo_profiler'
75
-
76
- # Security with Devise
77
- # authenticate :user do
78
- # mount MongoProfiler::Web => '/mongo_profiler'
79
- # end
80
- #
81
- # authenticate :user, lambda { |u| u.admin? } do
82
- # mount MongoProfiler::Web => '/mongo_profiler'
83
- # end
79
+ unless Rails.env.production?
80
+ require 'mongo_profiler'
81
+ require 'mongo_profiler/web'
82
+ mount MongoProfiler::Web => '/mongo_profiler'
83
+ # Security with Devise
84
+ # authenticate :user do
85
+ # mount MongoProfiler::Web => '/mongo_profiler'
86
+ # end
87
+ #
88
+ # authenticate :user, lambda { |u| u.admin? } do
89
+ # mount MongoProfiler::Web => '/mongo_profiler'
90
+ # end
91
+ end
84
92
  end
85
93
  ```
86
94
 
87
- ## Screenshots
88
-
89
- ### Dashboard index
90
-
91
- ![Dashboard Index](https://raw.github.com/phstc/mongo_profiler/master/assets/mongo_profiler_dashboard_index.png)
92
-
93
- ### Queries Group Index
94
-
95
- ![Queries Group Index](https://raw.github.com/phstc/mongo_profiler/master/assets/mongo_profiler_group_details.png)
96
-
97
- ### Query details
98
-
99
- ![Query Details](https://raw.github.com/phstc/mongo_profiler/master/assets/mongo_profiler_query_details.png)
100
-
101
- ### Query details (backtrace)
102
-
103
- ![Query Details Backtrace](https://raw.github.com/phstc/mongo_profiler/master/assets/mongo_profiler_query_details_backtrace.png)
104
-
105
-
106
95
  ## Contributing
107
96
 
108
97
  1. Fork it ( http://github.com/phstc/mongo_profiler/fork )
109
98
  2. Create your feature branch (`git checkout -b my-new-feature`)
110
99
  3. Commit your changes (`git commit -am 'Add some feature'`)
111
100
  4. Push to the branch (`git push origin my-new-feature`)
112
- 5. Create new Pull Request
101
+ 5. Create new Pull Request
@@ -1,108 +1,22 @@
1
- require 'mongo'
2
1
  require 'json'
2
+ require 'mongoid'
3
3
  require 'active_support/core_ext/hash/indifferent_access'
4
4
 
5
5
  require 'mongo_profiler/version'
6
- require 'mongo_profiler/profiler'
7
6
  require 'mongo_profiler/caller'
8
- require 'mongo_profiler/payload'
9
- require 'mongo_profiler/stats'
7
+ require 'mongo_profiler/util'
8
+ require 'mongo_profiler/extensions/moped'
9
+ require 'mongo_profiler/models/profile'
10
+ require 'mongo_profiler/models/profile_group'
10
11
 
11
12
  module MongoProfiler
12
- COLLECTION_CONFIG_NAME = 'mongo_profiler_config'
13
- COLLECTION_PROFILER_NAME = 'mongo_profiler'
14
-
15
13
  class << self
16
- attr_accessor :extra_attrs,
17
- :group_id,
18
- :application_name,
19
- :stats_client,
20
- :stats_prefix,
21
- :graphite_url
22
-
23
- attr_reader :database
24
-
25
- def log(document)
26
- collection.insert(document.merge(application_name: MongoProfiler.application_name,
27
- group_id: MongoProfiler.group_id))
28
- end
29
-
30
- def should_skip?(payload, _caller)
31
- Payload.new(payload).system_any? || _caller.mongo_profiler_caller?
32
- end
33
-
34
- def disable!
35
- # maybe we can refactor to check if the collections exist before trying to create them.
36
- # we must make sure the collections are in place before enabled/disable otherwise mongo will create a normal collection,
37
- # not a capped one, breaking the disable & enable functionality
38
- create_collections
39
-
40
- collection_config.insert(enabled: false)
14
+ def current_group_name=(group_name)
15
+ Thread.current['mongo_profiler_group_name'] = group_name
41
16
  end
42
17
 
43
- def enable!
44
- # check `disable!` comment
45
- create_collections
46
-
47
- collection_config.insert(enabled: true)
48
- end
49
-
50
- def enabled?
51
- !!collection_config.find.first.to_h['enabled']
52
- end
53
-
54
- def disabled?
55
- !enabled?
56
- end
57
-
58
- def extra_attrs
59
- @extra_attrs ||= {}
60
- end
61
-
62
- def group_id
63
- # The group_id is used to determine the life cycle where the queries occurred.
64
- # For web applications a life cycle can be a request.
65
- # So people can filter all Mongo Queries per request based on request#url and/or request#uuid.
66
- @group_id ||= { process_pid: Process.pid,
67
- thread_object_id: Thread.current.object_id }.to_a.join('-')
68
- end
69
-
70
- def stats_client=(stats_client)
71
- @stats_client = MongoProfiler::Stats.new(stats_client)
72
- end
73
-
74
- def create_collections
75
- # http://docs.mongodb.org/manual/core/capped-collections/
76
- # 1_048_576 - 1MB - allows only one document (max: 1)
77
- @database.create_collection(COLLECTION_CONFIG_NAME, capped: true, size: 1_048_576, max: 1)
78
-
79
- # 4_001_792 - 3.82MB - same size as db.system.profile.stats()
80
- @database.create_collection(COLLECTION_PROFILER_NAME, capped: true, size: 4_001_792, max: 9223372036854775807)
81
- end
82
-
83
- def collection
84
- @collection ||= @database[COLLECTION_PROFILER_NAME]
85
- end
86
-
87
- def collection_config
88
- @collection_config ||= @database[COLLECTION_CONFIG_NAME]
89
- end
90
-
91
- def connected?
92
- !!(@connection && @database)
93
- end
94
-
95
- def connect(host = 'localhost', port = 27017, db = nil, user = nil, pass = nil, options = {})
96
- @connection, @database = nil
97
-
98
- @connection = Mongo::MongoClient.new(host, port, options)
99
- if db
100
- @database = @connection.db(db)
101
- else
102
- # default database
103
- @database = @connection.db
104
- end
105
- @database.authenticate(user, pass) if user && pass
18
+ def current_group_name
19
+ Thread.current['mongo_profiler_group_name'] || 'Undefined group name'
106
20
  end
107
21
  end
108
22
  end
@@ -3,7 +3,7 @@ module MongoProfiler
3
3
  attr_reader :file, :line, :method, :_caller
4
4
 
5
5
  def initialize(_caller)
6
- @_caller = _caller.dup
6
+ @_caller = _caller
7
7
 
8
8
  caller_head = project_callers[0].split ':'
9
9
 
@@ -13,15 +13,13 @@ module MongoProfiler
13
13
  @method = project_callers[0][/`.*'/][1..-2]
14
14
  end
15
15
 
16
- def mongo_profiler_caller?
17
- _caller.any? { |line| line.include?('mongo_profiler') && !line.include?('_spec') }
18
- end
19
-
20
16
  private
21
17
 
22
18
  def project_callers
23
19
  # skip gem/bundle entries
24
- @project_callers ||= _caller.select { |line| !line.include?('bundle/ruby') && !line.include?('gem/ruby') && !line.include?('rubies/ruby') }
20
+ @project_callers ||= _caller.reject do |entry|
21
+ entry.include?('bundle/ruby') || entry.include?('gem/ruby') || entry.include?('rubies/ruby') || entry.include?('extensions/moped.rb')
22
+ end
25
23
  end
26
24
  end
27
25
  end