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

Para descobrir quais trechos específicos de código estão causando problemas de
desempenho, é útil adicionar instrumentação personalizada à sua aplicação. Isso
nos permite criar breakdowns melhores sobre quais códigos rodam mais devagar e em que tipo
de ação foi gasta a maior parte do tempo.

A instrumentação personalizada é possível de duas formas: usando function decorators e
funções helper de instrumentação. Os function decorators são mais fáceis de usar,
mas são menos flexíveis do que as funções helper de instrumentação.

Este guia curto ajudará você a configurar a instrumentação personalizada. Mais detalhes sobre
o uso de certos helpers podem ser encontrados nos Hex docs do [pacote
AppSignal](https://hexdocs.pm/appsignal/).

<Tip>
  **Nota**: Certifique-se de ter [integrado o
  AppSignal](/elixir/instrumentation/integrating-appsignal) antes de adicionar
  instrumentação personalizada à sua aplicação se ela não estiver integrada automaticamente
  por uma das nossas [integrações](/elixir/integrations) suportadas.
</Tip>

<Tip>
  **Nota**: Esta página descreve apenas como adicionar instrumentação de desempenho ao
  seu código. Para rastrear erros, leia nosso guia de [tratamento de
  exceções](/elixir/instrumentation/exception-handling).
</Tip>

## `Appsignal.instrument/2-3`

A função `instrument/2` é usada para adicionar instrumentação envolvendo um trecho
de código em um span. Um span eventualmente se torna uma amostra, ou um evento na amostra
de outro span no AppSignal.

### Adicionar spans a traces

No exemplo a seguir, temos um controller Phoenix com uma função `index/2`
que chama uma função lenta. A função `slow` é instrumentada usando
a função `Appsignal.instrument/2`, que a registra como um evento separado nessa
requisição Phoenix. Ela aparecerá no AppSignal.com na timeline de eventos
desta amostra para fornecer mais insight sobre onde a maior parte do tempo foi gasta durante a
requisição.

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

Aqui, envolvemos o conteúdo da nossa função com uma chamada a `Appsignal.instrument3`,
e passamos `"slow"` como o nome do evento.

### Iniciando novos traces

No exemplo do Phoenix, um trace do AppSignal já foi iniciado, graças
ao suporte de primeira classe ao Phoenix no pacote AppSignal. Nem todos os
frameworks e pacotes são suportados diretamente no momento e iniciam automaticamente
traces. O mesmo vale para suas próprias aplicações Elixir puras.

Como ao adicionar spans a traces já instrumentados, um novo root span é
criado usando a função `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>

Este exemplo cria uma amostra chamada "instrument" no namespace "background"
no AppSignal. O nome também será usado como o nome da categoria para o main
span. Para usar um nome de categoria diferente, use `instrument/3` em vez disso:

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

Ao passar uma função que recebe um argumento, a função `instrument/2-3` a chama com o span aberto para permitir mais personalização. Veja os docs em hex.pm para [todas as funções de Span disponíveis](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 ->
        # Exemplo de construção de uma consulta SQL complexa dentro do bloco instrument e sua execução
        query = "SOME complicate SQL query"
        # O body é definido aqui apenas porque é o valor sendo calculado e instrumentado nesta função
        Appsignal.Span.set_sql(span, query)
        Database.perform_query(query)
      end)
    end
  end
  ```
</CodeGroup>

### Tratamento de exceções {/* id: helper-exception-handling */}

Para reportar erros usando instrumentação personalizada, leia mais em nosso [guia de tratamento
de exceções](/elixir/instrumentation/exception-handling).

## Function decorators

Usando o módulo de decorator `Appsignal.Instrumentation.Decorators`, é
possível adicionar instrumentação personalizada às suas aplicações Elixir sem
alterar o conteúdo das funções.

### Eventos de transação {/* id: decorator-transaction-events */}

No exemplo a seguir, temos um controller Phoenix com uma função `index/2`
que chama uma função lenta. A função `slow` é instrumentada usando o decorator
`transaction_event` do AppSignal, que a registra como um evento separado nesta requisição
Phoenix. Ela aparecerá no AppSignal.com na timeline de eventos desta amostra de transação
para fornecer mais insight sobre onde a maior parte do tempo foi gasta durante a requisição.

<CodeGroup>
  ```elixir Elixir theme={null}
  # Exemplo de controller Phoenix
  defmodule PhoenixExample.PageController do
    use PhoenixExample.Web, :controller
    # Inclua isto
    use Appsignal.Instrumentation.Decorators

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

    # Decore esta função para adicionar instrumentação personalizada
    @decorate transaction_event()
    defp slow do
      :timer.sleep(1000)
    end
  end
  ```
</CodeGroup>

Se você quiser agrupar certos eventos sob o mesmo grupo de eventos (outros
grupos são `phoenix_controller`, `phoenix_render`, `ecto`, etc.), você também pode
fornecer um nome de grupo ao decorator `transaction_event`.

<CodeGroup>
  ```elixir Elixir theme={null}
  @decorate transaction_event("github_api")
  defp get_data_from_github do
    # Chamada de API de terceiros
  end
  ```
</CodeGroup>

Isso criará um evento `get_data_from_github.github_api` na timeline
de eventos. Para mais informações sobre como os nomes de eventos são usados, leia
nossas [diretrizes de nomenclatura de eventos](/api/event-names).

### Transações {/* id: decorator-transactions */}

No exemplo do Phoenix, uma transação AppSignal já foi iniciada, graças
ao suporte de primeira classe ao Phoenix no pacote AppSignal. Nem todos os frameworks
e pacotes são suportados diretamente no momento e iniciam automaticamente transações.
O mesmo vale para suas próprias aplicações Elixir puras.

Para rastrear decorators `transaction_event`, precisaremos iniciar uma
transação AppSignal previamente. Podemos iniciar uma transação com o function
decorator `transaction`.

<CodeGroup>
  ```elixir Elixir theme={null}
  # Exemplo em Elixir puro
  defmodule FunctionDecoratorsExample do
    # Inclua isto
    use Appsignal.Instrumentation.Decorators

    # Nenhuma transação é iniciada previamente como no Phoenix, então precisamos iniciá-la
    # nós mesmos.
    @decorate transaction()
    def call do
      slow()
      # ...
    end

    # Decore esta função para adicionar instrumentação personalizada
    @decorate transaction_event()
    defp slow do
      :timer.sleep(1000)
    end
  end
  ```
</CodeGroup>

**Nota**: Ao usar aplicações Elixir puras, certifique-se de que a aplicação
AppSignal foi iniciada antes de iniciar uma transação. Para mais informações,
veja como
[integrar o AppSignal](/elixir/instrumentation/integrating-appsignal).

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

Para diferenciar entre requisições HTTP e background jobs, podemos passar um
namespace para a transação assim que iniciá-la.

Os dois namespaces a seguir são namespaces oficiais suportados pelo AppSignal.

* `http_request` - o padrão - é chamado de namespace "web"
* `background_job` - cria o namespace "background"

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

    # Sem argumento de namespace, o padrão é `:http_request`
    @decorate transaction()
    def web_function do
      # faça coisas
    end

    # O namespace "background"
    @decorate transaction(:background_job)
    def background_function do
      # faça coisas
    end
  end
  ```
</CodeGroup>

Para mais informações sobre o que são namespaces, veja nossa
documentação de [namespaces](/application/namespaces).

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

Você também pode criar seus próprios namespaces para rastrear transações em uma parte separada
da sua aplicação, como um painel administrativo. Isso agrupará todas as transações
com esse namespace em uma seção separada no AppSignal.com para que controllers admin lentos
não interfiram nas médias de velocidade da sua aplicação.

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

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

Há um function decorator personalizado para Phoenix channels. Este decorator deve
ser colocado antes da função `handle_in/3` de um módulo `Phoenix.Channel`.

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

    # Adicione este function decorator de channel
    @decorate channel_action()
    def handle_in("ping", _payload, socket) do
      # seu código aqui..
    end
  end
  ```
</CodeGroup>

Eventos de channels serão exibidos sob o namespace "background", mostrando o
módulo do channel e o argumento de ação no qual ele é usado.

## Criando e fechando spans manualmente

Em alguns casos, pode ser útil lidar com spans manualmente. Você pode usar a
API de spans para instrumentar tasks, por exemplo:

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