Registrar Intervalos do APM como Eventos de JFR

O Rastreador do APM e o Agente do APM suportam a gravação de intervalos do APM como Eventos de JFR.

No momento, o JDK 11 ou mais recente são suportados.

Para obter informações sobre como gravar intervalos do APM como eventos de JFR ao usar o Agente do APM, consulte Registrar Intervalos do APM como Eventos de JFR em Provisionar e Implantar Agentes Java do APM em Servidores de Aplicativos.

Observação

O Java Flight Recorder (JFR) é uma ferramenta para coletar dados de diagnóstico e criação de perfil sobre um aplicativo Java em execução. Para obter informações sobre o Java Flight Recorder (JFR) e o Java Mission Control (JMC), consulte JDK Mission Control.

Capturar Eventos do APM em Gravações de JFR

Para capturar eventos do APM em gravações de JFR ao usar o Rastreador do APM, siga estas etapas:

  1. Verifique se o Rastreador do APM está funcionando corretamente.

    Abra o Trace Explorer e confirme se você pode exibir todos os rastreamentos. Para obter informações sobre como abrir e usar o Trace Explorer, consulte Monitorar Rastreamentos no Trace Explorer.

  2. Adicione uma dependência ao projeto Maven que permitirá que o Rastreador do APM adicione eventos às gravações de JFR feitas pela JVM Helidon.

    <dependency>
        <groupId>com.oracle.apm.agent.java</groupId>
        <artifactId>apm-java-agent-jfr11</artifactId>
        <version>[1.0.1389,)</version>
    </dependency>
  3. Inicie uma gravação.

    Para testar se tudo está funcionando corretamente, você precisa iniciar uma gravação usando o seu método preferencial (Pode ser usando a interface de usuário do JDK Mission Control ou o utilitário de linha de comando JCMD). Após a inicialização de uma gravação, os eventos de rastreamento são exibidos na interface de usuário do JDK Mission Control quando a gravação é visualizada.

    Para verificar se os eventos de rastreamento do APM foram adicionados corretamente às gravações de JFR, conecte-se ao JDK Mission Control e confirme se os rastreamentos do APM estão visíveis no Browser do Eventos: clique em OpenTracing do APM e confirme se os eventos de rastreamento do APM estão visíveis.

Configurar Eventos de JFR no Rastreador do APM

(Opcional) Esta é uma etapa opcional se você quiser personalizar o relatório dos eventos.

Para simplificar a análise de eventos de gravação de JFR, cada evento é organizado em uma categoria ou um tipo de evento.

Categoria Padrão

No Rastreador do APM, a categoria padrão para eventos de JFR do APM é obtida usando o conteúdo do Span Operation Name (em um campo chamado name dentro do Intervalo). A tag component não pode ser preenchida; portanto, não pode ser usada como categoria padrão.

Eventos

Um tipo de evento permite que os eventos sejam organizados e classificados na interface de usuário do JMC. Quando o Rastreador do APM obtém um intervalo, ele pode gerar um evento para esse intervalo, mas ele precisa determinar o tipo de evento desse evento específico.

Exemplos de tipo de evento são servlet, jdbc e jax-rs.

Configuração do Tipo de Evento

Há várias maneiras de fazer a configuração de um tipo de evento ou categoria. Veja abaixo os diferentes casos de uso:

  • Caso 1: tag component

    Essa é a maneira mais simples de classificar um evento. Esse é o método recomendado a ser usado.

    Na maioria dos cenários, o intervalo do Opentracing conterá uma tag chamada component. O valor da tag component é usado para determinar o tipo de evento.

    Por exemplo, consulte o seguinte intervalo:

    {  "id":"e926ff3d06013045",
      "trace-id":"49abd92e69786853e926ff3d06013045",
      "parent-id":"6ef54ec2c524c99a",
      "name":"content-write",
      "ts-micros":1614190751360177,
      "td-micros":219348,
      "attributes":{
        "server":"Helidon SE",
        "http.url":"http://localhost:8079/health",
        "http.status_code":200,
        "component":"helidon-webserver",
        "http.method":"GET",
        "organization":"development"
      },
      "events":[
      ]
    },

    Nesse caso, o evento gerado receberá um tipo de evento helidon-webserver, pois esse é o valor da tag component.

  • Caso 2: Outra tag

    Se seu aplicativo não usar a tag component, mas usar outra tag ou houver uma biblioteca que esteja gerando as tags para você, o Rastreador do APM poderá ser configurado para ler o tipo de evento dessa outra tag.

    Por exemplo, consulte o seguinte intervalo no qual você pode ler o tipo de evento da tag chamada span.type:

    {  "id":"e926ff3d06013045",
      "trace-id":"49abd92e69786853e926ff3d06013045",
      "parent-id":"6ef54ec2c524c99a",
      "name":"content-write",
      "ts-micros":1614190751360177,
      "td-micros":219348,
      "attributes":{
        "server":"Helidon SE",
        "http.url":"http://localhost:8079/health",
        "http.status_code":200,
        "span.type":"helidon-webserver",
        "http.method":"GET",
        "organization":"development"
      },
      "events":[
      ]
    },

    Nesse caso, você pode obter o Rastreador do APM para ler o tipo de evento da tag span.type usando a seguinte propriedade do sistema ao iniciar o aplicativo java:

    java -Dcom.oracle.apm.agent.jfr.category.tag=span.type ...
  • Caso 3: Uso do Nome da Operação quando nenhuma tag estiver disponível

    Se seu aplicativo não usar qualquer tag que tenha categorias úteis, será possível usar Operation Name para determinar o tipo de evento, mas esse método não é recomendado.

    O sistema JFR exige que o nome do tipo de evento seja um identificador Java válido, mas o Operation Name geralmente tem espaços e também outros caracteres inválidos. O Rastreador do APM converterá o Operation Name em um identificador válido substituindo todos os caracteres ilegais por um sublinhado.

    java -Dcom.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMES
    Observação

    O Operation Name só será usado se a tag de categoria estiver ausente ou vazia.

    Esta não é uma solução simples porque o Operation Name pode conter tokens exclusivos, como IDs, que transformarão cada evento no próprio tipo de evento. Além disso, a conversão do Operation Name em um identificador válido causará mais problemas na configuração do tipo de evento para configurar quais campos são necessários no evento e também, a configuração precisará ser feita com base no Operation Name convertido do contrário, você precisará configurar muitas variantes distintas do Operation Name da mesma maneira.

  • Caso 4: Não há tags disponíveis e todos os Nomes de Operação são exclusivos

    Nesse caso, não há informações disponíveis para classificar os tipos de evento. Esse é o pior cenário de caso em que todos os eventos terminarão como o mesmo tipo de evento ou todos serão exclusivos se forem configurados usando o cenário do caso de uso 3 conforme visto acima. A única coisa possível a fazer é permitir que você escolha o nome desse tipo de evento padrão, e isso pode ser configurado conforme mostrado abaixo.

    java -Dcom.oracle.apm.agent.jfr.category.default=Unknown
    Observação

    O padrão só será usado se a tag de categoria estiver ausente ou vazia.

    Nesse caso, todos os eventos serão colocados no tipo de evento chamado Unknown ou qualquer valor personalizado será selecionado.

Campos para o tipo de evento

Para cada tipo de evento, podemos adicionar 1 ou mais campos que contêm dados específicos àquele evento.

A lista de campos que podem ser adicionados ao tipo de evento precisa ser configurada no arquivo ACML e, somente depois, os campos podem ser publicados no JFR. Para cada campo, são necessárias as seguintes informações:
  • Nome.
  • Tipo (int, float, string, thread).
  • Label.
  • Descrição.
Por exemplo, consulte a seguinte definição de campo para traceID:
- name: traceID
  type: String
  label: New Trace ID
  description: New Opentracing Trace ID

Criar um Arquivo ACML

Esta etapa é opcional. Se as definições padrão estiverem funcionando conforme esperado, você poderá ignorar esta etapa.

Você pode criar um arquivo ACML se quiser alterar as definições padrão e personalizar as gravações.

O exemplo a seguir mostra o formato de um arquivo ACML configurando o registro de evento em log para o JFR substituindo as definições padrão incorporadas para o contêiner de microsserviços do Helidon:

caseSensitiveFieldName: false
recordCallStack: true

eventTypes:
  helidon-webserver:
    name: helidon-webserver
    label: Helidon Webserver Events
    description: All events based on helidon webserver
    recordCallStack: true
    # All fields must be provided here.
    # Fields are NOT incremental since that would make them impossible to remove 
    fields:
      - name: traceID
        type: String
        label: New Trace ID
        description: New Opentracing Trace ID
      - name: spanID
        type: String
        label: New Span ID
        description: New Opentracing Span ID
      - name: http.url
        type: String
        label: New HTTP URL
        description: The New URL for the HTTP endpoint being hit
      - name: organization
        type: String
        label: Organization
        description: The New Organization value of this call
      - name: startThread
        type: Thread
        label: Start Thread
        description: The thread on which this event started
      - name: http.status_code
        type: int
        label: Status Code
        description: The HTTP Response status code
      - name: http.method
        type: String
        label: HTTP Method
        description: The HTTP Method

Você pode usar o formato acima do arquivo ACML ao usar o Agente do APM e o Rastreador do APM. Para o Rastreador do APM, ele funcionará para qualquer contêiner, como Helidon, Springboot e Micronaut.

Perguntas Mais Frequentes

  1. Quando você tem as duas definições fornecidas: propriedades com.oracle.apm.agent.jfr.category.tag e com.oracle.apm.agent.jfr.category.default, qual definição tem prioridade?

    Se ambas tiverem um valor, primeiro pesquisaremos no intervalo a tag de categoria. Caso seja encontrada, ela será usada. Caso esteja ausente, o padrão será usado.

  2. Para o Rastreador do APM, é obrigatório o uso de um arquivo de configuração? Posso apenas especificar as propriedades sem arquivo?

    Um arquivo de configuração não é obrigatório. Se o padrão funcionar para você, você não precisará de um arquivo de configuração e ainda poderá especificar as propriedades.

  3. Em alguns casos, por que parece que as entradas estão duplicadas? Por exemplo, o seguinte trecho de código do arquivo de configuração ACML tem a entrada helidon-webserver duas vezes:
    eventTypes:
      helidon-webserver:
        name: helidon-webserver

    A primeira entrada helidon-webserver é o que lemos/deduzimos das tags ou do nome da operação. Se o tipo de evento for claro, fácil de ler e intuitivo, como o exemplo acima, você poderá usar o mesmo tipo de evento para enviar para a gravação JFR, e assim ele será exibido no JMC.

    No entanto, às vezes, ao usar o operation name, você pode obter um tipo de evento como o seguinte: q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A=, que representa uma consulta JDBC de um cliente db. Nesse caso, você gostaria de alterar o nome enviado para a gravação de JFR para algo intuitivo, portanto, o exemplo abaixo pode ser usado nestes casos:
    eventTypes:
      q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A=:
        name: jdbc-select-query
  4. Se recordCallStack puder ser especificado para cada tipo de evento, por que também é necessário ter recordCallStack de nível superior?

    Oferecemos suporte a dois casos de uso para máxima flexibilidade no registro da pilha de chamadas. O registro da pilha de chamadas pode ser desativado globalmente e, em seguida, pode ser ativado seletivamente para tipos de evento específicos. Outra opção é ativá-lo globalmente e, em seguida, ele pode ser desativado seletivamente para tipos de evento específicos. Ambos os casos de uso são suportados; portanto, a definição está no nível superior e no nível do evento.

  5. Tenho alguns intervalos que não foram configurados e eles estão sendo ignorados. Ainda é possível capturar esses eventos sem configurá-los?

    Sim. Se você definir allowUnconfiguredEvents: true na configuração de nível superior principal, esses eventos serão capturados. Quando isso acontece, não sabemos quais campos devem ser coletados. Somente o seguinte conjunto de campos padrão é coletado: traceID, spanID, parentSpanID, startThread e operationName.

  6. Se eu tiver usado com.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMES para usar categorias definidas pelo nome da operação, o nome da operação deverá corresponder exatamente ao nome do tipo de evento no arquivo de configuração? Em caso afirmativo, e se eu tiver nomes de operação exclusivos, precisarei especificar um tipo de evento para cada operação?

    Sim, ele deve corresponder ao nome do tipo de evento no arquivo de configuração. Mesmo que você tenha muitos nomes de operação exclusivos, será necessário especificar um tipo de evento para cada operação, pois cada um desses tipos de evento provavelmente terá um conjunto diferente de campos que precisam ser configurados.

  7. Meu Nome da Operação está sendo convertido em um identificador Java, portanto, não consigo configurar seu tipo de evento. Como faço para determinar a qual meu Nome da Operação foi convertido?

    Todos os caracteres inválidos foram substituídos por um sublinhado. Se você precisar de um código Java de amostra para converter suas strings em identificadores, poderá usar o código a seguir, que é a mesma rotina que o APM usa para converter as strings.
    // Convert an arbitrary string into a valid java identifier by replacing non-identifier chars with an underscore
    public static String getJavaIdentifier(String inString)
    {
        if (inString == null || inString.length() == 0)
           return inString;
        StringBuilder stringBuilder = new StringBuilder();
        char[] allChars = inString.toCharArray();
    
        if(Character.isJavaIdentifierStart(allChars[0]))
            stringBuilder.append(allChars[0]);
        else
            stringBuilder.append("_");
    
        for (int i = 1; i < allChars.length; i++)
        {
            if (Character.isJavaIdentifierPart(allChars[i]))
                stringBuilder.append(allChars[i]);
            else
                stringBuilder.append("_");
        }
        return stringBuilder.toString();
    }
  8. A correspondência de nome pode ser RegEx?

    Não. Não há suporte para RegEx.