edge
Mais em rubyonrails.org: Mais Ruby on Rails

Instrumentação do Active Support

O Active Support é uma parte do Rails core que fornece extensões de linguagem Ruby, utilitários e outras coisas. Uma das coisas que ele inclui é uma API de instrumentação que pode ser usada dentro de um aplicativo para medir certas ações que ocorrem dentro do código Ruby, como aquelas dentro de um aplicativo Rails ou do próprio framework. No entanto, não se limita ao Rails. Ele pode ser usado independentemente em outros scripts Ruby, se desejado.

Neste guia, você aprenderá como usar a API de instrumentação do Active Support para medir eventos dentro do Rails e outros códigos Ruby.

Depois de ler este guia, você saberá:

1 Introdução à Instrumentação

A API de instrumentação fornecida pelo Active Support permite que os desenvolvedores forneçam ganchos aos quais outros desenvolvedores podem se conectar. Existem vários desses dentro do framework Rails. Com esta API, os desenvolvedores podem optar por serem notificados quando certos eventos ocorrem dentro de seu aplicativo ou outro trecho de código Ruby.

Por exemplo, há um gancho fornecido dentro do Active Record que é chamado toda vez que o Active Record usa uma consulta SQL em um banco de dados. Este gancho pode ser assinado e usado para rastrear o número de consultas durante uma determinada ação. Há outro gancho em torno do processamento de uma ação de um controlador. Isso poderia ser usado, por exemplo, para rastrear quanto tempo uma ação específica levou.

Você também pode criar seus próprios eventos dentro do seu aplicativo aos quais você pode se inscrever posteriormente.

2 Assinando um Evento

Assinar um evento é fácil. Use ActiveSupport::Notifications.subscribe com um bloco para ouvir qualquer notificação.

O bloco recebe os seguintes argumentos:

  • Nome do evento
  • Hora em que começou
  • Hora em que terminou
  • Um ID único para o instrumentador que disparou o evento
  • O payload para o evento
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # suas próprias coisas personalizadas
  Rails.logger.info "#{name} Recebido! (começou: #{started}, terminou: #{finished})" # process_action.action_controller Recebido (começou: 2019-05-05 13:43:57 -0800, terminou: 2019-05-05 13:43:58 -0800)
end

Se você estiver preocupado com a precisão de started e finished para calcular um tempo decorrido preciso, use ActiveSupport::Notifications.monotonic_subscribe. O bloco fornecido receberá os mesmos argumentos acima, mas o started e finished terão valores com um tempo monótono preciso em vez do tempo de parede.

ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # suas próprias coisas personalizadas
  Rails.logger.info "#{name} Recebido! (começou: #{started}, terminou: #{finished})" # process_action.action_controller Recebido (começou: 1560978.425334, terminou: 1560979.429234)
end

Definir todos esses argumentos de bloco toda vez pode ser tedioso. Você pode facilmente criar um ActiveSupport::Notifications::Event a partir dos argumentos do bloco assim:

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (em milissegundos)
  event.payload   # => {:extra=>informação}

  Rails.logger.info "#{event} Recebido!"
end

Você também pode passar um bloco que aceite apenas um argumento, e ele receberá um objeto de evento:

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |event|
  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (em milissegundos)
  event.payload   # => {:extra=>informação}

  Rails.logger.info "#{event} Recebido!"
end

Você também pode se inscrever em eventos que correspondam a uma expressão regular. Isso permite que você se inscreva em múltiplos eventos de uma vez. Veja como se inscrever em tudo do ActionController:

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # inspecione todos os eventos do ActionController
end

3 Visualizar Temporizações da Instrumentação em Seu Navegador

O Rails implementa o padrão Server Timing para disponibilizar informações de temporização no navegador da web. Para habilitar, edite a configuração do ambiente (geralmente development.rb, pois é mais usado no desenvolvimento) para incluir o seguinte:

  config.server_timing = true

Depois de configurado (incluindo reiniciar o servidor), você pode ir para o painel Ferramentas do Desenvolvedor do seu navegador, em seguida, selecione Rede e recarregue sua página. Em seguida, você pode selecionar qualquer solicitação para o seu servidor Rails e verá as temporizações do servidor na guia de temporizações. Para um exemplo de como fazer isso, consulte a Documentação do Firefox.

4 Ganchos do Framework Rails

Dentro do framework Ruby on Rails, existem vários ganchos fornecidos para eventos comuns. Esses eventos e seus payloads são detalhados abaixo.

4.1 Controlador de Ação

4.1.1 start_processing.action_controller

Chave Valor
:controller O nome do controlador
:action A ação
:params Hash dos parâmetros da solicitação sem nenhum parâmetro filtrado
:headers Cabeçalhos da solicitação
:format html/js/json/xml etc
:method Verbo de solicitação HTTP
:path Caminho da solicitação
{
  controller: "PostsController",
  action: "new",
  params: { "action" => "new", "controller" => "posts" },
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts/new"
}

4.1.2 process_action.action_controller

Chave Valor
:controller O nome do controlador
:action A ação
:params Hash dos parâmetros da solicitação sem nenhum parâmetro filtrado
:headers Cabeçalhos da solicitação
:format html/js/json/xml etc
:method Verbo de solicitação HTTP
:path Caminho da solicitação
:request O objeto ActionDispatch::Request
:response O objeto ActionDispatch::Response
:status Código de status HTTP
:view_runtime Tempo gasto na visualização em ms
:db_runtime Tempo gasto executando consultas ao banco de dados em ms
{
  controller: "PostsController",
  action: "index",
  params: {"action" => "index", "controller" => "posts"},
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts",
  request: #<ActionDispatch::Request:0x00007ff1cb9bd7b8>,
  response: #<ActionDispatch::Response:0x00007f8521841ec8>,
  status: 200,
  view_runtime: 46.848,
  db_runtime: 0.157
}

4.1.3 send_file.action_controller

Chave Valor
:path Caminho completo para o arquivo

Chaves adicionais podem ser adicionadas pelo chamador.

4.1.4 send_data.action_controller

ActionController não adiciona nenhuma informação específica à carga útil. Todas as opções são passadas para a carga útil.

4.1.5 redirect_to.action_controller

Chave Valor
:status Código de resposta HTTP
:location URL para redirecionar
:request O objeto ActionDispatch::Request
{
  status: 302,
  location: "http://localhost:3000/posts/new",
  request: <ActionDispatch::Request:0x00007ff1cb9bd7b8>
}

4.1.6 halted_callback.action_controller

Chave Valor
:filter Filtro que interrompeu a ação
{
  filter: ":halting_filter"
}

4.1.7 unpermitted_parameters.action_controller

Chave Valor
:keys As chaves não permitidas
:context Hash com as seguintes chaves: :controller, :action, :params, :request

4.2 Controlador de Ação — Cache

4.2.1 write_fragment.action_controller

Chave Valor
:key A chave completa
{
  key: 'posts/1-dashboard-view'
}

4.2.2 read_fragment.action_controller

Chave Valor
:key A chave completa
{
  key: 'posts/1-dashboard-view'
}

4.2.3 expire_fragment.action_controller

Chave Valor
:key A chave completa
{
  key: 'posts/1-dashboard-view'
}

4.2.4 exist_fragment?.action_controller

Chave Valor
:key A chave completa
{
  key: 'posts/1-dashboard-view'
}

4.3 Despacho de Ação

4.3.1 process_middleware.action_dispatch

Chave Valor
:middleware Nome do middleware

4.3.2 redirect.action_dispatch

Chave Valor
:status Código de resposta HTTP
:location URL para redirecionar
:request O objeto ActionDispatch::Request

4.3.3 request.action_dispatch

Chave Valor
:request O objeto ActionDispatch::Request

4.4 Visualização de Ação

4.4.1 render_template.action_view

Chave Valor
:identifier Caminho completo para o template
:layout Layout aplicável
:locals Variáveis locais passadas para o template
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
  layout: "layouts/application",
  locals: { foo: "bar" }
}

4.4.2 render_partial.action_view

Chave Valor
:identifier Caminho completo para o template
:locals Variáveis locais passadas para o template
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb",
  locals: { foo: "bar" }
}

4.4.3 render_collection.action_view

Chave Valor
:identifier Caminho completo para o template
:count Tamanho da coleção
:cache_hits Número de parciais buscadas no cache

A chave :cache_hits é incluída apenas se a coleção for renderizada com cached: true. ruby { identifier: "/Users/adam/projects/notifications/app/views/posts/_post.html.erb", count: 3, cache_hits: 0 }

4.4.4 render_layout.action_view

Chave Valor
:identifier Caminho completo do modelo
{
  identifier: "/Users/adam/projects/notifications/app/views/layouts/application.html.erb"
}

4.5 Active Record

4.5.1 sql.active_record

Chave Valor
:sql Declaração SQL
:name Nome da operação
:connection Objeto de conexão
:binds Parâmetros de ligação
:type_casted_binds Parâmetros de ligação convertidos
:statement_name Nome da declaração SQL
:cached true é adicionado quando consultas em cache são usadas

Os adaptadores podem adicionar seus próprios dados também.

{
  sql: "SELECT \"posts\".* FROM \"posts\" ",
  name: "Post Load",
  connection: <ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9f7a838850>,
  binds: [<ActiveModel::Attribute::WithCastValue:0x00007fe19d15dc00>],
  type_casted_binds: [11],
  statement_name: nil
}

4.5.2 strict_loading_violation.active_record

Este evento é emitido apenas quando config.active_record.action_on_strict_loading_violation está definido como :log.

Chave Valor
:owner Modelo com strict_loading habilitado
:reflection Reflexão da associação que tentou carregar

4.5.3 instantiation.active_record

Chave Valor
:record_count Número de registros instanciados
:class_name Classe do registro
{
  record_count: 1,
  class_name: "User"
}

4.6 Action Mailer

4.6.1 deliver.action_mailer

Chave Valor
:mailer Nome da classe do mailer
:message_id ID da mensagem, gerado pelo gem Mail
:subject Assunto do email
:to Endereço(es) de destino do email
:from Endereço de origem do email
:bcc Endereços BCC do email
:cc Endereços CC do email
:date Data do email
:mail A forma codificada do email
:perform_deliveries Se a entrega desta mensagem é realizada ou não
{
  mailer: "Notification",
  message_id: "[email protected]",
  subject: "Rails Guides",
  to: ["[email protected]", "[email protected]"],
  from: ["[email protected]"],
  date: Sat, 10 Mar 2012 14:18:09 +0100,
  mail: "...", # omitido por brevidade
  perform_deliveries: true
}

4.6.2 process.action_mailer

Chave Valor
:mailer Nome da classe do mailer
:action A ação
:args Os argumentos
{
  mailer: "Notification",
  action: "welcome_email",
  args: []
}

4.7 Active Support — Caching

4.7.1 cache_read.active_support

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe do armazenamento
:hit Se esta leitura é um acerto
:super_operation :fetch se uma leitura é feita com fetch

4.7.2 cache_read_multi.active_support

Chave Valor
:key Chaves usadas no armazenamento
:store Nome da classe do armazenamento
:hits Chaves dos acertos em cache
:super_operation :fetch_multi se uma leitura é feita com fetch_multi

4.7.3 cache_generate.active_support

Este evento é emitido apenas quando fetch é chamado com um bloco.

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe do armazenamento

As opções passadas para fetch serão mescladas com o payload ao escrever no armazenamento.

{
  key: "nome-da-computacao-complicada",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.4 cache_fetch_hit.active_support

Este evento é emitido apenas quando fetch é chamado com um bloco.

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe do armazenamento

As opções passadas para fetch serão mescladas com o payload.

{
  key: "nome-da-computacao-complicada",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.5 cache_write.active_support

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe do armazenamento

Os armazenamentos de cache podem adicionar seus próprios dados também.

{
  key: "nome-da-computacao-complicada",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.6 cache_write_multi.active_support

Chave Valor
:key Chaves e valores escritos no armazenamento
:store Nome da classe do armazenamento

4.7.7 cache_increment.active_support

Este evento é emitido apenas ao usar MemCacheStore ou RedisCacheStore.

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe de armazenamento
:amount Quantidade a ser incrementada
{
  key: "garrafas-de-cerveja",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 99
}

4.7.8 cache_decrement.active_support

Este evento é emitido apenas ao usar os armazenamentos de cache Memcached ou Redis.

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe de armazenamento
:amount Quantidade a ser decrementada
{
  key: "garrafas-de-cerveja",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 1
}

4.7.9 cache_delete.active_support

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe de armazenamento
{
  key: "nome-do-calculo-complicado",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.10 cache_delete_multi.active_support

Chave Valor
:key Chaves usadas no armazenamento
:store Nome da classe de armazenamento

4.7.11 cache_delete_matched.active_support

Este evento é emitido apenas ao usar RedisCacheStore, FileStore ou MemoryStore.

Chave Valor
:key Padrão de chave usado
:store Nome da classe de armazenamento
{
  key: "posts/*",
  store: "ActiveSupport::Cache::RedisCacheStore"
}

4.7.12 cache_cleanup.active_support

Este evento é emitido apenas ao usar MemoryStore.

Chave Valor
:store Nome da classe de armazenamento
:size Número de entradas no cache antes da limpeza
{
  store: "ActiveSupport::Cache::MemoryStore",
  size: 9001
}

4.7.13 cache_prune.active_support

Este evento é emitido apenas ao usar MemoryStore.

Chave Valor
:store Nome da classe de armazenamento
:key Tamanho alvo (em bytes) para o cache
:from Tamanho (em bytes) do cache antes da poda
{
  store: "ActiveSupport::Cache::MemoryStore",
  key: 5000,
  from: 9001
}

4.7.14 cache_exist?.active_support

Chave Valor
:key Chave usada no armazenamento
:store Nome da classe de armazenamento
{
  key: "nome-do-calculo-complicado",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.8 Active Support — Mensagens

4.8.1 message_serializer_fallback.active_support

Chave Valor
:serializer Serializador primário (pretendido)
:fallback Serializador de fallback (real)
:serialized String serializada
:deserialized Valor deserializado
{
  serializer: :json_allow_marshal,
  fallback: :marshal,
  serialized: "\x04\b{\x06I\"\nHello\x06:\x06ETI\"\nWorld\x06;\x00T",
  deserialized: { "Hello" => "World" },
}

4.9 Active Job

4.9.1 enqueue_at.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job

4.9.2 enqueue.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job

4.9.3 enqueue_retry.active_job

Chave Valor
:job Objeto Job
:adapter Objeto QueueAdapter processando o job
:error O erro que causou a repetição
:wait O atraso da repetição

4.9.4 enqueue_all.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:jobs Um array de objetos Job

4.9.5 perform_start.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job

4.9.6 perform.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job
:db_runtime Quantidade de tempo gasto executando consultas no banco em ms

4.9.7 retry_stopped.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job
:error O erro que causou a repetição

4.9.8 discard.active_job

Chave Valor
:adapter Objeto QueueAdapter processando o job
:job Objeto Job
:error O erro que causou o descarte

4.10 Action Cable

4.10.1 perform_action.action_cable

Chave Valor
:channel_class Nome da classe do canal
:action A ação
:data Um hash de dados

4.10.2 transmit.action_cable

Chave Valor
:channel_class Nome da classe do canal
:data Um hash de dados
:via Via

4.10.3 transmit_subscription_confirmation.action_cable

Chave Valor
:channel_class Nome da classe do canal

4.10.4 transmit_subscription_rejection.action_cable

Chave Valor
:channel_class Nome da classe do canal

4.10.5 broadcast.action_cable

Chave Valor
:broadcasting Um broadcasting nomeado
:message Um hash de mensagem
:coder O codificador

4.11 Active Storage

4.11.1 preview.active_storage

Chave Valor
:key Token seguro

4.11.2 transform.active_storage

4.11.3 analyze.active_storage

Chave Valor
:analyzer Nome do analisador, por exemplo, ffprobe

4.12 Active Storage — Storage Service

4.12.1 service_upload.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço
:checksum Checksum para garantir a integridade

4.12.2 service_streaming_download.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço

4.12.3 service_download_chunk.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço
:range Faixa de bytes tentada de leitura

4.12.4 service_download.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço

4.12.5 service_delete.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço

4.12.6 service_delete_prefixed.active_storage

Chave Valor
:prefix Prefixo da chave
:service Nome do serviço

4.12.7 service_exist.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço
:exist Arquivo ou blob existe ou não

4.12.8 service_url.active_storage

Chave Valor
:key Token seguro
:service Nome do serviço
:url URL gerada

4.12.9 service_update_metadata.active_storage

Este evento é emitido apenas ao usar o serviço Google Cloud Storage.

Chave Valor
:key Token seguro
:service Nome do serviço
:content_type Campo HTTP Content-Type
:disposition Campo HTTP Content-Disposition

4.13 Action Mailbox

4.13.1 process.action_mailbox

Chave Valor
:mailbox Instância da classe Mailbox herdando de ActionMailbox::Base
:inbound_email Hash com dados sobre o email de entrada sendo processado
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,
  inbound_email: {
    id: 1,
    message_id: "[email protected]",
    status: "processing"
  }
}

4.14 Railties

4.14.1 load_config_initializer.railties

Chave Valor
:initializer Caminho do inicializador carregado em config/initializers

4.15 Rails

4.15.1 deprecation.rails

Chave Valor
:message O aviso de depreciação
:callstack De onde veio a depreciação
:gem_name Nome da gem relatando a depreciação
:deprecation_horizon Versão em que o comportamento obsoleto será removido

5 Exceções

Se ocorrer uma exceção durante qualquer instrumentação, o payload incluirá informações sobre ela.

Chave Valor
:exception Um array de dois elementos. Nome da classe da exceção e a mensagem
:exception_object O objeto de exceção

6 Criando Eventos Personalizados

Adicionar seus próprios eventos também é fácil. O Active Support cuidará de todo o trabalho pesado para você. Basta chamar ActiveSupport::Notifications.instrument com um nome, payload e um bloco. A notificação será enviada após o retorno do bloco. O Active Support gerará os tempos de início e término, e adicionará o ID exclusivo do instrumentador. Todos os dados passados para a chamada instrument serão incluídos no payload. Aqui está um exemplo:

ActiveSupport::Notifications.instrument "my.custom.event", this: :data do
  # faça suas personalizações aqui
end

Agora você pode ouvir esse evento com:

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

Você também pode chamar instrument sem passar um bloco. Isso permite que você aproveite a infraestrutura de instrumentação para outros usos de mensagens.

ActiveSupport::Notifications.instrument "my.custom.event", this: :data

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

Você deve seguir as convenções do Rails ao definir seus próprios eventos. O formato é: evento.biblioteca. Se sua aplicação estiver enviando Tweets, você deve criar um evento chamado tweet.twitter.

Feedback

Você é incentivado a ajudar a melhorar a qualidade deste guia.

Por favor, contribua se encontrar algum erro de digitação ou factual. Para começar, você pode ler nossa contribuição à documentação seção.

Você também pode encontrar conteúdo incompleto ou desatualizado. Por favor, adicione qualquer documentação ausente para o principal. Certifique-se de verificar Guias Edge primeiro para verificar se os problemas já foram corrigidos ou não no branch principal. Verifique as Diretrizes dos Guias do Ruby on Rails para estilo e convenções.

Se por algum motivo você encontrar algo para corrigir, mas não puder corrigi-lo você mesmo, por favor abra uma issue.

E por último, mas não menos importante, qualquer tipo de discussão sobre a documentação do Ruby on Rails é muito bem-vinda no Fórum oficial do Ruby on Rails.