sql-logging 3.0.1
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/README.rdoc +69 -0
- data/lib/sql-logging.rb +1 -0
- data/lib/sql-logging/adapters/mysql.rb +15 -0
- data/lib/sql-logging/adapters/mysql2.rb +15 -0
- data/lib/sql-logging/adapters/postgresql.rb +19 -0
- data/lib/sql-logging/adapters/sqlite.rb +13 -0
- data/lib/sql-logging/adapters/sqlite3.rb +1 -0
- data/lib/sql-logging/controller_runtime.rb +14 -0
- data/lib/sql-logging/logged_query.rb +50 -0
- data/lib/sql-logging/railtie.rb +33 -0
- data/lib/sql-logging/statistics.rb +103 -0
- data/lib/sql-logging/version.rb +3 -0
- metadata +93 -0
data/README.rdoc
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
= SQL Logging
|
2
|
+
|
3
|
+
The SQL Logging gem adds useful SQL debugging tools to ActiveRecord. The gem
|
4
|
+
is a repackaging of the old SQL Logging plug-in for Rails 2.x. It, in turn,
|
5
|
+
was based on ideas and plug-ins from Adam Doppelt's (standard logging
|
6
|
+
enhancements) and Nathaniel Talbott (the QueryTrace plug-in).
|
7
|
+
|
8
|
+
This gem is for Rails 3 only. It supports MySQL (including the mysql2 gem),
|
9
|
+
PostgreSQL and SQLite.
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
Once installed, the out-of-the-box behavior gives you:
|
14
|
+
|
15
|
+
* A cleaned-up backtrace after every SQL query, so you know exactly what
|
16
|
+
piece of code triggered the query.
|
17
|
+
* A report of the number of rows and rough count of bytes returned after
|
18
|
+
each query.
|
19
|
+
* After each request completes, additional summary information telling you
|
20
|
+
the number of statements executed, as well as a rough total number of
|
21
|
+
bytes received from the database.
|
22
|
+
* A top 10 list of SQL executions, sorted by total execution time (based on
|
23
|
+
the location of the query in code), including the total number of rows
|
24
|
+
and bytes returned over all executions.
|
25
|
+
|
26
|
+
All of this additional information is logged at DEBUG level, so it won't
|
27
|
+
clutter up your production log files.
|
28
|
+
|
29
|
+
== Options
|
30
|
+
|
31
|
+
The Top 10 summary provides the most options to customize its behavior.
|
32
|
+
|
33
|
+
If you want more or fewer than 10 queries, you can easily change that:
|
34
|
+
|
35
|
+
SqlLogging::Statistics.top_sql_queries = 5
|
36
|
+
|
37
|
+
If you want the sorted by something other than the total execution time,
|
38
|
+
you can instead sort by the median execution time, number of executions
|
39
|
+
or rows/bytes returned over all executions of the query:
|
40
|
+
|
41
|
+
SqlLogging::Statistics.show_top_sql_queries = :median_time
|
42
|
+
SqlLogging::Statistics.show_top_sql_queries = :queries
|
43
|
+
SqlLogging::Statistics.show_top_sql_queries = :rows
|
44
|
+
SqlLogging::Statistics.show_top_sql_queries = :bytes
|
45
|
+
|
46
|
+
You can also turn the list off entirely:
|
47
|
+
|
48
|
+
SqlLogging::Statistics.show_top_sql_queries = false
|
49
|
+
|
50
|
+
If you don't want to see query backtraces:
|
51
|
+
|
52
|
+
SqlLogging::Statistics.show_sql_backtrace = false
|
53
|
+
|
54
|
+
= Acknowledgments
|
55
|
+
|
56
|
+
Adam's post describing his logging improvements is at
|
57
|
+
http://gurge.com/blog/2006/11/09/rails-sql-logging-improvements/.
|
58
|
+
|
59
|
+
Nathaniel's QueryTrace is available at
|
60
|
+
http://terralien.com/projects/querytrace/.
|
61
|
+
|
62
|
+
= Contact
|
63
|
+
|
64
|
+
Feedback and/or patches to make this gem better are greatly appreciated!
|
65
|
+
|
66
|
+
Steve Madsen
|
67
|
+
Light Year Software, LLC
|
68
|
+
http://lightyearsoftware.com
|
69
|
+
steve@lightyearsoftware.com
|
data/lib/sql-logging.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'sql-logging/railtie'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_record/connection_adapters/mysql_adapter'
|
2
|
+
|
3
|
+
class ActiveRecord::ConnectionAdapters::MysqlAdapter
|
4
|
+
def select_with_sql_logging(sql, name = nil)
|
5
|
+
rows = nil
|
6
|
+
elapsed = Benchmark.measure do
|
7
|
+
rows = select_without_sql_logging(sql, name)
|
8
|
+
end
|
9
|
+
msec = elapsed.real * 1000
|
10
|
+
SqlLogging::Statistics.record_query(sql, name, msec, rows)
|
11
|
+
rows
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method_chain :select, :sql_logging
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
2
|
+
|
3
|
+
class ActiveRecord::ConnectionAdapters::Mysql2Adapter
|
4
|
+
def select_with_sql_logging(sql, name = nil)
|
5
|
+
rows = nil
|
6
|
+
elapsed = Benchmark.measure do
|
7
|
+
rows = select_without_sql_logging(sql, name)
|
8
|
+
end
|
9
|
+
msec = elapsed.real * 1000
|
10
|
+
SqlLogging::Statistics.record_query(sql, name, msec, rows)
|
11
|
+
rows
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method_chain :select, :sql_logging
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
2
|
+
|
3
|
+
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
4
|
+
def execute_with_sql_logging(sql, name = nil)
|
5
|
+
result = nil
|
6
|
+
elapsed = Benchmark.measure do
|
7
|
+
result = execute_without_sql_logging(sql, name)
|
8
|
+
end
|
9
|
+
msec = elapsed.real * 1000
|
10
|
+
if result.respond_to?(:rows)
|
11
|
+
SqlLogging::Statistics.record_query(sql, name, msec, result.rows)
|
12
|
+
else
|
13
|
+
SqlLogging::Statistics.record_query(sql, name, msec, result)
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method_chain :execute, :sql_logging
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ActiveRecord::ConnectionAdapters::SQLiteAdapter
|
2
|
+
def execute_with_sql_logging(sql, name = nil)
|
3
|
+
res = nil
|
4
|
+
elapsed = Benchmark.measure do
|
5
|
+
res = execute_without_sql_logging(sql, name)
|
6
|
+
end
|
7
|
+
msec = elapsed.real * 1000
|
8
|
+
SqlLogging::Statistics.record_query(sql, name, msec, res)
|
9
|
+
res
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method_chain :execute, :sql_logging
|
13
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'sql-logging/adapters/sqlite'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class LoggedQuery
|
2
|
+
attr_accessor :sql, :name, :backtrace, :queries, :rows, :bytes
|
3
|
+
|
4
|
+
def initialize(sql, name, backtrace)
|
5
|
+
@sql = sql
|
6
|
+
@name = name
|
7
|
+
@backtrace = backtrace
|
8
|
+
@queries = 0
|
9
|
+
@rows = 0
|
10
|
+
@bytes = 0
|
11
|
+
@times = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def log_query(rows, bytes, time)
|
15
|
+
@queries += 1
|
16
|
+
@rows += rows
|
17
|
+
@bytes += bytes
|
18
|
+
@times << time
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](key)
|
22
|
+
case key.to_sym
|
23
|
+
when :sql: @sql
|
24
|
+
when :name: @name
|
25
|
+
when :backtrace: @backtrace
|
26
|
+
when :queries: @queries
|
27
|
+
when :rows: @rows
|
28
|
+
when :bytes: @bytes
|
29
|
+
when :median_time: median_time
|
30
|
+
when :total_time: total_time
|
31
|
+
else nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def median_time
|
36
|
+
total_time / @times.length
|
37
|
+
end
|
38
|
+
|
39
|
+
def min_time
|
40
|
+
@times.min
|
41
|
+
end
|
42
|
+
|
43
|
+
def max_time
|
44
|
+
@times.max
|
45
|
+
end
|
46
|
+
|
47
|
+
def total_time
|
48
|
+
@times.inject(0) { |sum, time| sum += time }
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'sql-logging/statistics'
|
2
|
+
require 'rails'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module SqlLogging
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
initializer 'sql_logging.load_adapter_extensions' do
|
8
|
+
ActiveSupport.on_load(:active_record, :after => 'active_record.initialize_database') do
|
9
|
+
adapter = ActiveRecord::Base.configurations[Rails.env]['adapter']
|
10
|
+
begin
|
11
|
+
require "sql-logging/adapters/#{adapter}"
|
12
|
+
rescue LoadError => e
|
13
|
+
Rails.logger.warn "SQL Logging extensions are not available for #{adapter}; functionality will be limited"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
initializer 'sql_logging.reset_statistics' do
|
19
|
+
ActiveSupport.on_load(:active_record) do
|
20
|
+
ActionDispatch::Callbacks.before do
|
21
|
+
SqlLogging::Statistics.reset_statistics!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
initializer 'sql_logging.log_runtime' do
|
27
|
+
require "sql-logging/controller_runtime"
|
28
|
+
ActiveSupport.on_load(:action_controller) do
|
29
|
+
include SqlLogging::ControllerRuntime
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'sql-logging/logged_query'
|
2
|
+
|
3
|
+
module SqlLogging
|
4
|
+
class Helper
|
5
|
+
include Singleton
|
6
|
+
include ActionView::Helpers::TextHelper
|
7
|
+
include ActionView::Helpers::NumberHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
class Statistics
|
11
|
+
@@show_sql_backtrace = true
|
12
|
+
@@show_top_sql_queries = :total_time
|
13
|
+
@@top_sql_queries = 10
|
14
|
+
|
15
|
+
cattr_accessor :show_sql_backtrace, :top_sql_queries
|
16
|
+
|
17
|
+
def self.show_top_sql_queries
|
18
|
+
@@show_top_sql_queries
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.show_top_sql_queries=(value)
|
22
|
+
unless [ false, :rows, :queries, :bytes, :total_time, :median_time ].include?(value)
|
23
|
+
raise ArgumentError, "show_top_sql_queries must be one of false, :rows, :queries, :bytes, :total_time or :median_time"
|
24
|
+
end
|
25
|
+
|
26
|
+
@@show_top_sql_queries = value
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.reset_statistics!
|
30
|
+
@@queries = @@bytes = @@rows = 0
|
31
|
+
@@top_queries = {}
|
32
|
+
end
|
33
|
+
|
34
|
+
@@backtrace_cleaner = Rails.backtrace_cleaner.dup
|
35
|
+
@@backtrace_cleaner.add_silencer { |line| line =~ %r{sql-logging/lib} }
|
36
|
+
|
37
|
+
def self.record_query(sql, name, msec, result)
|
38
|
+
unless name.blank? || name =~ / Columns$/ || name == :skip_logging
|
39
|
+
bytes = 0
|
40
|
+
if result.nil?
|
41
|
+
ntuples = 0
|
42
|
+
else
|
43
|
+
result.each do |row|
|
44
|
+
row.each do |key, value|
|
45
|
+
bytes += key.size if key && key.respond_to?(:size)
|
46
|
+
bytes += value.size if value && value.respond_to?(:size)
|
47
|
+
end
|
48
|
+
end if result.respond_to?(:each)
|
49
|
+
ntuples = 0
|
50
|
+
if result.respond_to?(:length)
|
51
|
+
ntuples = result.length
|
52
|
+
elsif result.respond_to?(:num_rows)
|
53
|
+
ntuples = result.num_rows
|
54
|
+
elsif result.respond_to?(:ntuples)
|
55
|
+
ntuples = result.ntuples
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@@queries += 1
|
60
|
+
@@rows += ntuples
|
61
|
+
@@bytes += bytes
|
62
|
+
|
63
|
+
backtrace = @@backtrace_cleaner.clean(caller).join("\n ")
|
64
|
+
unless @@show_top_sql_queries == false
|
65
|
+
key = "#{name}:#{backtrace}"
|
66
|
+
unless query = @@top_queries[key]
|
67
|
+
query = LoggedQuery.new(sql, name, backtrace)
|
68
|
+
@@top_queries[key] = query
|
69
|
+
end
|
70
|
+
query.log_query(ntuples || 0, bytes || 0, msec)
|
71
|
+
end
|
72
|
+
|
73
|
+
Rails.logger.debug " #{helper.pluralize(ntuples, 'row')}, #{helper.number_to_human_size(bytes)}"
|
74
|
+
Rails.logger.debug " #{backtrace}" if @@show_sql_backtrace
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.log_report
|
79
|
+
Rails.logger.debug "SQL Logging: #{helper.pluralize(@@queries, 'statement')} executed, returning #{helper.number_to_human_size(@@bytes)}"
|
80
|
+
|
81
|
+
unless @@show_top_sql_queries == false
|
82
|
+
Rails.logger.debug "Top #{@@top_sql_queries} SQL executions:"
|
83
|
+
sorted_keys = @@top_queries.keys.sort_by { |k| @@top_queries[k][@@show_top_sql_queries] }.reverse
|
84
|
+
sorted_keys.slice(0..@@top_sql_queries).each do |key|
|
85
|
+
query = @@top_queries[key]
|
86
|
+
Rails.logger.debug " Executed #{helper.pluralize(query.queries, 'time')} in #{'%.1f' % query.total_time}ms " +
|
87
|
+
"(#{'%.1f' % query.min_time}/#{'%.1f' % query.median_time}/#{'%.1f' % query.max_time}ms min/median/max), " +
|
88
|
+
"returning #{helper.pluralize(query.rows, 'row')} " +
|
89
|
+
"(#{helper.number_to_human_size(query.bytes)}):\n" +
|
90
|
+
" #{query.name}\n" +
|
91
|
+
" First exec was: #{query.sql}\n" +
|
92
|
+
" #{query.backtrace}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def self.helper
|
100
|
+
Helper.instance
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sql-logging
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 5
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 3.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Steve Madsen
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-22 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rails
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 3.0.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description: Adds SQL analysis and debugging info to Rails 3 apps.
|
38
|
+
email: steve@lightyearsoftware.com
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- README.rdoc
|
45
|
+
files:
|
46
|
+
- lib/sql-logging/adapters/mysql.rb
|
47
|
+
- lib/sql-logging/adapters/mysql2.rb
|
48
|
+
- lib/sql-logging/adapters/postgresql.rb
|
49
|
+
- lib/sql-logging/adapters/sqlite.rb
|
50
|
+
- lib/sql-logging/adapters/sqlite3.rb
|
51
|
+
- lib/sql-logging/controller_runtime.rb
|
52
|
+
- lib/sql-logging/logged_query.rb
|
53
|
+
- lib/sql-logging/railtie.rb
|
54
|
+
- lib/sql-logging/statistics.rb
|
55
|
+
- lib/sql-logging/version.rb
|
56
|
+
- lib/sql-logging.rb
|
57
|
+
- README.rdoc
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/lightyear/sql-logging
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.7
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Adds SQL analysis and debugging info to Rails 3 apps.
|
92
|
+
test_files: []
|
93
|
+
|