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 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
@@ -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,14 @@
1
+ module SqlLogging
2
+ module ControllerRuntime
3
+ extend ActiveSupport::Concern
4
+
5
+ protected
6
+
7
+ module ClassMethods
8
+ def log_process_action(payload)
9
+ SqlLogging::Statistics.log_report
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module SqlLogging
2
+ VERSION = '3.0.1'
3
+ 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
+