Java Trace SDK baseado em configuração

O SDK de rastreamento do Java, baseado em configuração, permite uma especificação declarativa dos spans e das tags que esses spans devem conter, além de criar spans ao executar determinados métodos da sua aplicação.

A expressividade é comparável à das @Span anotações e SpanSupport.annotate() recursos do SDK de rastreamento programático Java.

Antes de implementar o rastreamento personalizado, leia as práticas recomendadas para rastreamento.

Introdução

O SDK baseado em configuração é sensível às mudanças em seu aplicativo. Você pode renomear uma classe ou um método e, de repente, a configuração não corresponde mais e você perde seus dados de rastreio Sempre que possível, recomendamos que você utilize o SDK de rastreamento do Java, que é muito mais resistente a alterações no código e oferece mais recursos para ajudá-lo a atingir seus objetivos.

Configuração

Para usar o SDK de rastreamento do ` Java ` baseado em configuração, é necessário habilitar o SDK de rastreamento do ` Java `, conforme descrito em “Habilitando o SDK de rastreamento do ` Java ` ”.

Notas:

  • As alterações na configuração do SDK de rastreamento do Java baseado em configuração são detectadas automaticamente pelo agente do Instana. Os aplicativos já instrumentados precisam ser reiniciados para usar a configuração mudada.

  • O SDK de rastreamento do Java, baseado em configuração, está disponível na versão 1.2.351Java do Trace Sensor ou em versões posteriores.

Formato

A listagem a seguir descreve o formato geral da configuração:

# Java Tracing
com.instana.plugin.javatrace:
  instrumentation:
    sdk:
      targets:
        - match:
            type: 'interface'|'class'|'baseclass'
            name: '<type-name>'
            method: '<method-name>'
            [argumentTypes:
              - '<argument-type-index0>'
              - '<argument-type-indexn>']
            [returnType: '<return-type-name>']
          span:
            name: '<span-name>'
            [type: '<span-type>']
            [stackDepth: <depth>]
            [tags:
              - kind: 'argument'
                name: 'name'
                index: 0
              - kind: 'return'
                name: 'name'
              - kind: 'constant'
                name: 'name'
                value: 'constant-value']
 

Diversos destinos podem ser definidos dentro da chave targets, cada um deles especifica um período a ser criado. O objeto match de um target especifica o método ao qual aplicar a instrumentação. O objeto span especifica como construir o período, incluindo o seu nome (que é usado, por exemplo, no Unbounded Analytics para o filtro call.name ) e quais tags devem ser configuradas.

Métodos de correspondência a serem instrumentados

Observação: A implementação de interfaces ou classes base pode consumir muitos recursos, especialmente em aplicativos que utilizam muitas classes, e deve ser evitada, se possível.

Esse objeto descreve o ponto de código no qual uma instrumentação deve ocorrer:

  • type: o tipo do código a ser instrumentado; valores suportados:
    • class, corresponder a uma classe concreta
    • interface, corresponder a todas as classes que implementam a interface
    • baseclass, corresponder a todas as classes que ampliam a classe base
  • name: Nome completo da classe, interface ou classe base a ser encontrada. Para classes aninhadas, deve-se usar a a.b.c.OutsideClass$NestedClass notação
  • method: o nome do método da classe, interface ou classe base determinada da qual uma chamada deve ser registrada
  • argumentTypes: lista de tipos de argumento totalmente qualificados do método a ser correspondido (opcional)
    • Se ausentes, os argumentos não serão correspondidos e a instrumentação será aplicada a todos os métodos em caso de sobrecarga
    • Se presentes, todos os argumentos terão de corresponder aos tipos especificados em ordem, caso contrário, o método não corresponderá
  • returnType: tipo retornado totalmente qualificado do método a ser correspondido (opcional)
    • Se ausente, o tipo de retorno não será considerado
    • Se presente, o tipo de retorno terá de corresponder ao tipo especificado, caso contrário, o método não corresponderá

Especificando como os períodos se parecerão

Esse objeto descreve propriedades do período que serão criadas se o método descrito em match for chamado:

  • name: Nome do intervalo
  • type: tipo de período (opcional); valores suportados:
    • ENTRY, usado para indicar chamadas "recebidas" de sistemas externos
    • INTERMEDIATE, usado para capturar chamadas internas para métodos "interessantes" (padrão)
    • EXIT, usado para indicar chamadas de "saída" para sistemas externos
  • stackDepth: número de estruturas de pilha a serem capturadas da chamada de método (opcional); o padrão é 0
  • tags: a lista de tags/anotações a serem capturadas e como obter seus valores (opcional); valores suportados:
    • constant, capturar um valor constante
      • kind: constant
      • name: o nome da tag a ser criada
      • value: o valor constante da tag a ser criada
    • return, capturar o valor de retorno da chamada de método
      • kind: return
      • name: o nome da tag a ser criada; o valor será aquele do objeto retornado
    • argument, capturar um valor do argumento específico da chamada de método
      • kind: argument
      • name: o nome da tag a ser criada
      • index: índice baseado em 0 do argumento para capturar como valor da tag
Observação: Se o valor capturado for null ou, Optional.empty a tag definida não será adicionada. Os intervalos com tags ausentes podem ser consultados no Unbounded Analytics usando o is not present operador em conjunto com o call.tag filtro.

Períodos errôneos

Se um valor Throwable for propagado para fora de um método instrumentado, o intervalo será automaticamente marcado como errado, e o valor de Throwable#getMessage() será definido como a mensagem de erro, que você poderá pesquisar no Unbounded Analytics por meio da call.error.message tag.

Verificando a configuração do SDK

  1. Verifique se a configuração foi analisada com sucesso. Nos registros do agente, procure uma mensagem semelhante a:
    Parsed configuration file /instana-agent/etc/instana/configuration.yaml 
  2. Verifique se a instrumentação foi aplicada. Após a análise, o agente registrará uma mensagem indicando que realizou a instrumentação do SDK:
    ... Spent XX ms and XXX KiB of Metaspace for instrumentation [sdk] ... 
  3. Ative e verifique os registros de rastreamento de intervalos do SDK. Para verificar se os spans estão realmente sendo criados, habilite o registro de rastreamento adicionando o seguinte ` YAML `:
    com.instana.plugin.javatrace: instrumentation: log: type: trace file: /tmp/trace.log 

Assim que a instrumentação estiver ativa e o código instrumentado for executado, você deverá ver os spans do SDK sendo emitidos. Exemplo de formato de log de rastreamento:

 -|EN|052d6bf37f16034c7:0:52d6bf37f16034c7|sdk:sdk.quarkus-hello|*com.instana.agent.instrumentation.sdk.SdkPlugin:start:789:SdkPlugin.java
    

Exemplo

O fragmento a seguir mostra uma configuração de exemplo de como as tarefas em lote de manipulação de aplicativo poderiam ser rastreadas:

com.instana.plugin.javatrace:
  instrumentation:
    sdk:
      targets:
        - match:
            type: class
            name: com.instana.java.sdk.BatchApplication
            method: processBatch
          span:
            name: Job
            type: ENTRY
            stackDepth: 2
            tags:
              - kind: constant
                name: endpoint
                value: BatchJob
              - kind: argument
                name: batch.job
                index: 0
        - match:
            type: class
            name: com.instana.java.sdk.BatchApplication
            method: updateDatabase
          span:
            name: DatabaseCall
            type: EXIT
            stackDepth: 2
            tags:
              - kind: constant
                name: db.connection_string
                value: jdbc:mysql://127.0.0.1:3306/jobs
              - kind: argument
                name: db.statement
                index: 0
 

Primeiramente, o método processBatch na classe com.instana.java.sdk.BatchApplication é instrumentado para criar períodos de entrada com o nome Job, a anotação endpoint com o valor constante BatchJob e a anotação batch.job com o primeiro argumento como o valor dela.

Além disso, as chamadas de saída do banco de dados durante o processamento em lote, ou seja, as chamadas de método updateDatabase na mesma classe, criarão períodos de saída com o nome DatabaseCall, a anotação db.connection_string com o valor constante jdbc:mysql://127.0.0.1:3306/jobs e a anotação db.statement com o primeiro argumento da chamada de método.

O processamento de um novo lote com processBatch iniciará um novo rastreio e as subsequentes atualizações do banco de dados com updateDatabase serão listadas como períodos filhos dentro dele. Todos os recursos da Instana, como o Unbounded Analytics, podem ser usados identicamente para rastreios criados com a Instana AutoTrace.

Limitações

As restrições a seguir aplicam-se ao Java Trace SDK baseado em configuração:

  • A instrumentação de construtores não é suportada.
  • Não há suporte para iniciar um período em um método e fechá-lo em outro, ou seja, o SDK baseado em configuração não tem nenhum equivalente para as anotações @Span.Start e @Span.End.
  • A captura de todos os argumentos ou o valor de retorno sem criar explicitamente uma tag não é suportada.
  • Não é permitido especificar placeholders na lista de argumentos para argumentos não essenciais ou para todos os demais; a correspondência baseada em argumentos é executada de forma estrita.
  • A especificação de padrões de nome para classes ou métodos não é suportada.
  • A restauração de um contexto de rastreio não é suportada antes da criação de um período, ou seja, o SDK baseado em configuração não tem um recurso equivalente a SpanSupport.inheritNext().
  • O SDK baseado em configuração não oferece suporte à instrumentação de classes do JDK.