query_tracer 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.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,54 @@
1
+ # QueryTracer
2
+
3
+ * https://github.com/daemon/query_tracer
4
+
5
+ ## DESCRIPTION
6
+
7
+ QueryTracer is designed to log where from queries to DB were made.
8
+
9
+ ## Origins
10
+
11
+ Original code was built for Scribd by Dmitry Shteflyuk.
12
+
13
+ ## TODO
14
+
15
+ Rewrite SQL queries adding small trace as a comment. It will show where long running queries came from.
16
+
17
+ ## Usage
18
+
19
+ Add following code to config/initializers/query_tracer.rb:
20
+
21
+ QueryTracer::Configuration.set do |tracer|
22
+ tracer.enabled = true
23
+ tracer.colorize = true
24
+ tracer.show_revision = true
25
+ tracer.multiline = true
26
+ tracer.skip_queries = [%r{FROM sqlite_master}]
27
+ end
28
+
29
+ QueryTracer::Logger.attach_to :active_record
30
+
31
+ `skip_queries` will merge one/many regexps into default expressions list (QueryTracer::Tracer::EXCLUDE_SQL) for current DB.
32
+
33
+ ## Example
34
+
35
+ Let's say we have model
36
+
37
+ class User < ActiveRecord::Base
38
+ scope :active, where(:active => true)
39
+
40
+ def self.traceme
41
+ active.to_a
42
+ end
43
+ end
44
+
45
+ Invoking `User.traceme` will produce in logs:
46
+
47
+ SQL (0.9ms) SELECT name
48
+ FROM sqlite_master
49
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
50
+
51
+ User Load (25.8ms) SELECT "users".* FROM "users" WHERE "users"."active" = 't'
52
+ ^^^^ Called from: Rev[d11816c90c2a38dcd866b115ed2ffa28d7d84e2c]
53
+ -> /Users/dm/Projects/tmp/loggertest/app/models/user.rb:5:in `traceme'
54
+ -> (irb):1:in `irb_binding'
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ begin
2
+ require "bundler"
3
+ Bundler.setup
4
+ rescue LoadError
5
+ $stderr.puts "You need to have Bundler installed to be able build this gem."
6
+ end
7
+
8
+ gemspec = eval(File.read(Dir["*.gemspec"].first))
9
+
10
+
11
+ desc "Validate the gemspec"
12
+ task :gemspec do
13
+ gemspec.validate
14
+ end
15
+
16
+ desc "Build gem locally"
17
+ task :build => :gemspec do
18
+ system "gem build #{gemspec.name}.gemspec"
19
+ FileUtils.mkdir_p "pkg"
20
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
21
+ end
22
+
23
+ desc "Install gem locally"
24
+ task :install => :build do
25
+ system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
26
+ end
27
+
28
+ desc "Clean automatically generated files"
29
+ task :clean do
30
+ FileUtils.rm_rf "pkg"
31
+ end
@@ -0,0 +1,32 @@
1
+ module QueryTracer
2
+ class Configuration
3
+
4
+ class << self
5
+
6
+ attr_accessor :show_revision, :enabled, :colorize
7
+ attr_accessor :multiline, :log_level
8
+
9
+ def set
10
+ db_adapter = ActiveRecord::Base.connection.adapter_name.capitalize
11
+ begin
12
+ QueryTracer::Tracer::EXCLUDE_SQL << QueryTracer::Db.const_get(db_adapter)::SKIP_QUERIES
13
+ QueryTracer::Tracer::EXCLUDE_SQL.flatten!
14
+ rescue
15
+ end
16
+
17
+ yield self
18
+ end
19
+
20
+ def log_level
21
+ @log_level || :debug
22
+ end
23
+
24
+ def skip_queries=(val)
25
+ QueryTracer::Tracer::EXCLUDE_SQL << val
26
+ QueryTracer::Tracer::EXCLUDE_SQL.flatten!
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ module QueryTracer
2
+ module Db
3
+ module Mysql
4
+ SKIP_QUERIES = [%r{^(SET|SHOW)}]
5
+
6
+ def execute_with_trace(sql)
7
+
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module QueryTracer
2
+ module Db
3
+ module Sqlite
4
+ SKIP_QUERIES = [%r{FROM sqlite_master}]
5
+
6
+ def execute_with_trace(sql)
7
+
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ require 'query_tracer/db/mysql'
2
+ require 'query_tracer/db/sqlite'
3
+
4
+ module QueryTracer
5
+ module Db
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_record/log_subscriber'
2
+
3
+ require 'query_tracer/configuration'
4
+ require 'query_tracer/tracer'
5
+
6
+ module QueryTracer
7
+
8
+ class Logger < ActiveSupport::LogSubscriber
9
+ # event.payload[:name]
10
+ # event.duration
11
+ # event.payload[:sql]
12
+ def sql(event)
13
+ return unless Configuration.enabled
14
+
15
+ sql = event.payload[:sql]
16
+ # Skip noisy queries
17
+ trace = Tracer.build_trace(sql)
18
+ return if trace.blank?
19
+ # We're done
20
+ if Configuration.colorize
21
+ message = "\e[34m\e[43m^^^^ Called from:\e[0m "
22
+ indent = "\e[34m\e[43m->\e[0m "
23
+ else
24
+ message = '^^^^ Called from: '
25
+ indent = " "
26
+ end
27
+ logger.send QueryTracer::Configuration.log_level.to_sym, message + trace.join("\n#{indent}")
28
+ end
29
+ end
30
+ end
31
+
32
+
@@ -0,0 +1,36 @@
1
+ module QueryTracer
2
+ module Tracer
3
+
4
+ module Revision
5
+ # Detect the current code revision and memoize it for the future.
6
+ def self.current
7
+ return nil unless QueryTracer::Configuration.show_revision
8
+
9
+ begin
10
+ # Do we have the code revision memoized?
11
+ unless defined?(@@current_code_revision)
12
+ @@current_code_revision = if File.exists?("#{Rails.root}/REVISION")
13
+ # Capistrano-deployed application, we know where to get current revision
14
+ File.read("#{Rails.root}/REVISION").chomp.strip
15
+ else
16
+ # Try to use git
17
+ rev = `git rev-parse HEAD 2>/dev/null`.chomp.strip
18
+ rev.empty? ? nil : rev
19
+ end
20
+ end
21
+ rescue
22
+ nil
23
+ end
24
+ humanized_revision
25
+ end
26
+
27
+ def self.humanized_revision
28
+ if @@current_code_revision
29
+ "Rev[#{@@current_code_revision}]"
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,50 @@
1
+ require 'query_tracer/configuration'
2
+ require 'query_tracer/tracer/revision'
3
+
4
+ module QueryTracer
5
+ module Tracer
6
+ extend self
7
+
8
+ INCLUDE_CODEPOINTS = [
9
+ %r{^#{Rails.root}/(app/presenters/.*)},
10
+ %r{^#{Rails.root}/(app/views/.*)},
11
+ %r{^#{Rails.root}/(app/controllers/.*)},
12
+ %r{^#{Rails.root}/(app/models/.*)},
13
+ %r{^#{Rails.root}/(lib/.*)},
14
+ %r{^#{Rails.root}/(spec/.*)},
15
+ %r{^#{Rails.root}/(app/.*)},
16
+ %r{^#{Rails.root}/(vendor/(?:gems|plugins)/.*)},
17
+ %r{^#{Rails.root}/(.*)},
18
+ %r{in `(irb)_binding'}
19
+ ]
20
+ # A regular expression used to skip certain code points (gems that do nothing
21
+ # but add noice to the result).
22
+ EXCLUDE_CODEPOINT = %r{^(#{Rails.root}/(?:vendor/(?:rails|gems/(?:composite_primary_keys|db-charmer)|plugins/(?:paginating_find|acts_as_sluggable))|config/initializers/mysql_adapter_extensions\.rb|tmp/gems|lib/query_tracer))|\.rvm/|/gems/}
23
+ # A regular expression to exclude certain SQL queries from processing (who cares
24
+ # where SHOW TABLES was issues from).
25
+ EXCLUDE_SQL = []
26
+
27
+ def build_trace(sql)
28
+ unless skip_query?(sql)
29
+ # Skip noisy codepoints
30
+ lines = caller.inject([]) do |filtered, line|
31
+ unless line =~ EXCLUDE_CODEPOINT
32
+ filtered << line unless INCLUDE_CODEPOINTS.select{ |expr| line =~ expr }.blank?
33
+ end
34
+ filtered
35
+ end
36
+
37
+ unless lines.blank?
38
+ lines = lines.first unless QueryTracer::Configuration.multiline
39
+ [QueryTracer::Tracer::Revision.current, lines].flatten
40
+ end
41
+
42
+ end
43
+ end
44
+
45
+ def skip_query?(sql)
46
+ !EXCLUDE_SQL.select { |expr| sql =~ expr }.blank?
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ require 'query_tracer/configuration'
2
+ require 'query_tracer/tracer'
3
+ require 'query_tracer/logger'
4
+ require 'query_tracer/db'
@@ -0,0 +1,30 @@
1
+ # coding: UTF-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "query_tracer"
5
+ s.version = "0.0.2"
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["Dmitry Shaposhnik", "Dmytro Shteflyuk"]
8
+ s.email = ["dmitry@shaposhnik.name", "kpumuk@kpumuk.info"]
9
+ s.homepage = "http://github.com/daemon/query_tracer"
10
+ s.summary = "Query tracer and logger for Rails3"
11
+ s.description = ""
12
+
13
+ s.required_rubygems_version = ">= 1.3.6"
14
+
15
+ # If you have runtime dependencies, add them here
16
+ # s.add_runtime_dependency "other", "~> 1.2"
17
+
18
+ # If you have development dependencies, add them here
19
+ # s.add_development_dependency "another", "= 0.9"
20
+
21
+ # The list of files to be contained in the gem
22
+ s.files = `git ls-files`.split("\n")
23
+ # s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
24
+ # s.extensions = `git ls-files ext/extconf.rb`.split("\n")
25
+
26
+ s.require_path = 'lib'
27
+
28
+ # For C extensions
29
+ # s.extensions = "ext/extconf.rb"
30
+ end
File without changes
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: query_tracer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Dmitry Shaposhnik
14
+ - Dmytro Shteflyuk
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-04-18 00:00:00 +03:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: ""
24
+ email:
25
+ - dmitry@shaposhnik.name
26
+ - kpumuk@kpumuk.info
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - README.markdown
37
+ - Rakefile
38
+ - lib/query_tracer.rb
39
+ - lib/query_tracer/configuration.rb
40
+ - lib/query_tracer/db.rb
41
+ - lib/query_tracer/db/mysql.rb
42
+ - lib/query_tracer/db/sqlite.rb
43
+ - lib/query_tracer/logger.rb
44
+ - lib/query_tracer/tracer.rb
45
+ - lib/query_tracer/tracer/revision.rb
46
+ - query_tracer.gemspec
47
+ - test/test_helper.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/daemon/query_tracer
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 23
72
+ segments:
73
+ - 1
74
+ - 3
75
+ - 6
76
+ version: 1.3.6
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.5.3
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Query tracer and logger for Rails3
84
+ test_files: []
85
+