> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Instrumentation personnalisée pour Elixir

Pour identifier quels morceaux de code spécifiques causent des problèmes de performance,
il est utile d'ajouter de l'instrumentation personnalisée à votre application. Cela
nous permet de créer de meilleures décompositions de quel code s'exécute le plus lentement et de quel type
d'action a pris le plus de temps.

L'instrumentation personnalisée est possible de deux façons : en utilisant des décorateurs de fonction et
des fonctions d'aide à l'instrumentation. Les décorateurs de fonction sont les plus simples à utiliser,
mais sont moins flexibles que les fonctions d'aide à l'instrumentation.

Ce court guide vous aidera à mettre en place l'instrumentation personnalisée. Plus de détails sur
l'utilisation de certains helpers se trouvent dans les Hex docs du [paquet
AppSignal](https://hexdocs.pm/appsignal/).

<Tip>
  **Remarque** : Assurez-vous d'avoir [intégré
  AppSignal](/elixir/instrumentation/integrating-appsignal) avant d'ajouter
  de l'instrumentation personnalisée à votre application si elle n'est pas automatiquement
  intégrée par l'une de nos [intégrations](/elixir/integrations) prises en charge.
</Tip>

<Tip>
  **Remarque** : Cette page décrit uniquement comment ajouter de l'instrumentation de performance à
  votre code. Pour suivre les erreurs, veuillez lire notre guide de [gestion des
  exceptions](/elixir/instrumentation/exception-handling).
</Tip>

## `Appsignal.instrument/2-3`

La fonction `instrument/2` est utilisée pour ajouter de l'instrumentation en enveloppant un morceau
de code dans un span. Un span devient finalement un échantillon, ou un événement dans l'échantillon
d'un autre span dans AppSignal.

### Ajouter des spans aux traces

Dans l'exemple suivant, nous avons un contrôleur Phoenix avec une fonction `index/2`
qui appelle une fonction lente. La fonction `slow` est instrumentée à l'aide de
la fonction `Appsignal.instrument/2` qui l'enregistre comme un événement distinct dans
cette requête Phoenix. Elle apparaîtra sur AppSignal.com dans la timeline des événements de
cet échantillon pour mieux comprendre où le plus de temps a été passé pendant la
requête.

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule AppsignalPhoenixExampleWeb.PageController do
    use AppsignalPhoenixExampleWeb, :controller

    def index(conn, _params) do
      slow()
      render(conn, "index.html")
    end

    defp slow do
      Appsignal.instrument("slow", fn ->
        :timer.sleep(1000)
      end)
    end
  end
  ```
</CodeGroup>

Ici, nous enveloppons le contenu de notre fonction par un appel à `Appsignal.instrument3`,
et nous passons `"slow"` comme nom pour l'événement.

### Démarrer de nouvelles traces

Dans l'exemple Phoenix, une trace AppSignal a déjà été démarrée, grâce au
support natif de Phoenix dans le paquet AppSignal. Tous les frameworks
et paquets ne sont pas pris en charge directement et ne démarrent pas automatiquement
des traces. Il en va de même pour vos propres applications Elixir pures.

Comme pour l'ajout de spans à des traces déjà instrumentées, un nouveau span racine est
créé à l'aide de la fonction `Appsignal.instrument/2` :

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule AppsignalElixirExample do
    def example_fn do
      Appsignal.instrument("instrument", fn ->
        :timer.sleep(500)
      end)
    end
  end
  ```
</CodeGroup>

Cet exemple crée un échantillon nommé « instrument » dans le namespace « background »
dans AppSignal. Le nom sera également utilisé comme nom de catégorie pour le span
principal. Pour utiliser un autre nom de catégorie, utilisez `instrument/3` à la place :

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule AppsignalElixirExample do
    def example_fn do
      Appsignal.instrument("instrument", "call.instrument", fn ->
        :timer.sleep(500)
      end)
    end
  end
  ```
</CodeGroup>

Lorsque vous passez une fonction qui prend un argument, la fonction `instrument/2-3` l'appelle avec le span ouvert pour permettre une personnalisation supplémentaire. Consultez la documentation sur hex.pm pour [toutes les fonctions Span disponibles](https://hexdocs.pm/appsignal/Appsignal.Span.html).

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule AppsignalElixirExample do
    def example_fn do
      Appsignal.instrument("Build complicated SQL query", "prepare_query.sql", fn span ->
        # Example of building a complex SQL query in the instrument block and performing it
        query = "SOME complicate SQL query"
        # The body is only set here because it's the value being calculated and instrumented in this function
        Appsignal.Span.set_sql(span, query)
        Database.perform_query(query)
      end)
    end
  end
  ```
</CodeGroup>

### Gestion des exceptions {/* id: helper-exception-handling */}

Pour signaler des erreurs en utilisant l'instrumentation personnalisée, veuillez lire notre guide de [gestion
des exceptions](/elixir/instrumentation/exception-handling).

## Décorateurs de fonction

En utilisant le module décorateur `Appsignal.Instrumentation.Decorators`, il est
possible d'ajouter de l'instrumentation personnalisée à vos applications Elixir sans
modifier le contenu des fonctions.

### Événements de transaction {/* id: decorator-transaction-events */}

Dans l'exemple suivant, nous avons un contrôleur Phoenix avec une fonction `index/2`
qui appelle une fonction lente. La fonction `slow` est instrumentée à l'aide du décorateur
AppSignal `transaction_event` qui l'enregistre comme un événement distinct dans cette requête
Phoenix. Elle apparaîtra sur AppSignal.com dans la timeline des événements de cet échantillon de
transaction pour donner plus d'informations sur l'endroit où le plus de temps a été passé pendant la requête.

<CodeGroup>
  ```elixir Elixir theme={null}
  # Phoenix controller example
  defmodule PhoenixExample.PageController do
    use PhoenixExample.Web, :controller
    # Include this
    use Appsignal.Instrumentation.Decorators

    def index(conn, _params) do
      slow()
      render conn, "index.html"
    end

    # Decorate this function to add custom instrumentation
    @decorate transaction_event()
    defp slow do
      :timer.sleep(1000)
    end
  end
  ```
</CodeGroup>

Si vous souhaitez regrouper certains événements sous le même groupe d'événements (d'autres
groupes sont `phoenix_controller`, `phoenix_render`, `ecto`, etc.), vous pouvez également
fournir un nom de groupe au décorateur `transaction_event`.

<CodeGroup>
  ```elixir Elixir theme={null}
  @decorate transaction_event("github_api")
  defp get_data_from_github do
    # Third-party API call
  end
  ```
</CodeGroup>

Cela créera un événement `get_data_from_github.github_api` dans la timeline
des événements. Pour plus d'informations sur la façon dont les noms d'événements sont utilisés, veuillez lire
nos [directives de nommage des événements](/api/event-names).

### Transactions {/* id: decorator-transactions */}

Dans l'exemple Phoenix, une transaction AppSignal a déjà été démarrée, grâce
au support natif de Phoenix dans le paquet AppSignal. Tous les frameworks
et paquets ne sont pas pris en charge directement et ne démarrent pas automatiquement de transactions.
Il en va de même pour vos propres applications Elixir pures.

Pour suivre les décorateurs `transaction_event`, nous devrons démarrer une
transaction AppSignal au préalable. Nous pouvons démarrer une transaction avec le
décorateur de fonction `transaction`.

<CodeGroup>
  ```elixir Elixir theme={null}
  # Pure Elixir example
  defmodule FunctionDecoratorsExample do
    # Include this
    use Appsignal.Instrumentation.Decorators

    # No transaction is started beforehand like in Phoenix, so we need to start
    # it ourselves.
    @decorate transaction()
    def call do
      slow()
      # ...
    end

    # Decorate this function to add custom instrumentation
    @decorate transaction_event()
    defp slow do
      :timer.sleep(1000)
    end
  end
  ```
</CodeGroup>

**Remarque** : Lorsque vous utilisez des applications Elixir pures, assurez-vous que l'application
AppSignal est démarrée avant de démarrer une transaction. Pour plus d'informations,
voyez comment
[intégrer AppSignal](/elixir/instrumentation/integrating-appsignal).

### Namespaces {/* id: decorator-namespaces */}

Pour différencier les requêtes HTTP et les jobs en arrière-plan, nous pouvons passer un
namespace à la transaction une fois que nous la démarrons.

Les deux namespaces suivants sont les namespaces officiels pris en charge par AppSignal.

* `http_request` - par défaut - est appelé le namespace « web »
* `background_job` - crée le namespace « background »

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule FunctionDecoratorsExample do
    # Include this
    use Appsignal.Instrumentation.Decorators

    # No namespace argument defaults to `:http_request`
    @decorate transaction()
    def web_function do
      # do stuff
    end

    # The "background" namespace
    @decorate transaction(:background_job)
    def background_function do
      # do stuff
    end
  end
  ```
</CodeGroup>

Pour plus d'informations sur ce que sont les namespaces, veuillez consulter notre
documentation sur les [namespaces](/application/namespaces).

### Namespaces personnalisés {/* id: decorator-custom-namespaces */}

Vous pouvez également créer vos propres namespaces pour suivre les transactions dans une partie distincte
de votre application, comme un panneau d'administration. Cela regroupera toutes les transactions
avec ce namespace dans une section distincte sur AppSignal.com afin que les contrôleurs d'administration lents
n'interfèrent pas avec les moyennes de vitesse de votre application.

<CodeGroup>
  ```elixir Elixir theme={null}
  @decorate transaction(:admin)
  def some_function do
    # do stuff
  end
  ```
</CodeGroup>

### Canaux Phoenix {/* id: decorator-phoenix-channels */}

Il existe un décorateur de fonction personnalisé pour les canaux Phoenix. Ce décorateur est destiné
à être placé avant la fonction `handle_in/3` d'un module `Phoenix.Channel`.

<CodeGroup>
  ```elixir Elixir theme={null}
  defmodule FunctionDecoratorsExample.MyChannel do
    # Include this
    use Appsignal.Instrumentation.Decorators

    # Add this channel function decorator
    @decorate channel_action()
    def handle_in("ping", _payload, socket) do
      # your code here..
    end
  end
  ```
</CodeGroup>

Les événements de canal seront affichés sous le namespace « background », montrant le
module du canal et l'argument d'action sur lequel il est utilisé.

## Créer et fermer manuellement des spans

Dans certains cas, il peut être utile de gérer manuellement les spans. Vous pouvez utiliser
l'API span pour instrumenter par exemple des tâches :

<CodeGroup>
  ```elixir Elixir theme={null}
  def index(conn, _params) do
    current = Appsignal.Tracer.current_span()
    fn ->
      span = "http_request"
      |> Appsignal.Tracer.create_span(current)
      |> Appsignal.Span.set_name("name")
      |> Appsignal.Span.set_attribute("appsignal:category", "category")
      :timer.sleep(1000)
      Appsignal.Tracer.close_span(span)
    end
    |> Task.async()
    |> Task.await()
    render(conn, "index.html")
  end
  ```
</CodeGroup>
