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

# Benutzerdefinierte Instrumentierung für Node.js

<Note>
  🛟 Zögern Sie nicht, uns zu [kontaktieren](mailto:support@appsignal.com), falls Sie beim
  Implementieren benutzerdefinierter Instrumentierungen auf Probleme stoßen. Wir helfen Ihnen gerne!
</Note>

Die Einbeziehung benutzerdefinierter Instrumentierung in Ihre Anwendung kann nützlich sein, um die spezifischen Codezeilen zu identifizieren, die Performance-Probleme verursachen. AppSignal bietet [Helper](#helpers), mit denen Sie relevante Daten über den Zustand Ihrer Anwendung neben Performance-Metriken anzeigen können, um die Ursachen von Performance-Problemen Ihrer Anwendung zu identifizieren.

## Einrichtung

Um die Hilfsfunktionen von AppSignal in Ihrer Instrumentierung zu verwenden, müssen Sie zuerst [`opentelemetry` importieren und ein Tracer-Objekt definieren](#import-opentelemetry-and-define-tracer). Abhängig von Ihrer Instrumentierung müssen Sie möglicherweise auch [zusätzliche Spans erstellen](#spans).

Unsere [Beispiel-Anwendungsfälle](#example-use-cases) zeigen, wie Sie Tracer, Spans und Helper verwenden können, um Ihre benutzerdefinierte Instrumentierung zu erstellen.

### OpenTelemetry importieren und Tracer definieren

Die AppSignal-Integration für Node.js verwendet OpenTelemetry-Tracer-Objekte. Diese Tracer enthalten verschiedene Funktionen zum Erstellen benutzerdefinierter Instrumentierungen.

Der Tracer stellt Funktionen zum Erstellen und Erzeugen neuer Spans bereit. Diese Dokumentation beschreibt, wie Sie Tracer und Spans verwenden können, um Ihre benutzerdefinierte Integration zu implementieren.

Sie müssen zuerst das trace-Objekt aus `@opentelemetry/api` importieren, bevor Sie mit Tracern und Spans arbeiten können. Durch den Aufruf der Funktion `getTracer` am trace-Objekt kann ein neues Tracer-Objekt erstellt werden. Sie müssen Ihrem Tracer-Objekt in dieser Funktion einen Namen geben, wie im untenstehenden Beispiel, in dem die Funktion `getTracer` verwendet wird, um einen Tracer mit dem Namen `"my interesting app"` zu definieren.

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

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

### Spans

Ein Span ist der Name des Objekts, das wir verwenden, um Daten über die Performance Ihrer Anwendung, etwaige Fehler und den umgebenden Kontext zu erfassen. Ein Span ist Teil eines umfassenderen Trace, einer hierarchischen Darstellung des Datenflusses durch Ihre Anwendung. Spans verfolgen die Start- und Endzeit eines Ereignisses sowie weitere Informationen wie den Namen oder andere damit zusammenhängende Daten.

Mehr über Spans erfahren Sie in der [OpenTelemetry Tracing Dokumentation](https://opentelemetry.io/docs/instrumentation/js/api/tracing/).

### Einen aktiven Span erstellen

Neue Spans können über das [trace-Objekt](#import-opentelemetry-and-define-tracer) aufgerufen werden. In einem Express- oder Koa-Handler instrumentierter Code befindet sich bereits in einem Span. Sie können neue Spans erstellen, indem Sie die Funktion `startActiveSpan()` am Tracer-Objekt aufrufen. Neu erstellte Spans sind die Kinder des Spans, in dem sie erstellt wurden, sofern einer existiert. Sie können Child-Spans verwenden, um die Performance von Aufgaben zu messen, die innerhalb eines Parent-Spans ausgeführt werden.

Sie sollten Ihrem Span einen Namen geben, der seinen Zweck verdeutlicht. Führen Sie alle Aufgaben, die Sie überwachen möchten, innerhalb der Funktion `startActiveSpan()` aus, wie im folgenden Beispiel.

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

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

Nach Abschluss der Aufgabe müssen Sie den Span schließen: `span.end()`

### Beispiel-Anwendungsfälle

Bei der Implementierung benutzerdefinierter Instrumentierung möchten Sie möglicherweise das Verhalten bestimmter Funktionen verstehen, z. B. wie lange ihre Ausführung dauert.

#### Helper verwenden

Im folgenden Beispiel sind wir an der Performance unseres „order-coffee"-GET-Endpunkts für verschiedene Kaffeeröstungen interessiert. Um dies zu untersuchen, verwenden wir die Funktion `setAttribute`, um einen [Tag](#tag) namens flavor zu erstellen, dessen Wert wir aus den Request-Parametern abrufen.

**Hinweis:** Da dies innerhalb eines Express-Request-Handlers geschieht, wurde bereits ein Root-Span erstellt.

<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>

Um tiefere Einblicke in die Performance unseres Codes zu erhalten, können wir Child-Spans verwenden, um Funktionen zu untersuchen, die innerhalb unseres Express-Handlers aufgerufen werden.

Der folgende Code erstellt einen Child-Span des `"picking coffee beans"`-Spans, der in der Funktion `pickCoffeeBeans` definiert ist.

Sobald das Attribut zugewiesen und alle Funktionen ausgeführt wurden, beenden wir den Span mit `.end()`, um sicherzustellen, dass AppSignal die Start- und Endzeit sowie die zugewiesenen Attribute erhält:

<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>

In AppSignal können wir Performance-Daten für diese Funktion sehen. Wir können die Tags roast und batch verwenden, um die Daten zu filtern und tiefere Einblicke zu erhalten, welche Parameter potenziell beeinflussen, wie sich der Code unserer Anwendung verhält.

<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="Screenshot der Tags" width="933" height="329" data-path="assets/images/screenshots/node/node-instrumentation-sample.png" />

#### Aktive Spans

Während Tags hilfreich sind, um Performance-Unterschiede in derselben Funktion zu analysieren, geben sie uns keinen Einblick in die Performance von Funktionen, die innerhalb unserer Funktion aufgerufen werden.

Um uns tiefere Einblicke in das zu geben, was innerhalb von `pickCoffeeBeans()` passiert, erstellen wir einen neuen `activeSpan` und nennen ihn „picking coffee beans". Die gesamte Logik, die wir verfolgen möchten, wird innerhalb einer async-Funktion ausgeführt.

Wir `await` das Promise, das von `retrieveDrinkTypes()` zurückgegeben wird, damit wir seine Performance als Child-Span des `"picking coffee beans"`-Spans verfolgen können, den wir in `pickCoffeeBeans()` erstellt haben.

<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>

Mit dieser Instrumentierung liefert AppSignal Einblicke in die Performance von `pickCoffeeBeans()`, einschließlich der Performance-Daten der Funktion `retrieveDrinkTypes()`, was tiefere Einblicke in die Faktoren bietet, die die Gesamt-Performance einer Funktion beeinflussen.

## Helper

<Warning>
  Daten, die an AppSignal gesendet werden, dürfen keine personenbezogenen Daten wie Namen, E-Mail-Adressen usw. enthalten. Es liegt in Ihrer Verantwortung sicherzustellen, dass die Daten Ihrer Anwendung bereinigt werden, bevor sie an AppSignal weitergeleitet werden. Wenn die Identifizierung einer Person erforderlich ist, muss Ihre Anwendung alternative Identifikationsformen wie eine Benutzer-ID, einen Hash oder ein Pseudonym verwenden.
</Warning>

Um Hilfsfunktionen zu verwenden, müssen Sie diese zuerst aus `@appsignal/nodejs` importieren. Im folgenden Beispiel wird der Namespace, in dem der Code ausgeführt wird, an AppSignal gemeldet. Alle verfügbaren Hilfsfunktionen sind in der [folgenden Dokumentation](/#helper-functions) aufgeführt.

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

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

Alle verfügbaren Hilfsfunktionen für benutzerdefinierte Instrumentierungs-Attribute sind in der [Liste unten](#helper-functions) aufgeführt.

### Hilfsfunktionen

<Tip>
  Die folgenden Code-Snippets für die Helper gehen davon aus, dass Ihr Code bereits instrumentiert wird (z. B. innerhalb eines Express- oder Koa-Request-Handlers). Wenn Ihr Code noch nicht instrumentiert ist, müssen Sie [einen Span erstellen](#spans) und die Helper darin verwenden.
</Tip>

* [Namespace](#namespace)
* [Tag](#tag)
* [Request-Parameter](#request-parameters)
* [Session-Daten setzen](#set-session-data)
* [Request-Header](#request-headers)
* [Root Name](#root-name)
* [Custom Data](#custom-data)
* **[Child Span Helper:](#child-span-helpers)**
  * [Kategorie](#category)
  * [Name](#name)
  * [Body](#body)

### Namespace

Setzt den String-Wert des Namespace des Root-Spans.

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

### Tag

Setzt einen Tag, z. B. aus einem Request-Parameter, der als Filter innerhalb der AppSignal-Anwendung verwendet werden kann. Im folgenden Beispiel erstellen wir einen Tag namens color mit dem Wert blue. Sie können Tags mit Namen konfigurieren, die für den Kontext Ihrer Anwendung relevant sind.

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

### Request-Parameter

Ein Objekt, das nach JSON serialisierbar ist. Eingehende Request-Parameter, Request-Body und Query-Parameter.

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

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

### Session-Daten setzen

Ein Objekt, das nach JSON serialisierbar ist.

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

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

### Request-Header

Ein String, der den Header-Wert enthält.

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

### Root Name

Ermöglicht es Ihnen, den Namen des Trace festzulegen. Samples werden anhand ihres Trace-Namens in Actions gruppiert.

<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>

#### Beispiel-Anwendungsfall

Ihre Anwendung hat einen Endpunkt namens `GET /coffee`.

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

Alle Anfragen an diesen Endpunkt generieren Samples namens `GET /coffee`, aber Ihr Endpunkt verarbeitet mehrere Actions: `coffee?action=buy` und `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 ohne Root Name" width="1030" height="640" data-path="assets/images/screenshots/node/span-without-root-name.png" />

Obwohl alle den Endpunkt `GET /coffee` verwenden, sind sie konzeptionell sehr unterschiedlich, daher wäre es sinnvoll, dass sie in AppSignal separat gruppiert werden, anstatt im selben `GET /coffee`-Sample. Dazu können Sie den Helper `setRootName()` verwenden:

<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>

Die Verwendung von `setRootName` ändert den Namen des Root-Spans und gruppiert die Samples für die Anfragen `coffee?action=buy` und `coffee?action=sell` in separate Actions:

<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="Root Name Span" width="1052" height="780" data-path="assets/images/screenshots/node/root-name-span.png" />

### Custom Data

Ein Objekt, das nach JSON serialisierbar ist.

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

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

### Child Span Helper

Die folgenden Helper gelten nur für Child-Spans. Um einen Child-Span zu erstellen, müssen Sie einen neuen [Active Span](#creating-an-active-span) erstellen.

Neue Spans sind automatisch Kinder ihres Parent-Spans.

#### Kategorie

Ein String, der die Kategorie des Child-Spans enthält. Der Name sollte `.` verwenden, um die hierarchische Vererbung der Kategorie auszudrücken. Zum Beispiel: `cafe.coffee.cupsize`

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

#### Name

Ein String, der den Titel des Event-Timelines des Child-Spans enthält.

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

#### Body

<Warning>
  🔐 Senden Sie keine <strong>personenbezogenen Daten (Personal Identifiable Information, PII)</strong> an AppSignal. Filtern Sie PII (z. B. Namen, E-Mail-Adressen) und verwenden Sie stattdessen eine ID, einen Hash oder einen pseudonymisierten Bezeichner. <br /> <br /> Für <strong>HIPAA-pflichtige Stellen</strong> finden Sie weitere Informationen zum Abschluss eines Business Associate Agreement (BAA) in unserer <a href="/support/business-add-ons">Business Add-Ons-Dokumentation</a>.
</Warning>

Der Body des Spans kann zusätzliche Informationen über das Ereignis enthalten, wie den HTTP-Request, den verbundenen Host usw. Stellen Sie sicher, dass Sie die Informationen bereinigen, bevor Sie sie dem Span hinzufügen, damit keine personenbezogenen Daten an AppSignal gesendet werden. Diese Informationen sind für den Span sichtbar, wenn Sie mit der Maus über die Event-Timeline fahren.

Um SQL-Abfragen im Body des Spans zu speichern, verwenden Sie stattdessen den [`setSqlBody`-Helper](#sql-body).

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

#### SQL body

<Tip>
  Verfügbar seit Node.js-Paket 3.0.25.
</Tip>

Legen Sie eine SQL-Abfrage als Body des Spans fest, wie er in der Performance-Event-Timeline in der Detailansicht des Incident-Samples erscheint. Dies ist ähnlich dem [`setBody`-Helper](#body), ist aber auf SQL-Abfragen spezialisiert. Jede SQL-Abfrage, die mit diesem Attribut als Body gesetzt wird, wird bereinigt, um zu vermeiden, dass PII (Personal Identifiable Information)-Daten an unsere Server gesendet werden.

Weitere Informationen zur Funktionsweise des Body-Attributs finden Sie im [`setBody`-Helper](#body).

Wenn sowohl die Helper `setBody` als auch `setSqlBody` für denselben Span aufgerufen werden, ist der Wert des `setSqlBody`-Helpers führend und der Wert des `setBody`-Helpers wird ignoriert.

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