Aqui está uma solução de awk
que simplifica as coisas processando a saída na ordem inversa (requer o comando tac
, que é parte dos GNU coreutils):
Primeiro, o script awk
(coloque em um arquivo como 'process.awk'). É um pouco longo demais para um bash
one-liner.
BEGIN { output=0; any=0; }
/^Test .* FAILED/ { output=1; any=1; }
/^Test .* PASSED/ { output=0; }
/^Start test group/ && any == 1 { output=1; any=0; }
output == 1 { print; }
Em seguida, execute esse script no arquivo de log invertido e inverta a saída:
tac logfile | awk -f process.awk | tac
Como funciona?
Primeiro, passamos nossa entrada através de tac
para reverter a ordem das linhas (para que possamos determinar se as linhas "a seguir" pertencem a um teste FAILED ou PASSED antes de lê-las).
O script funciona da seguinte maneira. Cada ação consiste em uma condição que deve ser correspondida, seguida por um bloco de código a ser executado se a linha atual corresponder à condição.
A primeira ação é uma ação BEGIN, que é sempre executada uma vez antes de começarmos a examinar a entrada. Inicializou duas flags booleanas que controlam o que é impresso. output
será definido como 1 se quisermos imprimir a linha atual, 0 caso contrário. any
será definido como 1 sempre que encontrarmos um teste FAILED e redefinido como 0 depois que terminarmos de processar um grupo de teste. Ambos os valores começam em 0.
A próxima ação testa a linha atual para ver se é o início de um teste com falha (lembre-se de que estamos processando a saída na ordem inversa). Em caso afirmativo, defina os dois output
e any
.
A próxima ação testa a linha atual para ver se é o início de um teste passado. Nesse caso, limpe o sinalizador output
, mas deixe any
sozinho. (Ainda pode haver um teste com falha antes do final do grupo de teste).
A próxima ação testa a linha atual para ver se é o cabeçalho do grupo de teste e se o sinalizador any
está definido. Se estiver, queremos imprimir o cabeçalho (tivemos pelo menos um teste com falha), então defina output
e limpe any
(para preparar o próximo grupo de teste). Caso contrário, não precisamos fazer nada; any
já é 0 e output
não pode ter sido definido como 1
se any
nunca foi.
Por fim, temos uma ação que não examina a linha atual, mas apenas verifica se alguma das ações anteriores definiu output
. Se tiverem, imprimimos a linha atual (que pode ser uma linha "Teste FALHADO", algumas informações detalhadas que "precedem" a linha FAILED ou um cabeçalho de grupo de teste).
Quando todas as ações estiverem esgotadas, passamos para a próxima linha de entrada e tentamos aplicar cada ação novamente. Depois que toda a entrada estiver esgotada, teremos impresso cada uma das linhas de saída que queremos, mas na ordem inversa. Piping a saída através de tac
corrige isso.
Observe que o script pode ser um pouco mais eficiente ao custo de torná-lo mais complexo, mas deve ser rápido o suficiente.