Usando Eclipse AspectJ para injetar um Logger que Logs contexto / metadados do código executam?

Sep 21 2020

Estou tentando definir um aspecto para injetar um logger.

Estou procurando criar algo como:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public aspect LogInjector {

    private pointcut executionJoinPoints(): !within(LogInjector) && execution (* *.*(..));

    before(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get params name, type and values triplet or values at least if the previous is not possible, of the executed code
        params = ...

        // Get call stack of the executed code
        stack = ...

        logger.trace("{}.{}({}) - {}", clazz.name(), method.name(), params, stack);
    }

    after(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get return value or exception of the executed code
        result = ...

        logger.trace("{}.{} = {}", clazz.name(), method.name(), result);
    }
}

Para isso, desejo recuperar metadados de execução / dados de contexto:

  • exceções
  • valores de retorno

Como posso obter esses metadados / dados de contexto?

Respostas

1 kriegaex Sep 22 2020 at 02:51

Para manter seu aspecto eficiente, recomendo o seguinte:

  • Limite seu pointcut aos pacotes e classes de destino que você realmente deseja depurar. Não registre / rastreie o mundo inteiro. Você também pode usar um aspecto de base abstrato com um corte de ponto abstrato e estender o aspecto em um sub-aspecto concreto com um corte de ponto concreto. O último pode até ser fornecido por meio da configuração XML se você usar o entrelaçamento do tempo de carregamento.
  • Use um around()conselho em vez de um par before()/ after(). Então você só precisa calcular alguns dos valores registrados uma vez e usá-los antes e depois da chamada do método original feita via proceed().
  • Simplesmente registre em thisJoinPointvez de juntar os bits contidos nele por padrão. Isso já fornecerá o tipo de ponto de junção, assinatura do método, incluindo tipos de parâmetro e valor de retorno.
  • Não registre nomes de parâmetros, as informações não agregam valor real. Além disso, os nomes dos parâmetros estão sujeitos a refatoração e só estarão presentes se o seu código for compilado com informações de depuração. Mantenha-o simples e registre apenas os valores dos parâmetros.
  • No around()conselho mencionado acima, você pode incluir a proceed()chamada try-catch-finallye manipular e registrar convenientemente quaisquer exceções e rastreamentos de pilha e / ou agrupar exceções verificadas em AspectJs SoftExceptionou um simples RuntimeExceptione relançá-las. O que for aplicável à sua situação.
  • Os resultados da chamada de método são apenas os resultados de proceed(), que seria você também o que você precisa para retornar do around()conselho. Você também pode retornar algo diferente (mas deve ter o tipo de retorno correto) ou ignorar completamente proceed()se, por qualquer motivo, desejar ignorar a execução do método de destino.

Tudo o que acabei de dizer está escrito no manual do AspectJ ou em qualquer outro tutorial do AspectJ. Você pode querer ler alguns deles na próxima vez, antes de fazer uma pergunta geral como esta.