> ## 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 Node.js

<Note>
  🛟 N'hésitez pas à [nous contacter](mailto:support@appsignal.com) si vous rencontrez
  des problèmes lors de la mise en œuvre d'instrumentations personnalisées. Nous sommes là pour vous aider !
</Note>

L'inclusion d'une instrumentation personnalisée dans votre application peut être utile pour identifier les lignes de code spécifiques qui causent des problèmes de performance. AppSignal fournit des [helpers](#helpers), qui vous permettent d'afficher des données pertinentes sur l'état de votre application aux côtés des métriques de performance, afin de vous aider à identifier les causes profondes de tout problème de performance que votre application pourrait rencontrer.

## Configuration

Pour utiliser les fonctions helper d'AppSignal dans votre instrumentation, vous devez d'abord [importer `opentelemetry` et définir un objet tracer](#import-opentelemetry-and-define-tracer). Selon votre instrumentation, vous devrez peut-être également [créer des spans supplémentaires](#spans).

Nos [exemples de cas d'usage](#example-use-cases) montrent comment vous pouvez utiliser les tracers, les spans et les helpers pour créer votre instrumentation personnalisée.

### Importer OpenTelemetry et définir un Tracer

L'intégration AppSignal pour Node.js utilise les objets tracer d'OpenTelemetry. Ces tracers contiennent diverses fonctions pour créer des instrumentations personnalisées.

Le Tracer expose des fonctions pour créer de nouveaux spans. Cette documentation décrit comment vous pouvez utiliser les tracers et les spans pour implémenter votre intégration personnalisée.

Vous devez d'abord importer l'objet trace depuis `@opentelemetry/api` avant de travailler avec les tracers et les spans. En invoquant la fonction `getTracer` sur l'objet trace, un nouvel objet tracer peut être créé. Vous devez donner un nom à votre objet tracer dans cette fonction, comme dans l'exemple ci-dessous, où la fonction `getTracer` est utilisée pour définir un tracer avec le nom `"my interesting app"`.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { trace } from "@opentelemetry/api";

  const tracer = trace.getTracer("my-interesting-app");
  ```
</CodeGroup>

### Spans

Un span est le nom de l'objet que nous utilisons pour capturer des données sur les performances de votre application, les éventuelles erreurs et le contexte qui les entoure. Un span fait partie d'une trace plus large, une représentation hiérarchique du flux de données à travers votre application. Les spans gardent la trace de l'heure de début et de fin d'un événement, ainsi que d'autres informations, telles que le nom ou d'autres données qui s'y rapportent.

Vous pouvez en savoir plus sur les spans dans la [documentation de traçage OpenTelemetry](https://opentelemetry.io/docs/instrumentation/js/api/tracing/).

### Créer un span actif

De nouveaux spans peuvent être invoqués via l'[objet trace](#import-opentelemetry-and-define-tracer). Le code instrumenté à l'intérieur d'un handler Express ou Koa sera déjà à l'intérieur d'un span. Vous pouvez créer de nouveaux spans en invoquant la fonction `startActiveSpan()` sur l'objet tracer. Les spans nouvellement créés seront l'enfant du span dans lequel ils ont été créés, s'il en existe un. Vous pouvez utiliser des spans enfants pour mesurer les performances des tâches exécutées depuis un span parent.

Vous devez donner à votre span un nom qui rend son objectif clair. Exécutez toutes les tâches que vous souhaitez surveiller dans la fonction `startActiveSpan()`, comme dans l'exemple ci-dessous.

<CodeGroup>
  ```javascript Node.js theme={null}
  tracer.startActiveSpan("printing coffee beans", async (span) => {
    const coffeeBeans = await fetchAllCoffeeBeans();
    console.log(coffeeBeans);

    span.end();
  });
  ```
</CodeGroup>

Une fois la tâche terminée, vous devez fermer le span : `span.end()`

### Exemples de cas d'usage

Lors de la mise en œuvre d'une instrumentation personnalisée, vous pouvez être curieux de comprendre le comportement de fonctions particulières, par exemple combien de temps elles mettent à s'exécuter.

#### Utilisation des helpers

Dans l'exemple ci-dessous, nous nous intéressons aux performances de notre endpoint GET « order-coffee » pour différentes torréfactions de café. Pour étudier cela, nous utilisons la fonction `setAttribute` pour créer un [tag](#tag) appelé flavor, dont la valeur est récupérée depuis les paramètres de la requête.

**Note :** étant donné qu'il s'agit d'un handler de requête Express, un span racine a déjà été créé.

<CodeGroup>
  ```javascript Node.js theme={null}
  app.get('/order-coffee', (req, res) => {
      const roast = req.params.roast
      setTag("roast", roast)

      const coffeeBeans = pickCoffeeBeans(roast)
      prepareCoffeeBag(coffeeBeans)
    })
  }
  ```
</CodeGroup>

Pour obtenir des informations plus approfondies sur les performances de notre code, nous pouvons utiliser des spans enfants pour inspecter les fonctions appelées dans notre handler Express.

Le code ci-dessous crée un span enfant du span `"picking coffee beans"` défini dans la fonction `pickCoffeeBeans`.

Une fois l'attribut assigné et toutes les fonctions exécutées, nous appelons `.end()` sur le span pour nous assurer qu'AppSignal reçoit l'heure de début et de fin ainsi que les attributs que nous avons assignés :

<CodeGroup>
  ```javascript Node.js theme={null}
  function pickCoffeeBeans(roast) {
    tracer.startActiveSpan("picking coffee beans", async (span) => {
      const roastBrands = {
        light: "Caffinated Cloud",
        medium: "Feeling The Buzz",
        dark: "The Jitters",
      };

      const roastBrand = roastBrands[roast];

      setTag("brand", roastBrand);
      await retrieveDrinkTypes(roastBrand);
      span.end();
    });
  }
  ```
</CodeGroup>

Dans AppSignal, nous pouvons voir les données de performance pour cette fonction. Nous pouvons utiliser les tags roast et batch pour filtrer les données et obtenir des informations plus approfondies sur les paramètres qui pourraient influencer le comportement du code de notre application.

<img src="https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/node-instrumentation-sample.png?fit=max&auto=format&n=4TRZP0Sq9Zq7PAPW&q=85&s=4afd1219ca91a383ca1519c779eca87b" alt="Capture d'écran des tags" width="933" height="329" data-path="assets/images/screenshots/node/node-instrumentation-sample.png" />

#### Spans actifs

Bien que les tags soient utiles pour analyser les différences de performance sur une même fonction, ils ne nous donnent pas d'aperçu des performances des fonctions appelées depuis notre fonction.

Pour obtenir plus d'informations sur ce qui se passe à l'intérieur de `pickCoffeeBeans()`, nous créons un nouveau `activeSpan` et le nommons « picking coffee beans ». Toute la logique que nous souhaitons suivre est exécutée à l'intérieur d'une fonction async.

Nous attendons (`await`) la promesse retournée par `retrieveDrinkTypes()`, afin de pouvoir suivre ses performances en tant que span enfant du span `"picking coffee beans"` que nous avons créé dans `pickCoffeeBeans()`.

<CodeGroup>
  ```javascript Node.js theme={null}
  function pickCoffeeBeans(roast) {
    tracer.startActiveSpan("picking coffee beans", async (span) => {
      const roastBrands = {
        light: "Caffinated Cloud",
        medium: "Feeling The Buzz",
        dark: "The Jitters",
      };

      const roastBrand = roastBrands[roast];
      await retrieveDrinkTypes(roastBrand);
      span.end();
    });
  }

  function retrieveDrinkTypes(roastBrand) {
    return new Promise((resolve) => {
      const span = tracer.startActiveSpan("Fetching coffee types");

      const brandDrinks = {
        "Caffinated Cloud": ["americano", "capuccino"],
        "Feeling The Buzz": ["capuccino", "latte"],
        "The Jitters": ["espresso"],
      };

      const drinkTypes = brandDrinks[roastBrand];

      // we want to give our Barista's some time prepare the machine
      setTimeout(() => {
        resolve(drinkTypes);
        span.end();
      }, 60000);
    });
  }
  ```
</CodeGroup>

Avec cette instrumentation, AppSignal fournira des informations sur les performances de `pickCoffeeBeans()`, ce qui inclura les données de performance de la fonction `retrieveDrinkTypes()`, offrant ainsi une meilleure compréhension des facteurs qui impactent les performances globales d'une fonction.

## Helpers

<Warning>
  Les données envoyées à AppSignal ne doivent contenir aucune donnée personnelle, telle que
  des noms, des adresses e-mail, etc. Il est de votre responsabilité de vous assurer que les
  données de votre application sont assainies avant d'être transmises à AppSignal. Lorsqu'il est
  nécessaire d'identifier une personne, votre application doit utiliser d'autres formes
  d'identification telles qu'un identifiant utilisateur, un hash ou un pseudonyme.
</Warning>

Pour utiliser les fonctions helper, vous devez d'abord les importer depuis `@appsignal/nodejs`. Dans l'exemple ci-dessous, le namespace dans lequel le code est exécuté est signalé à AppSignal. Toutes les fonctions helper disponibles sont décrites dans la [documentation ci-dessous](/#helper-functions).

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setNamespace } from "@appsignal/nodejs";

  setNamespace("web");
  ```
</CodeGroup>

Toutes les fonctions helper disponibles pour les attributs d'instrumentation personnalisée sont décrites dans la [liste ci-dessous](#helper-functions).

### Fonctions helper

<Tip>
  Les extraits de code pour les helpers ci-dessous supposent que votre code est déjà
  instrumenté (par exemple, à l'intérieur d'un handler de requête Express ou Koa). Si votre
  code n'est pas déjà instrumenté, vous devez [créer un span](#spans) et utiliser les
  helpers à l'intérieur de celui-ci.
</Tip>

* [Namespace](#namespace)
* [Tag](#tag)
* [Paramètres de requête](#request-parameters)
* [Définir les données de session](#set-session-data)
* [En-têtes de requête](#request-headers)
* [Nom racine](#root-name)
* [Données personnalisées](#custom-data)
* **[Helpers de span enfant :](#child-span-helpers)**
  * [Catégorie](#category)
  * [Nom](#name)
  * [Corps](#body)

### Namespace

Définit la valeur de chaîne du namespace du span racine.

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { setNamespace } from "@appsignal/nodejs";
  setNamespace("app");
  ```
</CodeGroup>

### Tag

Définit un tag, par exemple à partir d'un paramètre de requête, qui peut être utilisé comme filtre dans l'application AppSignal. Dans l'exemple ci-dessous, nous créons un tag appelé color avec la valeur blue. Vous pouvez configurer les tags avec des noms pertinents pour le contexte de votre application.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setTag } from "@appsignal/nodejs";
  setTag("color", "blue");
  ```
</CodeGroup>

### Paramètres de requête

Un objet sérialisable en JSON. Les paramètres de requête entrants, le corps de la requête et les paramètres de requête.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setParams } from "@appsignal/nodejs";

  const exampleParams = { action: "delete" };
  setParams(exampleParams);
  ```
</CodeGroup>

### Définir les données de session

Un objet sérialisable en JSON.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setSessionData } from "@appsignal/nodejs";

  const exampleSessionData = { locale: "en-GB" };
  setSessionData(exampleSessionData);
  ```
</CodeGroup>

### En-têtes de requête

Une chaîne contenant la valeur de l'en-tête.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setHeader } from "@appsignal/nodejs";
  setHeader("Content-type", "application/json");
  ```
</CodeGroup>

### Nom racine

Vous permet de définir le nom de la trace. Les échantillons sont regroupés en actions en fonction de leur nom de trace.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setRootName } from "@appsignal/nodejs";

  // somewhere in your code where there's an active span...
  setRootName("The action name");
  ```
</CodeGroup>

#### Exemple de cas d'usage

Votre application a un endpoint appelé `GET /coffee`.

<CodeGroup>
  ```javascript Node.js theme={null}
  app.get("/coffee", (req, res) => {
    // ...
  });
  ```
</CodeGroup>

Toutes les requêtes vers cet endpoint généreront des échantillons appelés `GET /coffee`, mais votre endpoint gère plusieurs actions : `coffee?action=buy` et `coffee?action=sell`.

<img src="https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/span-without-root-name.png?fit=max&auto=format&n=4TRZP0Sq9Zq7PAPW&q=85&s=c17dd17713da423bac8d380df6274a1e" alt="Span sans nom racine" width="1030" height="640" data-path="assets/images/screenshots/node/span-without-root-name.png" />

Bien qu'elles utilisent toutes l'endpoint `GET /coffee`, elles sont conceptuellement très différentes et il serait donc logique qu'elles soient regroupées séparément dans AppSignal plutôt que dans le même échantillon `GET /coffee`. Pour ce faire, vous pouvez utiliser le helper `setRootName()` :

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setRootName } from "@appsignal/nodejs";

  app.get("/coffee", (req, res) => {
    if (req.query.action === "buy") {
      setRootName("Buy coffee");
      // ... buy coffee
    } else if (req.query.action === "sell") {
      setRootName("Sell coffee");
      // ... sell coffee
    }
  });
  ```
</CodeGroup>

L'utilisation de `setRootName` modifiera le nom du span racine, regroupant les échantillons des requêtes `coffee?action=buy` et `coffee?action=sell` dans des actions distinctes :

<img src="https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/root-name-span.png?fit=max&auto=format&n=4TRZP0Sq9Zq7PAPW&q=85&s=2d6521845df3d5bcd8938900b4b643ac" alt="Span avec nom racine" width="1052" height="780" data-path="assets/images/screenshots/node/root-name-span.png" />

### Données personnalisées

Un objet sérialisable en JSON.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setCustomData } from "@appsignal/nodejs";

  const exampleCustomData = { stroopwaffle: "true", coffee: "false" };
  setCustomData(exampleCustomData);
  ```
</CodeGroup>

### Helpers de span enfant

Les helpers suivants ne s'appliquent qu'aux spans enfants. Pour créer un span enfant, vous devez créer un nouveau [span actif](#creating-an-active-span).

Les nouveaux spans sont automatiquement enfants de leur span parent.

#### Catégorie

Une chaîne contenant la catégorie du span enfant. Le nom doit utiliser `.` pour exprimer l'héritage hiérarchique de la catégorie. Par exemple : `cafe.coffee.cupsize`

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setCategory } from "@appsignal/nodejs";
  setCategory("category.name");
  ```
</CodeGroup>

#### Nom

Une chaîne contenant le titre de la chronologie d'événements du span enfant.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setName } from "@appsignal/nodejs";
  setName("Users query");
  ```
</CodeGroup>

#### Corps

<Warning>
  🔐 N'envoyez pas d'<strong>informations personnelles identifiables (PII)</strong> à AppSignal. Filtrez les PII (par exemple, noms, e-mails) et utilisez un identifiant, un hash ou un identifiant pseudonymisé à la place. <br /> <br /> Pour les <strong>entités couvertes par la HIPAA</strong>, plus d'informations sur la signature d'un Business Associate Agreement (BAA) sont disponibles dans notre <a href="/support/business-add-ons">documentation Business Add-Ons</a>.
</Warning>

Le corps du span peut inclure des informations supplémentaires sur l'événement, comme la requête HTTP, l'hôte connecté, etc. Veillez à assainir les informations avant de les ajouter au span afin qu'aucune information personnelle identifiable ne soit envoyée à AppSignal. Ces informations seront visibles pour le span lors du survol de la chronologie d'événements.

Pour stocker des requêtes SQL dans le corps du span, veuillez utiliser le [helper `setSqlBody`](#sql-body) à la place.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setBody } from "@appsignal/nodejs";
  setBody("Span body");
  ```
</CodeGroup>

#### Corps SQL

<Tip>
  Disponible depuis le package Node.js 3.0.25.
</Tip>

Définir une requête SQL comme corps du span tel qu'elle apparaît dans la chronologie des événements de performance dans la vue détaillée d'un échantillon d'incident. Ceci est similaire au [helper `setBody`](#body), mais spécialisé pour les requêtes SQL. Toute requête SQL définie comme corps avec cet attribut sera assainie pour éviter d'envoyer des données PII (Personal Identifiable Information) à nos serveurs.

Consultez le [helper `setBody`](#body) pour plus de détails sur le fonctionnement de l'attribut body.

Lorsque les helpers `setBody` et `setSqlBody` sont appelés sur le même span, la valeur du helper `setSqlBody` prévaut et la valeur du helper `setBody` sera ignorée.

<CodeGroup>
  ```javascript Node.js theme={null}
  import { setSqlBody } from "@appsignal/nodejs";
  setSqlBody("SELECT * FROM users");
  ```
</CodeGroup>
