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

# AppSignal para Ruby e OpenTelemetry

export const Compatibility = ({versions = [], label = "Available in"}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const defaultPillStyle = {
    borderColor: "#d4d4d8",
    background: "#f4f4f5",
    color: "#3f3f46"
  };
  const pillStyles = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#d8b4fe",
      color: "#6b21a8"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#5eead4",
      color: "#115e59"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#86efac",
      color: "#166534"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#93c5fd",
      color: "#1e40af"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fca5a5",
      color: "#991b1b"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fdba74",
      color: "#9a3412"
    }
  };
  const getPillStyle = name => ({
    ...defaultPillStyle,
    ...pillStyles[name] || ({})
  });
  return <div className="not-prose my-4 rounded-lg border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm dark:border-white/10 dark:bg-white/5">
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span className="font-semibold text-zinc-700 dark:text-zinc-200">
          {label}:
        </span>
        {versions.map((v, i) => <span key={`${v.name}-${v.version}-${i}`} className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium" style={getPillStyle(v.name)}>
            <span>{v.name}</span>
            <span className="opacity-70">
              {v.version}
              {v.exact ? "" : "+"}
            </span>
          </span>)}
      </div>
    </div>;
};

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "5.0.0" }]} />

<Note>
  **Somente no modo collector:** isso se aplica quando o AppSignal para Ruby é executado no [modo collector](/ruby/configuration/collector). Nos demais casos, não tem efeito.
</Note>

No [modo collector](/ruby/configuration/collector), o AppSignal constrói seus traces a partir de spans do OpenTelemetry. Uma transaction se torna o span raiz de um trace. Cada evento que você instrumenta se torna um span filho dentro dele.

Sua própria instrumentação OpenTelemetry compartilha, portanto, esses traces. Esta página aborda o que isso oferece a você, e como descrever um span com mais detalhes do que o AppSignal faz por conta própria.

## Descrevendo um span nos termos do OpenTelemetry

Atributos são pares de chave e valor em um span. As [convenções semânticas](https://opentelemetry.io/docs/specs/semconv/) nomeiam os atributos a serem usados para tarefas comuns, como uma query de banco de dados ou uma requisição HTTP de saída. Use esses nomes onde eles se aplicarem, para que outras ferramentas possam ler o que você registra.

Adicione atributos ao span que o AppSignal está registrando no momento com `add_opentelemetry_attributes`:

<CodeGroup>
  ```ruby Ruby theme={null}
  Appsignal.instrument("query.my_database") do
    Appsignal::Transaction.current.add_opentelemetry_attributes(
      "db.system.name" => "mysql",
      "db.namespace" => "orders"
    )
    run_the_query
  end
  ```
</CodeGroup>

Os atributos são adicionados ao evento mais interno que estiver aberto naquele momento, que é o evento `query.my_database` no exemplo acima. Quando nenhum evento está aberto, eles são adicionados ao próprio span da transaction.

Um valor deve ser uma string, um integer, um float ou um boolean. Qualquer outro valor é convertido em uma string.

## Tipos de span e escopos de instrumentação

### Tipo de span

O tipo de um span indica qual papel o trabalho desempenhou no trace. Um span que atendeu a uma requisição de entrada é um span `:server`. Um span que chamou outro serviço é um span `:client`. Enviar e receber uma mensagem em uma queue são spans `:producer` e `:consumer`. Trabalho que permaneceu dentro da sua aplicação é um span `:internal`.

O span de um evento pode ser qualquer um desses cinco tipos. Ele é `:internal`, a menos que você defina um. A exceção é o `Appsignal.instrument_sql`, que registra um span `:client`, porque uma query é uma chamada de saída para um armazenamento de dados.

O span de uma transaction pode ser `:server`, `:consumer`, `:producer` ou `:internal`. Ele é `:server`, a menos que você defina um. Um tipo fora dessa lista retorna para `:server`.

<CodeGroup>
  ```ruby Ruby theme={null}
  Appsignal.instrument("request.my_api", :opentelemetry_kind => :client) do
    call_the_api
  end
  ```
</CodeGroup>

### Escopo de instrumentação

Um escopo de instrumentação nomeia a biblioteca para a qual um trecho de instrumentação foi escrito, como um par de nome e versão. Nem sempre é a biblioteca pela qual o trabalho passou. A instrumentação de um adapter de banco de dados tem escopo definido para a biblioteca de banco de dados com a qual ele se comunica, não para o adapter.

O AppSignal detalha o tempo que os eventos levaram e as allocations que fizeram por escopo de instrumentação. O escopo, portanto, decide contra qual biblioteca o custo de um span é reportado.

Os spans são registrados sob o escopo padrão do AppSignal quando você não define um. Defina um escopo próprio quando você instrumentar uma biblioteca em nome dela, para que o custo dela seja reportado contra essa biblioteca.

<CodeGroup>
  ```ruby Ruby theme={null}
  Appsignal.instrument(
    "query.my_database",
    :opentelemetry_scope => ["my_database", "2.1.0"]
  ) do
    run_the_query
  end
  ```
</CodeGroup>

### Quais métodos aceitam um tipo ou um escopo

Passe `opentelemetry_kind` e `opentelemetry_scope` para qualquer método que inicie uma transaction ou registre um evento:

* `Appsignal.monitor`
* `Appsignal.monitor_and_stop`
* `Appsignal.send_error`
* `Appsignal.report_error`
* `Appsignal.instrument`
* `Appsignal.instrument_sql`

Defina `opentelemetry_kind` como `:internal` em `Appsignal.instrument_sql` para sobrepor seu padrão `:client`.

## Continuando um trace de outro lugar

O trabalho pode chegar à sua aplicação a partir de um lugar que o AppSignal não instrumenta, carregando um contexto próprio do OpenTelemetry. Esse contexto nomeia o trace ao qual o trabalho pertence. Passá-lo permite que os dois lados sejam lidos como um único trace, em vez de dois.

Passe o contexto como `opentelemetry_context`. Diga o que o span da transaction deve fazer com ele usando `opentelemetry_relationship`:

* `:parent` faz do span da transaction um filho do span de entrada. O trabalho continua o mesmo trace. É isso o que acontece quando você passa um contexto e não diz mais nada.
* `:link` inicia um novo trace e registra um link de volta para o span de entrada. Use isso quando o trabalho for uma unidade própria em vez de uma continuação, o que costuma ser o caso de um background job.
* `:both` torna o span filho e também registra o link.
* `:none` ignora o contexto de entrada.

<CodeGroup>
  ```ruby Ruby theme={null}
  context = OpenTelemetry.propagation.extract(message.headers)

  Appsignal.monitor(
    :action => "MessageConsumer#perform",
    :namespace => "background_job",
    :opentelemetry_kind => :consumer,
    :opentelemetry_relationship => :link,
    :opentelemetry_context => context
  ) do
    handle(message)
  end
  ```
</CodeGroup>

### Quais métodos aceitam um contexto e uma relationship

Passe `opentelemetry_context` e `opentelemetry_relationship` para qualquer método que inicie uma transaction:

* `Appsignal.monitor`
* `Appsignal.monitor_and_stop`
* `Appsignal.send_error`
* `Appsignal.report_error`

`Appsignal.report_error` é a exceção. Ele inicia uma transaction apenas quando nenhuma está aberta. Os dois argumentos se aplicam quando ele inicia uma, e são ignorados quando ele adiciona o erro a uma transaction que já está aberta.

Você só precisa de tudo isso para trabalho que o AppSignal não instrumenta. As bibliotecas listadas em [distributed tracing](/ruby/distributed-tracing) já estão conectadas para você.

## Usando o SDK do OpenTelemetry diretamente

Você pode criar spans com o SDK do OpenTelemetry dentro de código que o AppSignal está rastreando. O AppSignal torna seu próprio span atual enquanto registra, então um span que você cria se torna um filho do evento do AppSignal dentro do qual você está.

<CodeGroup>
  ```ruby Ruby theme={null}
  tracer = OpenTelemetry.tracer_provider.tracer("my-app")

  Appsignal.instrument("checkout") do
    # This span is recorded as a child of the "checkout" event.
    tracer.in_span("charge_card") do |span|
      span.set_attribute("payment.provider", "stripe")
      charge_the_card
    end
  end
  ```
</CodeGroup>

Use `in_span` em vez de iniciar e finalizar spans você mesmo. Isso torna o span atual durante a duração do bloco, o finaliza depois e faz as duas coisas corretamente quando seu código gera um erro.

Dados que você reporta através do AppSignal são sempre registrados em um span criado pelo AppSignal, nunca em um span criado por você. Um erro reportado ao AppSignal dentro do seu próprio span é registrado no evento do AppSignal que o envolve, ou no span da transaction quando nenhum evento está aberto. Seus spans carregam apenas o que você mesmo registra neles.

## Usando instrumentação de terceiros para OpenTelemetry

Você pode instalar pacotes de instrumentação escritos por outras pessoas, como os que o projeto OpenTelemetry publica para bibliotecas comuns. Instale e configure-os como a própria documentação deles descreve. O AppSignal não precisa de nenhuma configuração para eles, e os spans deles aparecem nos seus traces ao lado dos do próprio AppSignal.

Isso funciona porque esses pacotes registram seu trabalho sob o span que estiver aberto no momento, e o AppSignal mantém seu próprio span aberto enquanto registra. Assim, os spans deles caem dentro da requisição ou do job que o AppSignal está rastreando, no lugar em que você esperaria.

Não funciona ao contrário. O AppSignal sempre inicia uma transaction como o começo de um novo trace, e não verifica o que o OpenTelemetry tem aberto no momento. Se um pacote abre um span próprio e uma requisição ou job do AppSignal começa dentro dele, essa requisição não se junta ao trace do pacote. Você obtém dois traces em vez de um, sem conexão entre eles.

Isso importa quando um pacote instrumenta o ponto de entrada da sua aplicação, porque o AppSignal também instrumenta esses pontos de entrada. Quando um pacote instrumenta trabalho que acontece no meio de uma requisição que o AppSignal já está rastreando, o que é o caso mais comum, os dois se encaixam sem que você precise fazer nada.

Quando você realmente precisar se juntar a um trace que o AppSignal não iniciou, passe o contexto dele você mesmo. Veja [continuando um trace de outro lugar](#continuando-um-trace-de-outro-lugar).
