sql-logging 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+