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 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