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

# Instrumentação personalizada para Node.js

<Note>
  🛟 Não hesite em [entrar em contato](mailto:support@appsignal.com) se você encontrar
  algum problema ao implementar instrumentações customizadas. Estamos aqui para ajudar!
</Note>

Incluir instrumentação personalizada na sua aplicação pode ser útil para identificar as linhas específicas de código que causam problemas de performance. O AppSignal fornece [helpers](#helpers), que permitem exibir dados relevantes sobre o estado da sua aplicação junto com métricas de performance, ajudando você a identificar as causas raiz de quaisquer problemas de performance que sua aplicação possa estar enfrentando.

## Configuração

Para usar as funções helper do AppSignal na sua instrumentação, primeiro você precisa [importar `opentelemetry` e definir um objeto tracer](#import-opentelemetry-and-define-tracer). Dependendo da sua instrumentação, talvez também seja necessário [criar spans adicionais](#spans).

Nossos [Exemplos de uso](#example-use-cases) demonstram como você pode usar tracers, spans e helpers para criar sua instrumentação personalizada.

### Importar OpenTelemetry e definir o Tracer

A integração do AppSignal para Node.js utiliza objetos tracer do OpenTelemetry. Esses tracers contêm várias funções para criar instrumentações personalizadas.

O Tracer expõe funções para criar novos spans. Esta documentação descreve como você pode usar tracers e spans para implementar sua integração personalizada.

Primeiro, você precisa importar o objeto trace de `@opentelemetry/api` antes de trabalhar com tracers e spans. Ao invocar a função `getTracer` no objeto trace, um novo objeto tracer pode ser criado. Você precisa dar um nome ao seu objeto tracer nesta função, como visto no exemplo abaixo, onde a função `getTracer` é usada para definir um tracer com o nome `"my interesting app"`.

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

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

### Spans

Um span é o nome do objeto que utilizamos para capturar dados sobre a performance da sua aplicação, quaisquer erros e qualquer contexto ao redor. Um span faz parte de um trace mais amplo, uma representação hierárquica do fluxo de dados pela sua aplicação. Spans mantêm registro do horário de início e fim de um evento, junto com outras informações, como o nome ou outros dados relacionados a ele.

Você pode ler mais sobre spans na [Documentação de Tracing do OpenTelemetry](https://opentelemetry.io/docs/instrumentation/js/api/tracing/).

### Criando um span ativo

Novos spans podem ser invocados via [objeto trace](#import-opentelemetry-and-define-tracer). Código instrumentado dentro de um handler de Express ou Koa já estará dentro de um span. Você pode criar novos spans invocando a função `startActiveSpan()` no objeto tracer. Spans recém-criados serão filhos do span no qual foram criados, se houver um. Você pode usar spans filhos para medir a performance de tarefas executadas dentro de um span pai.

Você deve dar ao seu span um nome que torne sua finalidade clara. Execute todas as tarefas que deseja monitorar dentro da função `startActiveSpan()`, como no exemplo abaixo.

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

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

Depois que a tarefa for concluída, você precisa fechar o span: `span.end()`

### Exemplos de uso

Ao implementar instrumentação personalizada, você pode querer entender o comportamento de funções específicas, por exemplo, quanto tempo elas levam para executar.

#### Usando helpers

No exemplo abaixo, estamos curiosos sobre a performance do nosso endpoint GET "order-coffee" para diferentes torras de café. Para investigar isso, usamos a função `setAttribute` para criar uma [tag](#tag) chamada flavor, cujo valor obtemos dos parâmetros da requisição.

**Nota:** Como isso está dentro de um handler de requisição do Express, um span raiz já foi criado.

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

Para obter insights mais profundos sobre a performance do nosso código, podemos usar spans filhos para inspecionar funções chamadas dentro do nosso handler do Express.

O código abaixo cria um span filho do span `"picking coffee beans"` definido na função `pickCoffeeBeans`.

Depois que o atributo for atribuído e todas as funções executadas, chamamos `.end()` no span para garantir que o AppSignal receba o horário de início e fim e os atributos que atribuímos:

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

No AppSignal, conseguimos ver dados de performance dessa função. Podemos usar as tags roast e batch para filtrar os dados e obter insights mais profundos sobre quais parâmetros potencialmente influenciam o comportamento do código da nossa aplicação.

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

#### Spans ativos

Embora as tags sejam úteis para analisar diferenças de performance na mesma função, elas não nos dão visibilidade sobre a performance de quaisquer funções chamadas a partir da nossa função.

Para obter mais insights sobre o que está acontecendo dentro de `pickCoffeeBeans()`, criamos um novo `activeSpan` e o nomeamos como "picking coffee beans". Toda a lógica que queremos rastrear é executada dentro de uma função async.

Usamos `await` na promise retornada por `retrieveDrinkTypes()`, para que possamos rastrear sua performance como um span filho do span `"picking coffee beans"` que criamos em `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>

Com essa instrumentação, o AppSignal fornecerá insights sobre a performance de `pickCoffeeBeans()`, o que incluirá os dados de performance da função `retrieveDrinkTypes()`, oferecendo maior visibilidade sobre quais fatores estão impactando a performance geral de uma função.

## Helpers

<Warning>
  Os dados enviados ao AppSignal não devem conter nenhum dado pessoal, como nomes,
  endereços de e-mail, etc. É responsabilidade sua garantir que os dados da sua
  aplicação sejam sanitizados antes de serem encaminhados ao AppSignal. Quando
  identificar uma pessoa for necessário, sua aplicação deve usar formas
  alternativas de identificação, como um ID de usuário, hash ou pseudônimo.
</Warning>

Para usar as funções helper, primeiro você precisa importá-las de `@appsignal/nodejs`. No exemplo abaixo, o namespace no qual o código está sendo executado é reportado ao AppSignal. Todas as funções helper disponíveis estão descritas na [documentação abaixo](/#helper-functions).

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

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

Todas as funções helper disponíveis para atributos de instrumentação personalizada estão descritas na [lista abaixo](#helper-functions).

### Funções helper

<Tip>
  Os snippets de código para os helpers abaixo assumem que seu código já está
  sendo instrumentado (por exemplo, dentro de um handler de requisição do Express
  ou Koa). Se seu código ainda não estiver instrumentado, você precisa [criar um
  span](#spans) e usar os helpers dentro dele.
</Tip>

* [Namespace](#namespace)
* [Tag](#tag)
* [Parâmetros da requisição](#request-parameters)
* [Definir dados de sessão](#set-session-data)
* [Headers da requisição](#request-headers)
* [Root Name](#root-name)
* [Dados personalizados](#custom-data)
* **[Helpers de span filho:](#child-span-helpers)**
  * [Category](#category)
  * [Name](#name)
  * [Body](#body)

### Namespace

Define o valor de string do namespace do span raiz.

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

### Tag

Define uma tag, por exemplo, a partir de um parâmetro da requisição, que pode ser usada como filtro dentro da aplicação AppSignal. No exemplo abaixo, criamos uma tag chamada color com o valor blue. Você pode configurar tags com nomes relevantes para o contexto da sua aplicação.

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

### Parâmetros da requisição

Um objeto serializável para JSON. Parâmetros da requisição recebida, corpo da requisição e parâmetros de query.

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

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

### Definir dados de sessão

Um objeto serializável para JSON.

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

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

### Headers da requisição

Uma string contendo o valor do header.

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

### Root Name

Permite definir o nome do trace. As amostras são agrupadas em ações pelo nome do 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>

#### Exemplo de uso

Sua aplicação tem um endpoint chamado `GET /coffee`.

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

Todas as requisições para esse endpoint vão gerar amostras chamadas `GET /coffee`, mas seu endpoint lida com múltiplas ações: `coffee?action=buy` e `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 sem Root Name" width="1030" height="640" data-path="assets/images/screenshots/node/span-without-root-name.png" />

Embora todos utilizem o endpoint `GET /coffee`, eles são conceitualmente muito diferentes, então faz sentido que sejam agrupados separadamente no AppSignal, em vez de na mesma amostra `GET /coffee`. Para fazer isso, você pode usar o 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>

Usar `setRootName` mudará o nome do span raiz, agrupando as amostras das requisições `coffee?action=buy` e `coffee?action=sell` em ações separadas:

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

### Dados personalizados

Um objeto serializável para JSON.

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

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

### Helpers de span filho

Os helpers a seguir só se aplicam a spans filhos. Para criar um span filho, você precisa criar um novo [Span Ativo](#creating-an-active-span).

Novos spans são automaticamente filhos do span pai.

#### Category

Uma string contendo a categoria do span filho. O nome deve usar `.` para expressar a herança hierárquica da categoria. Por exemplo: `cafe.coffee.cupsize`

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

#### Name

Uma string contendo o título do evento do span filho na linha do tempo.

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

#### Body

<Warning>
  🔐 Não envie <strong>Informações Pessoais Identificáveis (PII)</strong> para a AppSignal. Filtre PII (por exemplo, nomes, e-mails) e use um ID, hash ou identificador pseudonimizado no lugar. <br /> <br /> Para <strong>entidades cobertas pela HIPAA</strong>, mais informações sobre como assinar um Business Associate Agreement (BAA) estão disponíveis em nossa <a href="/support/business-add-ons">documentação de Business Add-Ons</a>.
</Warning>

O body do span pode incluir informações adicionais sobre o evento, como a requisição HTTP, o host conectado, etc. Certifique-se de sanitizar as informações antes de adicioná-las ao span para que nenhuma Informação Pessoal Identificável seja enviada ao AppSignal. Essas informações ficarão visíveis para o span ao passar o mouse sobre a linha do tempo do evento.

Para armazenar consultas SQL no body do span, por favor, use o [helper `setSqlBody`](#sql-body) em vez disso.

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

#### SQL body

<Tip>
  Disponível desde o pacote Node.js 3.0.25.
</Tip>

Define uma consulta SQL como o body do span, como aparece na linha do tempo de eventos de performance na visualização de detalhes da amostra do incidente. Isso é semelhante ao [helper `setBody`](#body), mas é especializado para consultas SQL. Qualquer consulta SQL definida como body com este atributo será sanitizada para evitar o envio de dados PII (Informação Pessoal Identificável) para nossos servidores.

Veja o [helper `setBody`](#body) para mais detalhes sobre como o atributo body funciona.

Quando os helpers `setBody` e `setSqlBody` são chamados no mesmo span, o valor do helper `setSqlBody` prevalece e o valor do helper `setBody` será ignorado.

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