Maneira rápida de obter informações de um arquivo de log enorme no unix

2

Eu tenho um arquivo de log de aplicativos de 6 GB. As linhas de log possuem o seguinte formato (encurtado)

[...]
timestamp;hostname;sessionid-ABC;type=m
timestamp;hostname;sessionid-ABC;set_to_TRUE
[...]
timestamp;hostname;sessionid-HHH;type=m
timestamp;hostname;sessionid-HHH;set_to_FALSE
[...]
timestamp;hostname;sessionid-ZZZ;type=m
timestamp;hostname;sessionid-ZZZ;set_to_FALSE
[...]
timestamp;hostname;sessionid-WWW;type=s
timestamp;hostname;sessionid-WWW;set_to_TRUE

Eu tenho muita sessão com mais do que essas duas linhas. Preciso descobrir todas as sessões com type=m e set_to_TRUE

Minha primeira tentativa foi grep todos os sessionIDs com type=m e gravar em um arquivo. Em seguida, loop com todas as linhas do arquivo (1 sessionID por linha) através do grande logfile e grep para sessionID;set_to_TRUE

Esse método leva muuuuito tempo. Alguém pode me dar uma dica para resolver isso de uma maneira muito melhor e mais rápida?

    
por xMaNuu 28.07.2017 / 12:36

5 respostas

1

Se cada sessão tiver um type correspondente e for set_to TRUE ou FALSE , você poderá usar sed e intervalos para isso:

sed '/type=m/,/set_to_/!d;/set_to_TRUE$/!d;s/.*\(sessionid-.*\);.*//' infile

Isso remove todas as linhas que não estão nos intervalos /type=m/,/set_to_/ . Também exclui as linhas nesses intervalos que não terminam em set_to_TRUE . O sessionid é então extraído da linha restante (se houver).
Alternativamente,

sed -n '/type=/h;/set_to_TRUE$/{
x;s/.*\(sessionid-.*\);type=m$//p
}' infile

deve imprimir o mesmo.
O último funciona sobrescrevendo o buffer de retenção em cada linha correspondente a type=
Em seguida, em cada linha correspondente a set_to_TRUE , os buffers são trocados e uma substituição é tentada - a saber, extraia sessionid de uma linha que termina em type=m - e, se bem-sucedida, o resultado será p rinted. Caso contrário, nada acontece porque a impressão automática está desativada por -n .
O acima assume que não há espaços em branco nas suas linhas.

    
por 28.07.2017 / 13:18
1

Use este comando awk :

awk -F";" '/type=m/{flag=$3;next} /set_to_TRUE/ && ($3==flag)' infile.txt

corresponderá se ambos os sessionIDs forem iguais e se as condições necessárias também forem vistas.

timestamp;hostname;sessionid-ABC;set_to_TRUE

acima irá imprimir toda a linha, você pode imprimir apenas a coluna desejada adicionando print $3 para ter somente sessionIDs, como abaixo:

awk -F";" '/type=m/{flag=$3;next} /set_to_TRUE/ && ($3==flag){print $3}' infile.txt
    
por 28.07.2017 / 13:19
1

Usando o grep, isso pode ser muito fácil:

grep -E "(type=|set_to_)" file.txt | grep -A 1 "type=m" | grep -B 1 "set_to_TRUE" > file1.txt &

Coloque no fundo, pegue um café e deixe terminar. Não tenho certeza se 'awk' nem 'sed' seriam mais rápidos. 6GB são muito para apenas texto, por isso vai demorar muito para você tentar.

Você verá quando terminar no console assim que pressionar Enter ou digitar outro comando como:

[1]+  Done                    grep --color=auto -E '(type=|set_to_)' file.txt | grep --color=auto -A 1 "type=m" | grep --color=auto -B 1 "set_to_TRUE" > file1.txt
    
por 28.07.2017 / 13:48
0

Suposições:

  • você só quer os nomes das sessões
  • a linha "type=" virá antes da linha "set_to_"
  • você realmente quis dizer que você só quer sessões onde "set_to_TRUE", como escrito na pergunta (que você contradisse em um comentário)

Se você precisar lidar com várias sessões abertas de uma só vez (não está claro), você pode fazer algo como (não testado):

perl -ne 'if (m/<timestamp>;<hostname>;(sessionid-[a-z]+);type=(.)/) { $type{$1}=$2 }; if (m/<timestamp>;<hostname>;(sessionid-[a-z]+);set_to_TRUE/) { if ($type{$1} eq "m") { print $1 } }'
    
por 28.07.2017 / 14:51
0
awk -F';' '/type=m/ { seen[$3]=1 };
           /set_to_TRUE/ && seen[$3] { print $3 ; delete seen[$3] };
           /set_to_FALSE/ && seen[$3] { delete seen[$3] }' logfile.txt

Isso é semelhante à resposta do @AFSHIN, mas em vez de usar apenas uma única variável ( flag ), ele usa uma matriz ( seen ) para rastrear quais IDs de sessão que correspondem à type=m .

Isso significa que funciona mesmo quando há outras type=m linhas para diferentes sessões entre o avistamento da linha type=m de qualquer sessão e o avistamento da linha set_to_ dessa sessão.

Para minimizar os requisitos de memória para o script, ele exclui o elemento seen da matriz para uma determinada ID de sessão assim que vê um set_to_TRUE ou set_to_FALSE .

correspondente

NOTA: O script acima imprime apenas os ids de sessão correspondentes. Se você quiser imprimir as linhas type=m e set_to_TRUE reais, o script awk seria:

awk -F';' '/type=m/ { seen[$3]=$0 };
           /set_to_TRUE/ && seen[$3] { print seen[$3]"\n"$0 ; delete seen[$3] };
           /set_to_FALSE/ && seen[$3] { delete seen[$3] }' logfile.txt

Isso tem o potencial de usar muito mais memória. Armazenar linhas de entrada inteiras em uma matriz requer muito mais RAM do que armazenar inteiros.

NOTA2: este script assume que os ids de sessão são únicos. Se, por exemplo, é possível que diferentes nomes de host (campo 2) possam gerar o mesmo id de sessão, tente isto:

awk -F';' '/type=m/ { seen[$3$2]=1 };
           /set_to_TRUE/ && seen[$3$2] { print $3 ; delete seen[$3$2] };
           /set_to_FALSE/ && seen[$3$2] { delete seen[$3$2] }' logfile.txt

ou

awk -F';' '/type=m/ { seen[$3$2]=$0 };
           /set_to_TRUE/ && seen[$3$2] {print seen[$3$2]"\n"$0;delete seen[$3$2]};
           /set_to_FALSE/ && seen[$3$2] { delete seen[$3$2] }' logfile.txt
    
por 29.07.2017 / 05:58