Observabilidade de Aplicações (APM)


Introdução à Observabilidade de Aplicações

O que é a Observabilidade de Aplicações?


Observabilidade de Aplicações permite entender um sistema externamente, possibilitando fazer perguntas sobre ele sem precisar conhecer seu funcionamento interno. Além disso, facilita a solução de problemas desconhecidos e imprevistos . A observabilidade ajuda a responder à pergunta: “Por que isso está acontecendo?”

Para fazer perguntas sobre um sistema, é necessário que sua aplicação esteja devidamente instrumentada. Isso significa que o código da aplicação ou algum componente intimamente ligado à aplicação como o Application Server, máquina virtual da linguagem da aplicação ou intepretador de comandos da linguagem devem emitir sinais, como rastreamentos (traces), métricas e logs. Uma aplicação está bem instrumentada quando os desenvolvedores não precisam adicionar mais instrumentação para investigar problemas, pois já possuem todas as informações necessárias.

O Priax, além de possuir mecanismos de instrumentação próprios pode é compatível com mecanismos consagrados do mercado como OpenTelemetry, Jaeger ou Opensearch APM. Todos esses mecanismos são usados para instrumentar o código da aplicação e tornar um sistema observável.

Telemetria, métricas e confiabilidade de Aplicações

Telemetria se refere aos dados emitidos por um sistema e seu comportamento. Esses dados podem ser apresentados na forma de rastreamentos, métricas e logs.

A confiabilidade responde à pergunta: “O serviço está fazendo o que os usuários esperam que ele faça?”. Por exemplo, um sistema pode estar disponível 100% do tempo, mas, se ao clicar em "Adicionar ao Carrinho" para incluir um par de sapatos pretos, o sistema não adicionar sempre os sapatos pretos, ele é considerado não confiável.

Métricas são agregações ao longo do tempo de dados numéricos sobre sua infraestrutura ou aplicação. Exemplos incluem:

SLI (Service Level Indicator) é uma medida do comportamento de um serviço. Um bom SLI mede o serviço do ponto de vista dos usuários. Um exemplo de SLI é a velocidade de carregamento de uma página web.

SLO (Service Level Objective) é a forma como a confiabilidade é comunicada dentro da organização ou para outras equipes, vinculando um ou mais SLIs ao valor de negócio.

Entendendo o Rastreamento Distribuído

O rastreamento distribuído permite observar solicitações conforme elas se propagam por sistemas distribuídos e complexos. Ele melhora a visibilidade sobre a saúde de uma aplicação ou sistema e ajuda a depurar comportamentos difíceis de reproduzir localmente.

O rastreamento distribuído é essencial para sistemas distribuídos, que frequentemente apresentam problemas não determinísticos ou complexos demais para serem reproduzidos em um ambiente local.

Para entender o rastreamento distribuído, é importante conhecer seus principais componentes: logs, spans e traces.

Logs

Um log é uma mensagem com carimbo de tempo emitida por serviços ou componentes. Diferente dos rastreamentos, os logs não estão necessariamente associados a uma solicitação ou transação específica. Eles estão presentes em praticamente todo software e foram amplamente utilizados por desenvolvedores e operadores para entender o comportamento dos sistemas.

Exemplo de log:

I, [2021-02-23T13:26:23.505892 #22473]  INFO -- : [6459ffe1-ea53-4044-aaa3-bf902868f730] Started GET "/" for ::1 at 2021-02-23 13:26:23 -0800

No entanto, os logs não são suficientes para rastrear a execução do código, pois geralmente carecem de informações contextuais, como o local de origem da chamada.

Os logs se tornam muito mais úteis quando são incluídos como parte de um span ou quando estão correlacionados a um trace e um span.

Spans

Um span representa uma unidade de trabalho ou uma operação. Ele rastreia operações específicas de uma solicitação, fornecendo uma visão detalhada do que ocorreu durante sua execução.

Um span inclui:

Atributos de Span

Os atributos são metadados associados a um span.

Chave Valor
http.request.method GET
network.protocol.version 1.1
url.path /webshop/articles/4
url.query ?s=1
server.address example.com
server.port 8080
url.scheme https
http.route /webshop/articles/:article_id
http.response.status_code 200
client.address 192.0.2.4
client.socket.address 192.0.2.5 (o cliente passa por um proxy)
user_agent.original Mozilla/5.0 (Windows NT 10.0; Win64; ...)

Rastreamentos Distribuídos

Um rastreamento distribuído (trace) registra os caminhos percorridos por solicitações (feitas por uma aplicação ou usuário final) enquanto atravessam arquiteturas multi-serviço, como aplicações baseadas em microsserviços ou serverless.

Um trace é composto por um ou mais spans:

Sem rastreamento, identificar a causa raiz de problemas de desempenho em sistemas distribuídos pode ser desafiador. O rastreamento simplifica a depuração e facilita o entendimento de sistemas complexos, detalhando o que acontece com uma solicitação enquanto ela se propaga pelo sistema.

Muitos backends de observabilidade visualizam os traces como diagramas de cascata (waterfall diagrams), que demonstram a relação entre spans pai e filhos, representando relações hierárquicas e aninhadas.

Propagação de Contexto

Entenda o conceito que viabiliza o Rastreamento Distribuído.

Com a propagação de contexto, os sinais podem ser correlacionados entre si, independentemente de onde são gerados. Embora não se limite apenas ao rastreamento, a propagação de contexto permite que os rastreamentos construam informações causais sobre um sistema que está distribuído de forma arbitrária entre processos e limites de rede.

Para entender a propagação de contexto, é necessário conhecer dois conceitos principais: contexto e propagação.

Contexto

O contexto é um objeto que contém as informações necessárias para que os serviços emissores e receptores, ou unidades de execução, possam correlacionar um sinal com outro.

Por exemplo: se o serviço A chama o serviço B, um span do serviço A, cujo ID está presente no contexto, será utilizado como span pai para o próximo span criado no serviço B. O ID do rastreamento (trace ID) também será incluído no contexto e utilizado para o próximo span criado no serviço B. Isso significa que esse novo span fará parte do mesmo rastreamento que o span do serviço A.

Propagação

A propagação é o mecanismo responsável por mover o contexto entre serviços e processos. Ela serializa ou desserializa o objeto de contexto e fornece as informações relevantes para que o contexto seja transferido de um serviço para outro.

Geralmente, a propagação é gerenciada automaticamente pelas bibliotecas de instrumentação e é transparente para o usuário. No entanto, caso seja necessário realizar a propagação de contexto manualmente, você pode utilizar a API de Propagadores (Propagators API) de cada biblioteca de instrumentação.

Sinais e Métricas das Aplicações

Tipos de Sinais

Conheça as categorias de telemetria suportadas pelo Priax e bibliotecas de instrumentação compatíveis:

O objetivo de uma biblioteca de instrumentação é coletar, processar e exportar sinais. Sinais são saídas do sistema que descrevem a atividade subjacente do sistema operacional e das aplicações em execução em uma plataforma. Um sinal pode representar algo que você deseja medir em um ponto específico no tempo, como a temperatura ou o uso de memória, ou um evento que percorre os componentes de um sistema distribuído e que você gostaria de rastrear.

Com o Priax você pode agrupar diferentes sinais para observar o funcionamento interno de uma mesma tecnologia sob diferentes perspectivas.

Atualmente, o Priax é capaz de exibir, detalhar, quantificar e detalhar as seguintes categorias de sinais:


Rastreamentos (Traces)

O caminho de uma solicitação através da sua aplicação.

Os rastreamentos nos dão uma visão geral do que acontece quando uma solicitação é feita a uma aplicação. Seja sua aplicação um monólito com um único banco de dados ou uma complexa malha de serviços, os rastreamentos são essenciais para entender o “caminho” completo que uma solicitação percorre na sua aplicação.

Vamos explorar isso com três unidades de trabalho representadas como Spans (faixas de execução):

Observação
Os exemplos de JSON a seguir não representam um formato específico, especialmente o OTLP/JSON, que é mais detalhado.

1. Span Hello:
{  
  "name": "hello",  
  "context": {  
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",  
    "span_id": "051581bf3cb55c13"  
  },  
  "parent_id": null,  
  "start_time": "2022-04-29T18:52:58.114201Z",  
  "end_time": "2022-04-29T18:52:58.114687Z",  
  "attributes": {  
    "http.route": "some_route1"  
  },  
  "events": [  
    {  
      "name": "Guten Tag!",  
      "timestamp": "2022-04-29T18:52:58.114561Z",  
      "attributes": { "event_attributes": 1 }  
    }  
  ]  
}

Este é o span raiz, indicando o início e o fim da operação inteira. Observe que ele tem um campo trace_id, mas não tem parent_id, o que o caracteriza como a raiz do rastreamento.

2. Span hello-greetings:
{
  "name": "hello-greetings",
  "context": {
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
    "span_id": "5fb397be34d26b51"
  },
  "parent_id": "051581bf3cb55c13",
  "start_time": "2022-04-29T18:52:58.114304Z",
  "end_time": "2022-04-29T22:52:58.114561Z",
  "attributes": {
    "http.route": "some_route2"
  },
  "events": [
    {
      "name": "hey there!",
      "timestamp": "2022-04-29T18:52:58.114561Z",
      "attributes": {
        "event_attributes": 1
      }
    },
    {
      "name": "bye now!",
      "timestamp": "2022-04-29T18:52:58.114585Z",
      "attributes": {
        "event_attributes": 1
      }
    }
  ]
}

Este span encapsula tarefas específicas, como exibir saudações, e seu parent_id é o ID do span raiz hello. Ele compartilha o mesmo trace_id, indicando que faz parte do mesmo rastreamento.

3. Span hello-salutations:
{  
  "name": "hello-salutations",  
  "context": {  
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",  
    "span_id": "93564f51e1abe1c2"  
  },  
  "parent_id": "051581bf3cb55c13",  
  "start_time": "2022-04-29T18:52:58.114492Z",  
  "end_time": "2022-04-29T18:52:58.114631Z",  
  "attributes": {  
    "http.route": "some_route3"  
  },  
  "events": [  
    {  
      "name": "hey there!",  
      "timestamp": "2022-04-29T18:52:58.114561Z"  
    }  
  ]  
}

Este span representa a terceira operação neste rastreamento e, assim como o anterior, é um filho do span raiz (hello). Isso também o torna um irmão do span hello-greetings

Esses três blocos de JSON compartilham o mesmo trace_id e utilizam o parent_id para representar a hierarquia. Isso cria o rastreamento completo!

Uma observação importante é que cada Span se assemelha a um log estruturado, com contexto, correlação e hierarquia embutidos. Contudo, esses “logs estruturados” podem vir de diferentes processos, serviços, VMs ou datacenters, permitindo que o rastreamento represente uma visão ponta a ponta de qualquer sistema.

Detalhamento de uma span

Uma span representa uma unidade de trabalho ou operação e inclui:

Exemplo de span:

{
  "name": "/v1/sys/health",
  "context": {
    "trace_id": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
    "span_id": "086e83747d0e381e"
  },
  "parent_id": "",
  "start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
  "end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
  "status_code": "STATUS_CODE_OK",
  "status_message": "",
  "attributes": {
    "net.transport": "IP.TCP",
    "net.peer.ip": "172.17.0.1",
    "net.peer.port": "51820",
    "net.host.ip": "10.177.2.152",
    "net.host.port": "26040",
    "http.method": "GET",
    "http.target": "/v1/sys/health",
    "http.server_name": "mortar-gateway",
    "http.route": "/v1/sys/health",
    "http.user_agent": "Consul Health Check",
    "http.scheme": "http",
    "http.host": "10.177.2.152:26040",
    "http.flavor": "1.1"
  },
  "events": [
    {
      "name": "",
      "message": "OK",
      "timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
    }
  ]
}

Contexto do Span

Os spans podem ser aninhados, como é indicado pela presença de um ID de span pai: os spans filhos representam suboperações. Isso permite que os spans capturem com mais precisão o trabalho realizado em uma aplicação. O span pai terá um trace_Id idêntico ao seu filho indicando portanto que atende a uma mesma requisição ao sistema.

O contexto do span é um objeto imutável presente em todos os spans que contém as seguintes informações:

Atributos

Os atributos são pares chave-valor usados para adicionar metadados a um span, permitindo capturar informações sobre a operação monitorada.

Por exemplo, se um span acompanha a operação de adicionar um item ao carrinho de compras em um sistema de e-commerce, você pode registrar o ID do usuário, o ID do item e o ID do carrinho.

Regras para atributos:

Além disso, existem Atributos Semânticos, que são convenções padronizadas para nomes de atributos comuns. Utilizar nomes semânticos facilita a padronização de metadados entre sistemas.

Eventos do Span

Um evento do span pode ser visto como uma mensagem de log estruturada (ou anotação) associada a um span. Geralmente é usado para marcar um ponto singular e significativo no tempo durante a duração de um span.

Exemplo prático em um navegador web:

  1. Carregamento da página → O span é mais apropriado, pois acompanha uma operação com início e fim.
  2. Página se torna interativa → Um evento do span é mais adequado, pois representa um ponto específico no tempo.

Quando usar eventos do span versus atributos?
Se o timestamp específico for relevante, use um evento do span. Caso contrário, use atributos.

Por exemplo, em um sistema distribuído, algumas operações são rastreadas por um trace. Em resposta a essas operações, uma nova tarefa pode ser enfileirada para execução assíncrona. Para associar o trace da operação subsequente ao trace original, criamos um link de span.

Status do Span

Cada span possui um status com três valores possíveis:

  1. Unset: (padrão) indica que a operação foi concluída sem erros.
  2. Error: indica que ocorreu algum erro, como um HTTP 500 em um servidor.
  3. Ok: explicitamente definido pelo desenvolvedor para marcar o span como bem-sucedido.

Nota: Quando não houver um status Ok para spans que concluíram sem erros, considera-se um evento bem sucedido, pois o valor padrão Unset já cobre esse caso. Ok é usado para deixar explícito que um span é considerado bem-sucedido, sem ambiguidades.

Tipo do Span (Span Kind)

Ao criar um span, ele pode ser classificado como Client, Server, Internal, Producer ou Consumer. O tipo de span informa ao backend de rastreamento como o trace deve ser montado.

Se o tipo não for especificado, ele é considerado Internal.


Métricas

Uma métrica é uma medida de um serviço capturada em tempo de execução. O momento em que a medição é registrada é conhecido como um evento de métrica, que inclui não apenas o valor medido, mas também o horário da captura e os metadados associados.

Métricas de aplicação e requisição são indicadores importantes de disponibilidade e desempenho. Métricas personalizadas podem oferecer insights sobre como os indicadores de disponibilidade impactam a experiência do usuário ou o negócio. Os dados coletados podem ser utilizados para alertar sobre interrupções ou para acionar decisões de escalonamento automático durante períodos de alta demanda.

Para compreender como as métricas funcionam quando se utiliza as bibliotecas de instrumentação compatíveis com o Priax, vamos analisar os componentes principais que ajudam na instrumentação do código.

Provedor de Meter (Meter Provider)

O Meter Provider é uma fábrica de Meters. Em aplicações, geralmente é inicializado uma única vez e seu ciclo de vida corresponde ao ciclo de vida da aplicação. A inicialização de um Meter Provider também envolve a configuração de Recursos e Exportadores. Esse é, normalmente, o primeiro passo ao configurar métricas no Priax. Em alguns SDKs compatíveis, um Meter Provider global já é inicializado automaticamente.

Meter

Um Meter é responsável por criar instrumentos de métrica que capturam medições sobre um serviço em tempo de execução. Os Meters são criados a partir de Meter Providers.

Exportador de Métricas (Metric Exporter)

Os Exportadores de Métricas enviam dados de métricas para um consumidor. Esse consumidor pode ser uma saída padrão (para depuração durante o desenvolvimento), o Priax utiliza o Opentelemetry Collector, ou qualquer backend de código aberto ou proprietário de sua escolha.

Instrumentos de Métrica (Metric Instruments)

No Priax, as medições são capturadas por instrumentos de métrica, definidos pelos seguintes atributos:

O nome, a unidade e a descrição são definidos pelo desenvolvedor ou por convenções semânticas para métricas comuns, como requisições e processos.

Os tipos de instrumentos compatíveis incluem:

Agregação

Além dos instrumentos de métrica, a agregação é um conceito importante. A agregação combina uma grande quantidade de medições em estatísticas exatas ou estimadas sobre eventos de métrica em uma janela de tempo. O protocolo OTLP transporta essas métricas agregadas.

A API do Priax fornece uma agregação padrão para cada instrumento, que pode ser personalizada usando Views. O objetivo do projeto Priax é fornecer agregações padrão que sejam compatíveis com ferramentas de visualização e backends de telemetria.

Diferentemente do rastreamento de requisições, que captura o ciclo de vida de uma requisição, as métricas fornecem informações estatísticas em agregados. Exemplos de uso incluem:

Views

As Views oferecem flexibilidade para personalizar a saída de métricas pelo SDK. É possível:

Suporte por Linguagem

O suporte às implementações específicas da API e do SDK de Métricas, por linguagem, está conforme a tabela abaixo:

Linguagem Status
C++ Estável
C#/.NET Estável
Erlang/Elixir Em desenvolvimento
Go Estável
Java Estável
JavaScript Estável
PHP Estável
Python Estável
Ruby Em desenvolvimento
Rust Beta
Swift Em desenvolvimento

Logs

Um log é um registro textual com marcação de tempo, podendo ser estruturado (recomendado) ou não estruturado, acompanhado de metadados opcionais. Entre todos os sinais de telemetria, os logs possuem o maior legado, já que a maioria das linguagens de programação inclui capacidades de logging nativas ou bibliotecas amplamente utilizadas.


Logs de Aplicação no Priax

O Priax não define uma API ou SDK específicos para criar logs. Em vez disso, os logs no Priax são aqueles já existentes, oriundos de frameworks de logging ou componentes de infraestrutura. Os SDKs e bibliotecas de instrumentação compatíveis com o Priax e a autoinstrumentação utilizam diversos componentes para correlacionar automaticamente logs com traces.

O suporte da biblioteca de instrumentação Priax para logs é projetado para ser totalmente compatível com sistemas existentes, oferecendo ferramentas para adicionar contexto adicional aos logs e manipulá-los em um formato comum, independentemente da origem.

Nas aplicações, os logs  são criados usando qualquer biblioteca ou funcionalidade nativa de logging. Ao adicionar autoinstrumentação ou ativar um SDK de instrumentação compatível com o Priax, os logs são correlacionados automaticamente existentes com quaisquer traces e spans ativos, encapsulando o corpo do log com seus respectivos IDs.


Suporte por Linguagem

As bibliotecas de instrumentação atualmente compatíveis com o Priax suportam o envio de logs para as seguintes linguagens de programação:

Linguagem Status
C++ Estável
C#/.NET Estável
Erlang/Elixir Em desenvolvimento
Go Beta
Java Estável
JavaScript Em desenvolvimento
PHP Estável
Python Em desenvolvimento
Ruby Em desenvolvimento
Rust Beta
Swift Em desenvolvimento

Logs Estruturados, Não Estruturados e Semi-Estruturados

Logs Estruturados

Logs estruturados seguem um formato consistente e legível por máquina, como JSON.

Exemplo em aplicação:

{
  "timestamp": "2024-08-04T12:34:56.789Z",
  "level": "INFO",
  "service": "autenticacao-usuario",
  "mensagem": "Login do usuário bem-sucedido",
  "contexto": {
    "userId": "12345",
    "ipAddress": "192.168.1.1"
  }
}

Logs Não Estruturados

Logs não estruturados não seguem um formato consistente. Apesar de serem mais legíveis para humanos, são difíceis de processar em larga escala.

Exemplo:
[ERRO] 2024-08-04 12:45:23 - Falha ao conectar ao banco de dados. Timeout.

Logs Semi-Estruturados

Logs semi-estruturados utilizam padrões consistentes, mas com formatações variadas entre sistemas.

Exemplo:
2024-08-04T12:45:23Z level=ERROR service=autenticacao-usuario action=login mensagem="Senha inválida"

Baggage

Informações contextuais propagadas entre sinais.

O Baggage representa informações contextuais que são mantidas junto ao contexto. O Baggage é uma estrutura de chave-valor que permite a propagação de dados arbitrários ao lado do contexto.

Com o Baggage, é possível transmitir dados entre serviços e processos, tornando essas informações acessíveis para serem adicionadas a traces, métricas ou logs nos serviços subsequentes.

Para que serve o Baggage

O Baggage é ideal para incluir informações que estão disponíveis no início de uma requisição, mas que precisam ser acessadas em estágios posteriores. Exemplos incluem:

Propagar essas informações usando o Baggage possibilita análises mais detalhadas na telemetria. Por exemplo, incluir um ID de Usuário em um span que monitora uma chamada ao banco de dados facilita responder perguntas como: “Quais usuários estão enfrentando as chamadas mais lentas ao banco de dados?”. Também é possível registrar informações de uma operação downstream e incluir o mesmo ID de Usuário nos dados de log.

Considerações de segurança do Baggage

Itens sensíveis no Baggage podem ser compartilhados com recursos não intencionais, como APIs de terceiros. Isso ocorre porque instrumentações automáticas incluem o Baggage na maioria das requisições de rede do seu serviço.

Especificamente, o Baggage e outras partes do contexto de trace são enviados em cabeçalhos HTTP, ficando visíveis para quem inspecionar o tráfego da rede. Se o tráfego estiver restrito à sua rede interna, esse risco pode não se aplicar, mas é importante lembrar que serviços downstream podem propagar o Baggage para fora da sua rede.

Além disso, não há verificações de integridade embutidas para garantir que os itens do Baggage sejam de sua origem. Por isso, tome cuidado ao acessá-los.

O Baggage não é o mesmo que atributos

Uma diferença importante é que o Baggage é um armazenamento separado de chave-valor, e não está associado diretamente aos atributos de spans, métricas ou logs, a menos que seja adicionado explicitamente.

Para adicionar entradas do Baggage como atributos, é necessário ler os dados do Baggage e incluí-los manualmente como atributos em spans, métricas ou logs.

Como um dos usos comuns do Baggage é adicionar dados como atributos de spans em um trace inteiro, várias linguagens oferecem Baggage Span Processors que automaticamente adicionam dados do Baggage como atributos na criação de spans.

Instrumentação com Bibliotecas OpenTelemetry

O envio de sinais para o Priax pode ser realizado através de instrumentação própria, alterando o código da aplicação a ser observada sem inserir componentes de terceiros à sua infraestrutura. Este processo, no entanto pode ser custoso e levar algum tempo. Para que se possa acelerar esse processo, recomendamos, apesar de não ser a única opção, as bibliotecas e SDKs open-source do OpenTelemetry. Tais bibliotecas seguem os padrões OpenTracing e se tornaram a mais difundida solução de instrumentação para o mercado de Observabilidade.

Como o OpenTelemetry facilita a instrumentação
Para tornar um sistema observável, é necessário instrumentá-lo: ou seja, o código dos componentes do sistema deve emitir traces, métricas e logs.

Com o OpenTelemetry, você pode instrumentar seu código de duas maneiras principais:

  1. Soluções baseadas em código
    Utilizando APIs e SDKs oficiais disponíveis para a maioria das linguagens de programação.

  2. Soluções sem código
    Ideais para casos em que você não pode ou não deseja modificar o aplicativo que precisa de telemetria.

Soluções baseadas em código

Essas soluções permitem uma telemetria mais profunda e detalhada, gerada diretamente pela sua aplicação. Elas utilizam a API do OpenTelemetry para produzir telemetria personalizada, complementando as informações coletadas por soluções sem código.

Soluções sem código

Perfeitas para começar rapidamente ou quando o aplicativo não pode ser modificado. Essas soluções oferecem uma telemetria rica baseada em bibliotecas utilizadas ou no ambiente em que a aplicação está sendo executada. Elas fornecem dados sobre o que está acontecendo nas "bordas" da aplicação, como interações externas e dependências.

Nota: É possível usar ambas as abordagens ao mesmo tempo para maximizar a observabilidade.


Benefícios adicionais do OpenTelemetry

O OpenTelemetry vai além de oferecer soluções com e sem código. Ele também inclui os seguintes recursos:

Formas de Instrumentação

Instrumentação sem código

A instrumentação sem código adiciona as capacidades da API e SDK do OpenTelemetry à sua aplicação, geralmente por meio de uma instalação de agente ou algo semelhante a um agente. Os mecanismos específicos variam conforme a linguagem, incluindo manipulação de bytecode, monkey patching ou eBPF, para injetar chamadas à API e ao SDK do OpenTelemetry diretamente na aplicação.

Como funciona

Normalmente, a instrumentação sem código adiciona suporte para bibliotecas que sua aplicação utiliza. Isso significa que requisições e respostas, chamadas a bancos de dados, chamadas de filas de mensagens, entre outros, serão instrumentados automaticamente. No entanto, o código da sua aplicação geralmente não é instrumentado. Para isso, é necessário utilizar instrumentação baseada em código.

Além disso, a instrumentação sem código permite configurar as bibliotecas de instrumentação e os exportadores que serão carregados.

Configuração

Você pode configurar a instrumentação sem código por meio de variáveis de ambiente e outros mecanismos específicos da linguagem, como propriedades do sistema ou argumentos passados para métodos de inicialização. Para começar, é necessário apenas configurar o nome do serviço para identificá-lo no backend de observabilidade escolhido.

Outras opções de configuração incluem:

Suporte de linguagens para instrumentação automática

A instrumentação automática está disponível para as seguintes linguagens:

Para realizar a instrumentação de sua aplicação, utilizando o método Zero Code, siga as instruções da página do OpenTelemetry.

Instrumentação Baseada em Código

A instrumentação baseada em código permite criar telemetria personalizada diretamente no código da sua aplicação. Abaixo estão os passos essenciais para configurar essa abordagem:

1. Importar a API e o SDK do OpenTelemetry

Para mais detalhes sobre a API e o SDK, consulte a especificação do OpenTelemetry.

2. Configurar a API do OpenTelemetry

3. Configurar o SDK do OpenTelemetry

A configuração pode ser feita programaticamente, por meio de arquivos de configuração ou outros mecanismos.

4. Criar Dados de Telemetria

5. Exportar Dados de Telemetria

Para realizar a instrumentação de sua aplicação, utilizando o método baseado em código siga as instruções da página do OpenTelemetry.

Instrumentação de Bibliotecas

A instrumentação nativa de bibliotecas com OpenTelemetry oferece uma experiência aprimorada tanto para desenvolvedores quanto para usuários finais, eliminando a necessidade de expor e documentar hooks personalizados. Aqui está como funciona e os benefícios associados:

Como Adicionar Instrumentação Nativa

Vantagens da Instrumentação Nativa

  1. Melhoria na Observabilidade e Experiência do Usuário:

    • Remove a necessidade de hooks personalizados, facilitando a integração.
    • APIs do OpenTelemetry são fáceis de usar e consistentes para os usuários finais.
  2. Telemetria Consistente e Correlação Aprimorada:

    • Traços, logs e métricas provenientes do código da biblioteca e da aplicação são correlacionados, criando uma visão coesa dos eventos.
    • Convenções comuns garantem uniformidade entre tecnologias, bibliotecas e linguagens.
  3. Extensibilidade e Ajustes Fáceis:

    • Sinais de telemetria podem ser ajustados (filtrados, processados, agregados) para atender a diferentes cenários de consumo.
    • OpenTelemetry oferece extensibilidade bem documentada para personalização.

Para realizar a instrumentação de sua aplicação, utilizando as bibliotecas nativas OpenTelemetry, siga as instruções da página do OpenTelemetry.

Instrumentação com Kubernetes Operator

A instrumentação de aplicações que rodam em workloads Kubernetes é facilitada pelo Opentelemetry Kubernetes Operator que é uma implementação de um Operador Kubernetes que gerencia coletores e a auto-instrumentação das cargas de trabalho usando bibliotecas de instrumentação do OpenTelemetry.

Introdução

O Operador OpenTelemetry é uma implementação de um Operador Kubernetes.

O operador gerencia:

Início Rápido

Para instalar o operador em um cluster existente, certifique-se de ter o cert-manager instalado e execute:

kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml

Assim que a implantação do opentelemetry-operator estiver pronta, crie uma instância do Coletor OpenTelemetry (otelcol) como o exemplo abaixo:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: simplest
spec:
  config: |
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
          http:
            endpoint: 0.0.0.0:4318
    processors:

    exporters:
      # NOTA: Antes da versão v0.86.0, use `logging` ao invés de `debug`.
      debug:

    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [debug]
EOF

Para mais opções de configuração e para configurar a injeção de auto-instrumentação das cargas de trabalho usando as bibliotecas de instrumentação do OpenTelemetry, continue lendo aqui.

Injeção de Auto-instrumentação

Configurar Instrumentação Automática
Para gerenciar a instrumentação automática, o operador precisa ser configurado para identificar quais pods instrumentar e qual instrumentação automática usar nesses pods. Isso é feito por meio do CRD de Instrumentação.

A criação correta do recurso de Instrumentação é fundamental para que a instrumentação automática funcione. Certifique-se de que todos os endpoints e variáveis de ambiente estejam configurados corretamente.

.NET

O seguinte comando criará um recurso básico de Instrumentação configurado especificamente para serviços .NET:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: demo-instrumentation
spec:
  exporter:
    endpoint: http://demo-collector:4318
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "1"
EOF

Por padrão, o recurso de Instrumentação para serviços .NET usa OTLP com o protocolo HTTP/Protobuf. O endpoint configurado deve ser capaz de receber OTLP via HTTP/Protobuf, como no exemplo: http://demo-collector:4318.

Excluindo bibliotecas de instrumentação

Se você não quiser usar determinadas bibliotecas, configure as variáveis de ambiente OTEL_DOTNET_AUTO_[SIGNAL]_[NAME]_INSTRUMENTATION_ENABLED=false.

Exemplo:

dotnet:
  env:
    - name: OTEL_DOTNET_AUTO_TRACES_GRPCNETCLIENT_INSTRUMENTATION_ENABLED
      value: false
    - name: OTEL_DOTNET_AUTO_METRICS_PROCESS_INSTRUMENTATION_ENABLED
      value: false

Java

O seguinte comando criará um recurso básico de Instrumentação para serviços Java:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: demo-instrumentation
spec:
  exporter:
    endpoint: http://demo-collector:4318
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "1"
EOF

Por padrão, a instrumentação Java usa OTLP com HTTP/Protobuf.

Excluindo bibliotecas de instrumentação

Para desativar bibliotecas específicas:

OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED=false
OTEL_INSTRUMENTATION_[NAME]_ENABLED=true

Configurar Instrumentação Automática
Para gerenciar a instrumentação automática, o operador precisa ser configurado para identificar quais pods instrumentar e qual instrumentação automática usar nesses pods. Isso é feito por meio do CRD de Instrumentação.

A criação correta do recurso de Instrumentação é fundamental para que a instrumentação automática funcione. Certifique-se de que todos os endpoints e variáveis de ambiente estejam configurados corretamente.


.NET

O seguinte comando criará um recurso básico de Instrumentação configurado especificamente para serviços .NET:

bash
kubectl apply -f - <<EOF apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: demo-instrumentation spec: exporter: endpoint: http://demo-collector:4318 propagators: - tracecontext - baggage sampler: type: parentbased_traceidratio argument: "1" EOF

Por padrão, o recurso de Instrumentação para serviços .NET usa OTLP com o protocolo HTTP/Protobuf. O endpoint configurado deve ser capaz de receber OTLP via HTTP/Protobuf, como no exemplo: http://demo-collector:4318.

Excluindo bibliotecas de instrumentação

Se você não quiser usar determinadas bibliotecas, configure as variáveis de ambiente OTEL_DOTNET_AUTO_[SIGNAL]_[NAME]_INSTRUMENTATION_ENABLED=false.

Exemplo:

yaml
dotnet: env: - name: OTEL_DOTNET_AUTO_TRACES_GRPCNETCLIENT_INSTRUMENTATION_ENABLED value: false - name: OTEL_DOTNET_AUTO_METRICS_PROCESS_INSTRUMENTATION_ENABLED value: false

Java

O seguinte comando criará um recurso básico de Instrumentação para serviços Java:

bash
kubectl apply -f - <<EOF apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: demo-instrumentation spec: exporter: endpoint: http://demo-collector:4318 propagators: - tracecontext - baggage sampler: type: parentbased_traceidratio argument: "1" EOF

Por padrão, a instrumentação Java usa OTLP com HTTP/Protobuf.

Excluindo bibliotecas de instrumentação

Para desativar bibliotecas específicas:

  • Use OTEL_INSTRUMENTATION_[NAME]_ENABLED=false.
  • Para desativar todas por padrão e ativar somente algumas:
    bash
    OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED=false OTEL_INSTRUMENTATION_[NAME]_ENABLED=true

Node.js

O seguinte comando criará um recurso básico de Instrumentação para serviços Node.js:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: demo-instrumentation
spec:
  exporter:
    endpoint: http://demo-collector:4317
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "1"
EOF

Por padrão, a instrumentação Node.js usa OTLP com gRPC.

Gerenciar bibliotecas de instrumentação

nodejs:
  env:
    - name: OTEL_NODE_ENABLED_INSTRUMENTATIONS
      value: http,nestjs-core
nodejs:
  env:
    - name: OTEL_NODE_DISABLED_INSTRUMENTATIONS
      value: fs,grpc

Python

O seguinte comando criará um recurso básico de Instrumentação para serviços Python:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: python-instrumentation
spec:
  exporter:
    endpoint: http://demo-collector:4318
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "1"
EOF

Por padrão, Python usa OTLP com HTTP/Protobuf.

Logs em Python

Para ativar a instrumentação automática de logs:

python:
  env:
    - name: OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED
      value: 'true'

Excluindo bibliotecas de instrumentação

Defina OTEL_PYTHON_DISABLED_INSTRUMENTATIONS com os pacotes a serem excluídos.

Go

Para serviços Go, crie o recurso básico de Instrumentação:

kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: demo-instrumentation
spec:
  exporter:
    endpoint: http://demo-collector:4318
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "1"
EOF

A instrumentação Go usa um agente eBPF em um sidecar, que requer permissões elevadas.

Adicione anotações para ativar a instrumentação automática:

instrumentation.opentelemetry.io/inject-go: 'true'
instrumentation.opentelemetry.io/otel-go-auto-target-exe: '/path/to/executable'

Habilitar Instrumentação Automática

Adicione anotações ao seu deployment para ativar a instrumentação automática:

 

 

Ingestão de Dados e Backend de Armazenamento

O Priax suporta diferentes backends de armazenamento para Traces, Logs e Métricas coletados e podendo trabalhar com Opensearch, ou Elasticsearch. Para que os dados sejam injetados nessas bases de dados, utilizamos o OpenTelemetry Collector, e pode ser combinado ou não com outras tecnologias de transporte e transformação de dados como o Data Prepper e o Kafka. 

Apresentaremos aqui os conceitos básicos do Collector e cenários práticos de implantação para utilização destas tecnologias com o Priax.

Data Collector

O  Collector oferece uma implementação independente de fornecedor para receber, processar e exportar dados de telemetria. Ele elimina a necessidade de operar e manter múltiplos agentes/coletores. O Collector funciona com escalabilidade aprimorada e suporta formatos de dados de observabilidade de código aberto (por exemplo, Jaeger, Prometheus, Fluent Bit, etc.), enviando para um ou mais backends de código aberto ou comerciais. O agente Collector local é o destino padrão para o qual as bibliotecas de instrumentação exportam seus dados de telemetria.

Objetivos

Em abbientes de desenvolvimento ou testes e para ter resultados rápido com a observabilidade de maneira pontual é possível enviar seus dados diretamente de sua aplicação para um backend. Em ambientes de produção, no entanto, recomendamos usar um coletor junto com seus serviços, pois ele permite que o serviço descarregue dados rapidamente, realize cache quando necessário e, além disso, o coletor pode lidar com tarefas adicionais, como tentativas de reenvio, agrupamento, criptografia ou até mesmo filtragem de dados sensíveis.

O Collector facilita a unificação de dados, visto que suporta diversas formas de ingestão (Receivers) e diversas formas de exportação de dados (Exporters). Abaixo podemos ver como o Collector trabalha e como ele pode ser utilizado para enviar dados para os Backends de Armazenamento compatíveis com o Priax.

image.png

Como se pode observar o Collector pode receber dados diretamente das aplicações instrumentadas, de outros sistemas de observabilidade como o Prometheus ou o Jaeger mas também pode receber dados de outros Collectors ou buscar dados em sistemas Kafka, que podem ter sido alimentados por outros Collectors. Dessa forma pode-se criar um layout de implantação flexível onde os Collectors podem atuar como gateways concentradores ou como agentes de simples transmissão de dados para os BackEnds de Armazenamento. Para enviar dados para o Backend de armazenamento compatível com o Priax (Opensearch) o Collector pode ou não utilizar o Data Prepper (ver abaixo as informações sobre o DataPrepper).

Para compreender mais sobre os layouts de implantação do Data Collector, consulte a página do OpenTelemetry que trata sobre o assunto.

Instalação e Configuração dos Collectors

A instalação dos Collectors é relativamente simples e pode ser realizada diretamente sobre os sistemas operacionais Windows ou Linux ou ainda utilizando Docker ou Kubernetes. As instruções para instalação podem ser consultadas na página de instalação do Collector do OpenTelemetry.

A Configuração completa do Collector pode ser consultada na extensa documentação fornecida pelo OpenTelemetry porém aqui apresentamos alguns cenários tipicamente utilizados.

Configuração do Collector para uso com e sem Data Prepper
receivers:
  otlp:
    protocols:
      http:
        #include_metadata: true
        cors:
          allowed_origins: ["http://*"]
          allowed_headers: ["*"]
          #max_age: 7200
        #endpoint: 127.0.0.1:4318
  kafka:
    protocol_version: 3.3.0
    group_id: priaxapm1
    encoding: otlp_proto
    brokers: 
      - priax-teste-01.servicebus.windows.net:9093
    topic: priax
    auth:
      sasl:
        username: $$ConnectionString
        password: Endpoint=sb://kafkaAzure.servicebus.windows.net/;SharedAccessKeyName=teste-priax;SharedAccessKey=z5kREHICeAw0EEMySt7cP2kgh4XGb/zh4+AEhMe7r0g=;EntityPath=priax
        mechanism: PLAIN
      tls:
        insecure: true
processors:
  batch: {}
  tail_sampling/priax:
    decision_wait: 40s
    policies:
      - name: sample-ottl
        type: ottl_condition
        ottl_condition:
          span:
            - "status.code == 2 and attributes[\"lime.envelope.type\"] == nil"
            - "status.code == 2 and attributes[\"lime.envelope.type\"] != nil and attributes[\"lime.envelope.type\"] != \"Notification\""
            - "end_time - start_time > Duration(\"29s\")"
            - "attributes[\"sample.force\"] == true"
      - name: probabilistic-policy
        type: probabilistic
        probabilistic:
          hash_salt: "custom-salt"
          sampling_percentage: 0.1
  k8sattributes:
    extract:
      metadata:
      - k8s.namespace.name
      - k8s.deployment.name
      - k8s.statefulset.name
      - k8s.daemonset.name
      - k8s.cronjob.name
      - k8s.job.name
      - k8s.node.name
      - k8s.pod.name
      - k8s.pod.uid
      - k8s.pod.start_time
    passthrough: false
    pod_association:
    - sources:
      - from: resource_attribute
        name: k8s.pod.ip
    - sources:
      - from: resource_attribute
        name: k8s.pod.uid
    - sources:
      - from: connection
  memory_limiter:
    check_interval: 5s
    limit_percentage: 80
    spike_limit_percentage: 25
  resource:
    attributes:
    - action: insert
      from_attribute: k8s.pod.uid
      key: service.instance.id
exporters:
  debug:
    verbosity: detailed
  otlp/data-prepper:
    endpoint: data-prepper:21890
    tls:
      insecure: true
  opensearch:
    http:
    endpoint: https://opensearchserver:9200
    auth:
      authenticator: basicauth/client
extensions:
  health_check:
  pprof:
  zpages:
    endpoint: ":55679"
  basicauth/client:
    client_auth:
      username: ingester
      password: ingesterpass
service:
  extensions: [health_check, pprof, zpages]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [k8sattributes,memory_limiter,resource,batch,tail_sampling/priax]
      exporters: [debug,opensearch]
    metrics:
      receivers: [otlp]
      processors: [k8sattributes,memory_limiter,resource,batch]
      exporters: [debug,opensearch]
    logs:
      receivers: [otlp]
      processors: [k8sattributes,memory_limiter,resource,batch]
      exporters: [debug,opensearch]
    traceswithKafkaandDataprepper:
      receivers: [kafka]
      processors: [k8sattributes,memory_limiter,resource,batch]
      exporters: [debug,otlp/dataprepper]
    metricswithKafkaandDataprepper:
      receivers: [kafka]
      processors: [k8sattributes,memory_limiter,resource,batch]
      exporters: [debug,otlp/dataprepper]
    logswithKafkaandDataprepper:
      receivers: [kafka]
      processors: [k8sattributes,memory_limiter,resource,batch]
      exporters: [debug,otlp/dataprepper]
Amostragem de Traces e Spans

É importante perceber que a configuração acima define que serão enviadas ao Backend de Armazenamento o 0,1% das spans coletadas pela instrumentação. Isso se dá nos trechos destacados abaixo:

[...]
processors:
[...]
  tail_sampling/priax:
    decision_wait: 40s
    policies:
      - name: sample-ottl
        type: ottl_condition
        ottl_condition:
          span:
            - "end_time - start_time > Duration(\"29s\")"
            - "attributes[\"sample.force\"] == true"
      - name: probabilistic-policy
        type: probabilistic
        probabilistic:
          hash_salt: "custom-salt"
          sampling_percentage: 0.1
[...]
pipelines:
  traces:
      receivers: [otlp]
      processors: [k8sattributes,memory_limiter,resource,batch,tail_sampling/priax] 
      # Para não utilizar o sampling neste pipeline basta rever o processador tail_sampling/priax desta seção.
      exporters: [debug,opensearch]
    traces:
      receivers: 
        - kafka
      processors:
        - batch
        - tail_sampling/priax 
      exporters: 
        - otlp/data-prepper
[...]

Para que sejam enviados 100% dos traces para o Backend de Armazenamento, remova a configuração de sampling do pipeline desejado conforme comentado no exemplo acima.

Data Prepper

Data Prepper
O Data Prepper é um componente da infraestrutura do Opensearch. É um coletor de dados do lado do servidor, capaz de filtrar, enriquecer, transformar, normalizar e agregar dados para análise e visualização posteriores. É a ferramenta de ingestão de dados preferida para o OpenSearch, recomendada para a maioria dos casos de uso de ingestão de dados no OpenSearch, especialmente para o processamento de conjuntos de dados grandes e complexos.

Com o Data Prepper, você pode criar pipelines personalizados para melhorar a visão operacional de suas aplicações. Dois casos de uso comuns do Data Prepper são a análise de rastros (trace analytics) e a análise de logs (log analytics). A análise de rastros ajuda a visualizar fluxos de eventos e identificar problemas de desempenho. Já a análise de logs oferece ferramentas para aprimorar as capacidades de busca, realizar análises detalhadas e obter insights sobre o desempenho e o comportamento das suas aplicações.

Conceitos-chave e fundamentos
O Data Prepper processa dados por meio de pipelines personalizáveis. Esses pipelines são compostos por componentes modulares que podem ser ajustados para atender às suas necessidades, inclusive permitindo a integração de implementações próprias. Um pipeline do Data Prepper consiste nos seguintes componentes:

Cada pipeline contém dois componentes obrigatórios: a fonte e o destino. Se um buffer, um processador, ou ambos estiverem ausentes do pipeline, o Data Prepper usará o buffer padrão bounded_blocking e um processador no-op. É importante observar que uma única instância do Data Prepper pode conter um ou mais pipelines.

O uso do Data Prepper com o Priax, facilita a adoção de padrões do Opensearch e é altamente recomendável.

Instalação do Data Prepper

A instalação do Data Prepper é relativamente simples e sua documentação pode ser consultada diretamente na página do OpenSearch.

Configurações básicas de pipeline

A configuração básica do Data Prepper para uso com o Priax pode ser vista abaixo:

entry-pipeline:
  delay: "100"
  source:
    otel_trace_source:
      ssl: false
    buffer:
      buffer_size: 10240
      batch_size: 160
  sink:
    - pipeline:
        name: "raw-trace-pipeline"
    - pipeline:
        name: "service-map-pipeline"
raw-trace-pipeline:
  source:
    pipeline:
      name: "entry-pipeline"
  buffer:
    bounded_blocking:
      buffer_size: 10240
      batch_size: 160
  processor:
    - otel_trace_raw:
  sink:
    - stdout: null
    - opensearch:
        hosts: ["http://opensearchserver:9200"]
        username: ingester
        password: passwordingester
        max_retries: 20
        bulk_size: 4
        insecure: true
        index_type: trace-analytics-raw
service-map-pipeline:
  delay: "100"
  source:
    pipeline:
      name: "entry-pipeline"
  buffer:
    bounded_blocking:
      buffer_size: 10240
      batch_size: 160
  processor:
    - service_map_stateful:
  sink:
    - stdout: null
    - opensearch:
        hosts: ["http://opensearchserver:9200"]
        username: ingester
        password: passwordingester
        max_retries: 20
        bulk_size: 4
        insecure: true
        index_type: trace-analytics-service-map

Visualização de Dados de Aplicações

Conceitos Essenciais

O Priax oferece os recursos visuais para analisar o desempenho, a estrutura, as dependências de aplicações. Para que se possa compreender essas telas é importante entender alguns conceitos iniciais.

Conceito Descrição
Serviço Os serviços são os blocos de construção das arquiteturas modernas de microserviços. Em termos gerais, um serviço agrupa endpoints, consultas ou tarefas com o objetivo de construir o aplicativo. Em aplicações mais antigas, um serviço representa uma porção lógica da aplicação que desempenha uma porção de trabalho delimitável da aplicação.
Transação Representam um trecho de código delimitado sendo executado dentro de um serviço. Tal trecho de código pode ser o atendimento de usuários remotos através de um socket de rede (por exemplo um servidor Web atendendo a um usuário), a execução de uma lógica ou função interna para montar a resposta para esse usuário ou a conexão à serviços de rede externos para coletar dados ou informações necessárias.
Indicadores/Métricas Métricas APM funcionam como métricas regulares, mas com controles específicos para o APM. Use essas métricas para receber alertas no nível do serviço sobre acessos, erros e diversas medidas de latência.
Trace Um trace é usado para rastrear o tempo gasto por um aplicativo processando uma solicitação e o status dessa solicitação. Cada trace consiste de um ou mais spans.
Instrumentação Instrumentação é o processo de adicionar código ao seu aplicativo para capturar e relatar dados de observabilidade.

Explorando Serviços, Traces e Transações

Depois de instrumentar serviços e ativar o discovery de transações no Priax, os serviços serão populados com as transações que estão sendo executadas pelas aplicações e suas interações com usuários e demais sistemas com os quais trocam informações. No Priax, um serviço pode ser representado por um Container (oriundos de sistemas Docker ou similares), um Deplyment, Statefulset, Daemonset (esses três últimos componentes de um cluster Kubernetes) ou ainda por aplicações hospedadas em servidores de aplicação ou interpretadores de linguagens (java, .net, php, ruby, perl, pyton, etc).

Abaixo podemos ver um exemplo de Deployment de um cluster Kubernetes com as transações executadas dentro de seus Pods. Neste caso o Deployment representa o Serviço da aplicação instrumentada.

image.png

Para ver o mapa de um serviço instrumentado, basta selecioná-lo e no canto superior direito do painel da esquerda acessar suas dependências no botão image.png.

.

Screenshot 2024-12-19 003040.png

Nesta tela é exibido o mapa de dependências do Serviço. Podemos visualizar tanto os componentes internos das aplicações, representados por transações quanto os componentes da infraestrutura que suportam essas transações, como bases de dados e a estrutura do Kubernetes. Ao selecionar uma Transação, são exibidas à direita os gráficos de Time Series dos indicadores e métricas que são gerados ao longo do tempo como a média de tempo de execução, taxa de erros e taxa de transferência de dados.

Screenshot 2024-12-19 184059.png

Ao selecionar uma operação na árvore, abaixo são exibidas os detalhes das transações e clicando na aba Transactions você pode filtrar o tempo de exibição que deseja para visualizar as ocorrências quando aquela operação foi executada pela aplicação.

image.png

Desta fora são exibidas todas execuções da operação ocorridas naquele período de tempo.

image.png

No ícone image.png, podemos personalizar a janela de tempo que será exibida. Podemos também dar zoom-in e zoom-out ao longo do tempo para poder ter mais detalhes das execuções da transação. As barras que representam cada execução fornecem informações importantes sobre o tempo que levou cada execução. Barras mais longas foram as execuções que mais demoraram, e o tempo de execução pode ser visto passando o mouse em cima de cada execução, o que nos fornece outras informações como ID da Span e do Trace.

Ao clicar em uma das execuções podemos explorar todo o Trace da qual a execução da Transação faz parte e assim podemos compreender exatamente como transcorreu aquela execução, como foi chamada, por qual transação e o que ocorreu com aquela chamada de sistema como um todo.

image.png

O gráfico de Destacado em vermelho, acima, mostra a linha de tempo e a relação pai-filho entre as spans (execuções da transação) e o gráfico em verde, mostra como o tempo foi percentualmente distribuído entre as spans pai e filho de cada trace.
Clicando em cada span em qualquer um dos gráficos, é possível ver os detalhes de cada execução, incluindo logs e parâmetros de execução.

image.png

As métricas para cada transação tal como: tempo médio Latency (ou Avg Transaction Time), Número de execuções por período (Calls), taxa de erros por período (Error Tax), são exibidas no painel da direita, além de diversos dashboards com será demonstrado nesse documento.

Dentre as diversas tipos de transações que o Priax consegue detectar e analisar, exibir estatísticas, gráfcos e realizar drill down , além de produzir eventos e alertas estão:

Os indicadores tradicionalmente coletadas para cada Transação são: 

No entanto as métricas podem ser customizadas para cada caso.

Detectando problemas em Transações

Ao detectar um problema, que pode ser pela detecção de limites auto-calculados o Priax realiza, com a utilização de técnicas de análise de dados e machine learning, uma análise profunda de causa raiz, diferenciando os indicadores que representam um sintoma dos indicadores que de fato estão causando o problema, e unificando isso em um único Evento.

Screenshot 2024-12-19 100758.png

A partir do momento que um novo evento é detectado e sua causa raiz isolada, ele pode ser direcionado para a equipe e indivíduo correto, podendo ele realizar análise das correlações dos indicadores e itens de configuração envolvidos no Evento.

Screenshot 2024-12-19 100022.png

Ao receber um evento, você pode realizar a análise de impactos e de dependências da Transação causa-raiz do evento, o que nos permite entender quais outras Transações, Serviços e Aplicações estão sendo afetadas pelo problema. Ao analisar as dependências, também podemos detectar indicadores de infraestrutura que podem estar causando indiretamente o Evento.

Sempre que um Evento é criado são realizadas as análises que evitam a duplicação de eventos, criação de falsos positivos e a criação de eventos isolados quando esses possuem a mesma causa raíz. Para tal o Priax realiza:

As trigger para disparo de Eventos podem ser configuradas manualmente ou ainda podem ser calculadas baseadas nos dados históricos com técnicas de Análise de Dados e Machine Learning.

Screenshot 2024-12-18 201953.png

Na tela acima, de edição do Indicador é possível habilitar o aprendizado de Triggers, definir se os limites deverão ser abaixo, acima ou abaixo e acima da normalidade, definir se haverá um perfil diferente de trigger por dia da semana e por horário, além de definir qual será o menor nível de alerta que será gerado pelas trigger automaticamente aprendidas.

Para saber mais sobre o Gerenciamento de Eventos, consulte o capítulo específico sobre Gerenciamento de Operações e Eventos neste manual.

APM Dashboards

Após instrumentar uma aplicação ou serviço e coletar métricas, traces e logs é possível no Priax criar painéis e relatórios a respeito de Transações ocorridas dentro de cada Serviço da Aplicação. Ao longo do tempo, com a execução continuada das transações, são produzidos dados Time Series com os indicadores relevantes a respeito de cada transação, como por exemplo:

Tais dados podem ser visualizados em Dashboards customizados agregados por:

Abaixo pode ser visualizado um exemplo de Dashboard que apresenta dados sobre as Transações executadas ao londo de determinado período. Os Dashboards podem ser acessados através do ícone destacado na barra de ícones da esquerda na imagem abaixo.

Screenshot 2024-12-19 121344.png

Na tela acima são exibidos de acordo com o Número destacado:

  1. Tela de Filtros: Os filtros podem ser aplicados para definir quais Transações serão considerados no Dashboard. Neste dashboard de exemplo, foram adicionados componentes para que se possa filtrar por Aplicação, Serviço, Transação e Host que executou a transação. É possível, no entanto, filtrar por qualquer Atributo presente nas Spans, como por exemplo, por qualquer campo que represente um endpoint ou pelo tipo de operação realizada.
  2. Gráfico que exibe a taxa de execução e de erros ocorrida nas transações filtradas em cada período de tempo.
  3. Gráfico que exibe latência média e nos percentis 75 e 99 para cada período de tempo.

Todas os dashboards podem ser filtrados ao nível de Transação específica, podendo exibir dados dos seguintes tipos de transações entre outros:

Os dashboards são completamente customizáveis, podendo receber novos componentes, filtros, gráficos e layout de exibição. Novos dashboards podem ser criados e publicados, criando novas abas de exibição no topo da tela de dashboards exibida na tela acima.