Module: ActiveRecord::QueryLogs

Defined in:
lib/active_record/query_logs.rb,
lib/active_record/query_logs_formatter.rb

Overview

Active Record Query Logs

Automatically append comments to SQL queries with runtime information tags. This can be used to trace troublesome SQL statements back to the application code that generated these statements.

Query logs can be enabled via Rails configuration in config/application.rb or an initializer:

config.active_record.query_log_tags_enabled = true

By default the name of the application, the name and action of the controller, or the name of the job are logged. The default format is SQLCommenter. The tags shown in a query comment can be configured via Rails configuration:

config.active_record.query_log_tags = [ :application, :controller, :action, :job ]

Active Record defines default tags available for use:

  • application

  • pid

  • socket

  • db_host

  • database

  • source_location

WARNING: Calculating the source_location of a query can be slow, so you should consider its impact if using it in a production environment.

Also see config.active_record.verbose_query_logs.

Action Controller adds default tags when loaded:

  • controller

  • action

  • namespaced_controller

Active Job adds default tags when loaded:

  • job

New comment tags can be defined by adding them in a Hash to the tags Array. Tags can have dynamic content by setting a Proc or lambda value in the Hash, and can reference any value stored by Rails in the context object. ActiveSupport::CurrentAttributes can be used to store application values. Tags with nil values are omitted from the query comment.

Escaping is performed on the string returned, however untrusted user input should not be used.

Example:

config.active_record.query_log_tags = [
  :namespaced_controller,
  :action,
  :job,
  {
    request_id: ->(context) { context[:controller]&.request&.request_id },
    job_id: ->(context) { context[:job]&.job_id },
    tenant_id: -> { Current.tenant&.id },
    static: "value",
  },
]

By default the name of the application, the name and action of the controller, or the name of the job are logged using the SQLCommenter format. This can be changed via config.active_record.query_log_tags_format

Tag comments can be prepended to the query:

ActiveRecord::QueryLogs.prepend_comment = true

For applications where the content will not change during the lifetime of the request or job execution, the tags can be cached for reuse in every query:

config.active_record.cache_query_log_tags = true

Defined Under Namespace

Modules: LegacyFormatter Classes: GetKeyHandler, IdentityHandler, SQLCommenter, ZeroArityHandler

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.cache_query_log_tagsObject

:nodoc:



119
120
121
# File 'lib/active_record/query_logs.rb', line 119

def cache_query_log_tags
  @cache_query_log_tags
end

.prepend_commentObject

:nodoc:



119
120
121
# File 'lib/active_record/query_logs.rb', line 119

def prepend_comment
  @prepend_comment
end

.taggingsObject

:nodoc:



118
119
120
# File 'lib/active_record/query_logs.rb', line 118

def taggings
  @taggings
end

.tagsObject

:nodoc:



118
119
120
# File 'lib/active_record/query_logs.rb', line 118

def tags
  @tags
end

.tags_formatterObject

:nodoc:



118
119
120
# File 'lib/active_record/query_logs.rb', line 118

def tags_formatter
  @tags_formatter
end

Class Method Details

.call(sql, connection) ⇒ Object

:nodoc:



143
144
145
146
147
148
149
150
151
152
153
# File 'lib/active_record/query_logs.rb', line 143

def call(sql, connection) # :nodoc:
  comment = self.comment(connection)

  if comment.blank?
    sql
  elsif prepend_comment
    "#{comment} #{sql}"
  else
    "#{sql} #{comment}"
  end
end

.clear_cacheObject

:nodoc:



155
156
157
# File 'lib/active_record/query_logs.rb', line 155

def clear_cache # :nodoc:
  self.cached_comment = nil
end

.query_source_locationObject

:nodoc:



159
160
161
162
163
164
165
# File 'lib/active_record/query_logs.rb', line 159

def query_source_location # :nodoc:
  Thread.each_caller_location do |location|
    frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
    return frame if frame
  end
  nil
end