edge
Plus sur rubyonrails.org: Plus de Ruby on Rails

Instrumentation Active Support

Active Support est une partie de Rails qui fournit des extensions de langage Ruby, des utilitaires et d'autres choses. L'une des choses qu'il inclut est une API d'instrumentation qui peut être utilisée à l'intérieur d'une application pour mesurer certaines actions qui se produisent dans le code Ruby, telles que celles à l'intérieur d'une application Rails ou du framework lui-même. Cependant, il n'est pas limité à Rails. Il peut être utilisé indépendamment dans d'autres scripts Ruby si nécessaire.

Dans ce guide, vous apprendrez comment utiliser l'API d'instrumentation d'Active Support pour mesurer des événements à l'intérieur de Rails et d'autres codes Ruby.

Après avoir lu ce guide, vous saurez :

1 Introduction à l'instrumentation

L'API d'instrumentation fournie par Active Support permet aux développeurs de fournir des crochets auxquels d'autres développeurs peuvent se connecter. Il y en a plusieurs dans le framework Rails. Avec cette API, les développeurs peuvent choisir d'être notifiés lorsque certains événements se produisent à l'intérieur de leur application ou d'un autre morceau de code Ruby.

Par exemple, il y a un crochet fourni dans Active Record qui est appelé à chaque fois qu'Active Record utilise une requête SQL sur une base de données. Ce crochet pourrait être abonné et utilisé pour suivre le nombre de requêtes pendant une certaine action. Il y a un autre crochet autour du traitement d'une action d'un contrôleur. Cela pourrait être utilisé, par exemple, pour suivre la durée d'une action spécifique.

Vous pouvez même créer vos propres événements à l'intérieur de votre application auxquels vous pourrez vous abonner ultérieurement.

2 S'abonner à un événement

S'abonner à un événement est facile. Utilisez ActiveSupport::Notifications.subscribe avec un bloc pour écouter toute notification.

Le bloc reçoit les arguments suivants :

  • Nom de l'événement
  • Heure de début
  • Heure de fin
  • Un identifiant unique pour l'instrument qui a déclenché l'événement
  • Les données pour l'événement
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # votre propre code personnalisé
  Rails.logger.info "#{name} Reçu ! (début : #{started}, fin : #{finished})" # process_action.action_controller Reçu (début : 2019-05-05 13:43:57 -0800, fin : 2019-05-05 13:43:58 -0800)
end

Si vous êtes préoccupé par l'exactitude de started et finished pour calculer un temps écoulé précis, utilisez ActiveSupport::Notifications.monotonic_subscribe. Le bloc donné recevra les mêmes arguments que ci-dessus, mais started et finished auront des valeurs avec un temps monotone précis au lieu du temps du calendrier.

ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # votre propre code personnalisé
  Rails.logger.info "#{name} Reçu ! (début : #{started}, fin : #{finished})" # process_action.action_controller Reçu (début : 1560978.425334, fin : 1560979.429234)
end

Définir tous ces arguments de bloc à chaque fois peut être fastidieux. Vous pouvez facilement créer un ActiveSupport::Notifications::Event à partir des arguments de bloc comme ceci :

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

  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (en millisecondes)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Reçu !"
end

Vous pouvez également passer un bloc qui n'accepte qu'un seul argument, et il recevra un objet événement :

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |event|
  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (en millisecondes)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Reçu !"
end

Vous pouvez également vous abonner à des événements correspondant à une expression régulière. Cela vous permet de vous abonner à plusieurs événements à la fois. Voici comment vous abonner à tout ce qui concerne ActionController :

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # inspecter tous les événements ActionController
end

3 Afficher les durées de l'instrumentation dans votre navigateur

Rails implémente la norme Server Timing pour rendre les informations de durée disponibles dans le navigateur web. Pour l'activer, modifiez votre configuration d'environnement (généralement development.rb car c'est le plus utilisé en développement) pour inclure ce qui suit :

  config.server_timing = true

Une fois configuré (y compris le redémarrage de votre serveur), vous pouvez accéder au volet Outils de développement de votre navigateur, puis sélectionner Réseau et recharger votre page. Vous pouvez ensuite sélectionner n'importe quelle requête vers votre serveur Rails, et vous verrez les durées du serveur dans l'onglet des durées. Pour un exemple de cela, consultez la documentation Firefox.

4 Crochets du framework Rails

Dans le framework Ruby on Rails, plusieurs crochets sont fournis pour des événements courants. Ces événements et leurs charges utiles sont détaillés ci-dessous.

4.1 Action Controller

4.1.1 start_processing.action_controller

Clé Valeur
:controller Le nom du contrôleur
:action L'action
:params Hash des paramètres de la requête sans aucun paramètre filtré
:headers En-têtes de la requête
:format html/js/json/xml etc
:method Verbe de la requête HTTP
:path Chemin de la requête
{
  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

Clé Valeur
:controller Le nom du contrôleur
:action L'action
:params Hash des paramètres de la requête sans aucun paramètre filtré
:headers En-têtes de la requête
:format html/js/json/xml etc
:method Verbe de la requête HTTP
:path Chemin de la requête
:request L'objet ActionDispatch::Request
:response L'objet ActionDispatch::Response
:status Code de statut HTTP
:view_runtime Temps passé dans la vue en ms
:db_runtime Temps passé à exécuter les requêtes de la base de données en 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

Clé Valeur
:path Chemin complet vers le fichier

Des clés supplémentaires peuvent être ajoutées par l'appelant.

4.1.4 send_data.action_controller

ActionController n'ajoute aucune information spécifique à la charge utile. Toutes les options sont transmises à la charge utile.

4.1.5 redirect_to.action_controller

Clé Valeur
:status Code de réponse HTTP
:location URL de redirection
:request L'objet ActionDispatch::Request
{
  status: 302,
  location: "http://localhost:3000/posts/new",
  request: <ActionDispatch::Request:0x00007ff1cb9bd7b8>
}

4.1.6 halted_callback.action_controller

Clé Valeur
:filter Filtre qui a interrompu l'action
{
  filter: ":halting_filter"
}

4.1.7 unpermitted_parameters.action_controller

Clé Valeur
:keys Les clés non autorisées
:context Hash avec les clés suivantes : :controller, :action, :params, :request

4.2 Action Controller — Caching

4.2.1 write_fragment.action_controller

Clé Valeur
:key La clé complète
{
  key: 'posts/1-dashboard-view'
}

4.2.2 read_fragment.action_controller

Clé Valeur
:key La clé complète
{
  key: 'posts/1-dashboard-view'
}

4.2.3 expire_fragment.action_controller

Clé Valeur
:key La clé complète
{
  key: 'posts/1-dashboard-view'
}

4.2.4 exist_fragment?.action_controller

Clé Valeur
:key La clé complète
{
  key: 'posts/1-dashboard-view'
}

4.3 Action Dispatch

4.3.1 process_middleware.action_dispatch

Clé Valeur
:middleware Nom du middleware

4.3.2 redirect.action_dispatch

Clé Valeur
:status Code de réponse HTTP
:location URL de redirection
:request L'objet ActionDispatch::Request

4.3.3 request.action_dispatch

Clé Valeur
:request L'objet ActionDispatch::Request

4.4 Action View

4.4.1 render_template.action_view

Clé Valeur
:identifier Chemin complet vers le modèle
:layout Mise en page applicable
:locals Variables locales passées au modèle
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
  layout: "layouts/application",
  locals: { foo: "bar" }
}

4.4.2 render_partial.action_view

Clé Valeur
:identifier Chemin complet vers le modèle
:locals Variables locales passées au modèle
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb",
  locals: { foo: "bar" }
}

4.4.3 render_collection.action_view

Clé Valeur
:identifier Chemin complet vers le modèle
:count Taille de la collection
:cache_hits Nombre de partiels récupérés du cache

La clé :cache_hits est incluse uniquement si la collection est rendue avec 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

Clé Valeur
:identifier Chemin complet du modèle
{
  identifier: "/Users/adam/projects/notifications/app/views/layouts/application.html.erb"
}

4.5 Active Record

4.5.1 sql.active_record

Clé Valeur
:sql Requête SQL
:name Nom de l'opération
:connection Objet de connexion
:binds Paramètres de liaison
:type_casted_binds Paramètres de liaison convertis en types
:statement_name Nom de la requête SQL
:cached true est ajouté lorsque des requêtes mises en cache sont utilisées

Les adaptateurs peuvent également ajouter leurs propres données.

{
  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

Cet événement est émis uniquement lorsque config.active_record.action_on_strict_loading_violation est défini sur :log.

Clé Valeur
:owner Modèle avec strict_loading activé
:reflection Réflexion de l'association qui a tenté de charger

4.5.3 instantiation.active_record

Clé Valeur
:record_count Nombre d'enregistrements instanciés
:class_name Classe de l'enregistrement
{
  record_count: 1,
  class_name: "User"
}

4.6 Action Mailer

4.6.1 deliver.action_mailer

Clé Valeur
:mailer Nom de la classe du mailer
:message_id ID du message, généré par la gem Mail
:subject Sujet du mail
:to Adresse(s) de destination du mail
:from Adresse d'expéditeur du mail
:bcc Adresses BCC du mail
:cc Adresses CC du mail
:date Date du mail
:mail La forme encodée du mail
:perform_deliveries Si la livraison de ce message est effectuée ou non
{
  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: "...", # omis pour plus de concision
  perform_deliveries: true
}

4.6.2 process.action_mailer

Clé Valeur
:mailer Nom de la classe du mailer
:action L'action
:args Les arguments
{
  mailer: "Notification",
  action: "welcome_email",
  args: []
}

4.7 Active Support — Caching

4.7.1 cache_read.active_support

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store
:hit Si cette lecture est un succès
:super_operation :fetch si une lecture est effectuée avec fetch

4.7.2 cache_read_multi.active_support

Clé Valeur
:key Clés utilisées dans le store
:store Nom de la classe du store
:hits Clés des lectures réussies
:super_operation :fetch_multi si une lecture est effectuée avec fetch_multi

4.7.3 cache_generate.active_support

Cet événement est émis uniquement lorsque fetch est appelé avec un bloc.

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store

Les options passées à fetch seront fusionnées avec la charge utile lors de l'écriture dans le store.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.4 cache_fetch_hit.active_support

Cet événement est émis uniquement lorsque fetch est appelé avec un bloc.

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store

Les options passées à fetch seront fusionnées avec la charge utile.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.5 cache_write.active_support

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store

Les stores de cache peuvent également ajouter leurs propres données.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.6 cache_write_multi.active_support

Clé Valeur
:key Clés et valeurs écrites dans le store
:store Nom de la classe du store

4.7.7 cache_increment.active_support

Cet événement est émis uniquement lors de l'utilisation de MemCacheStore ou RedisCacheStore.

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store
:amount Montant de l'incrément
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 99
}

4.7.8 cache_decrement.active_support

Cet événement est émis uniquement lors de l'utilisation des stores de cache Memcached ou Redis.

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store
:amount Montant du décrément
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 1
}

4.7.9 cache_delete.active_support

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.10 cache_delete_multi.active_support

Clé Valeur
:key Clés utilisées dans le store
:store Nom de la classe du store

4.7.11 cache_delete_matched.active_support

Cet événement est émis uniquement lors de l'utilisation de RedisCacheStore, FileStore ou MemoryStore.

Clé Valeur
:key Motif de clé utilisé
:store Nom de la classe du store
{
  key: "posts/*",
  store: "ActiveSupport::Cache::RedisCacheStore"
}

4.7.12 cache_cleanup.active_support

Cet événement est émis uniquement lors de l'utilisation de MemoryStore.

Clé Valeur
:store Nom de la classe du store
:size Nombre d'entrées dans le cache avant le nettoyage
{
  store: "ActiveSupport::Cache::MemoryStore",
  size: 9001
}

4.7.13 cache_prune.active_support

Cet événement est émis uniquement lors de l'utilisation de MemoryStore.

Clé Valeur
:store Nom de la classe du store
:key Taille cible (en octets) pour le cache
:from Taille (en octets) du cache avant l'élagage
{
  store: "ActiveSupport::Cache::MemoryStore",
  key: 5000,
  from: 9001
}

4.7.14 cache_exist?.active_support

Clé Valeur
:key Clé utilisée dans le store
:store Nom de la classe du store
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.8 Active Support — Messages

4.8.1 message_serializer_fallback.active_support

Clé Valeur
:serializer Serializer principal (prévu)
:fallback Serializer de secours (réel)
:serialized Chaîne sérialisée
:deserialized Valeur désérialisée
{
  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

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job

4.9.2 enqueue.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job

4.9.3 enqueue_retry.active_job

Clé Valeur
:job Objet Job
:adapter Objet QueueAdapter traitant le job
:error L'erreur qui a provoqué la nouvelle tentative
:wait Le délai de la nouvelle tentative

4.9.4 enqueue_all.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:jobs Un tableau d'objets Job

4.9.5 perform_start.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job

4.9.6 perform.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job
:db_runtime Temps passé à exécuter des requêtes de base de données en ms

4.9.7 retry_stopped.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job
:error L'erreur qui a provoqué la nouvelle tentative

4.9.8 discard.active_job

Clé Valeur
:adapter Objet QueueAdapter traitant le job
:job Objet Job
:error L'erreur qui a provoqué l'abandon

4.10 Action Cable

4.10.1 perform_action.action_cable

Clé Valeur
:channel_class Nom de la classe de canal
:action L'action
:data Un hash de données

4.10.2 transmit.action_cable

Clé Valeur
:channel_class Nom de la classe de canal
:data Un hash de données
:via Via

4.10.3 transmit_subscription_confirmation.action_cable

Clé Valeur
:channel_class Nom de la classe de canal

4.10.4 transmit_subscription_rejection.action_cable

Clé Valeur
:channel_class Nom de la classe de canal

4.10.5 broadcast.action_cable

Clé Valeur
:broadcasting Une diffusion nommée
:message Un hash de message
:coder Le codeur

4.11 Active Storage

4.11.1 preview.active_storage

Clé Valeur
:key Jeton sécurisé

4.11.2 transform.active_storage

4.11.3 analyze.active_storage

Clé Valeur
:analyzer Nom de l'analyseur, par exemple ffprobe

4.12 Active Storage — Service de stockage

4.12.1 service_upload.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service
:checksum Checksum pour assurer l'intégrité

4.12.2 service_streaming_download.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service

4.12.3 service_download_chunk.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service
:range Plage de bytes tentée à lire

4.12.4 service_download.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service

4.12.5 service_delete.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service

4.12.6 service_delete_prefixed.active_storage

Clé Valeur
:prefix Préfixe de clé
:service Nom du service

4.12.7 service_exist.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service
:exist Fichier ou blob existe ou non

4.12.8 service_url.active_storage

Clé Valeur
:key Jeton sécurisé
:service Nom du service
:url URL générée

4.12.9 service_update_metadata.active_storage

Cet événement est émis uniquement lors de l'utilisation du service Google Cloud Storage.

Clé Valeur
:key Jeton sécurisé
:service Nom du service
:content_type Champ HTTP Content-Type
:disposition Champ HTTP Content-Disposition

4.13 Action Mailbox

4.13.1 process.action_mailbox

Clé Valeur
:mailbox Instance de la classe Mailbox héritant de ActionMailbox::Base
:inbound_email Hash avec des données sur l'e-mail entrant en cours de traitement
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,
  inbound_email: {
    id: 1,
    message_id: "[email protected]",
    status: "processing"
  }
}

4.14 Railties

4.14.1 load_config_initializer.railties

Clé Valeur
:initializer Chemin de l'initialiseur chargé dans config/initializers

4.15 Rails

4.15.1 deprecation.rails

Clé Valeur
:message L'avertissement de dépréciation
:callstack D'où provient la dépréciation
:gem_name Nom de la gemme signalant la dépréciation
:deprecation_horizon Version où le comportement déprécié sera supprimé

5 Exceptions

Si une exception se produit pendant une instrumentation, la charge utile inclura des informations à ce sujet.

Clé Valeur
:exception Un tableau de deux éléments. Nom de la classe de l'exception et le message
:exception_object L'objet d'exception

6 Création d'événements personnalisés

Ajouter vos propres événements est également facile. Active Support s'occupera de tout le travail lourd pour vous. Il suffit d'appeler ActiveSupport::Notifications.instrument avec un name, payload et un bloc. La notification sera envoyée après que le bloc se termine. Active Support générera les temps de début et de fin, et ajoutera l'ID unique de l'instrumenteur. Toutes les données transmises à l'appel instrument feront partie de la charge utile. Voici un exemple :

ActiveSupport::Notifications.instrument "my.custom.event", this: :data do
  # effectuez vos actions personnalisées ici
end

Maintenant, vous pouvez écouter cet événement avec :

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

Vous pouvez également appeler instrument sans passer de bloc. Cela vous permet d'utiliser l'infrastructure d'instrumentation pour d'autres utilisations de messagerie.

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

Vous devez suivre les conventions de Rails lors de la définition de vos propres événements. Le format est : event.library. Si votre application envoie des tweets, vous devez créer un événement nommé tweet.twitter.

Retour d'information

Vous êtes encouragé à contribuer à l'amélioration de la qualité de ce guide.

Veuillez contribuer si vous trouvez des fautes de frappe ou des erreurs factuelles. Pour commencer, vous pouvez lire notre contribution à la documentation section.

Vous pouvez également trouver du contenu incomplet ou des informations qui ne sont pas à jour. Veuillez ajouter toute documentation manquante pour la version principale. Assurez-vous de vérifier Edge Guides d'abord pour vérifier si les problèmes ont déjà été résolus ou non sur la branche principale. Consultez les Directives des guides Ruby on Rails pour le style et les conventions.

Si pour une raison quelconque vous repérez quelque chose à corriger mais ne pouvez pas le faire vous-même, veuillez ouvrir un problème.

Et enfin, toute discussion concernant la documentation de Ruby on Rails est la bienvenue sur le Forum officiel de Ruby on Rails.