exibe apenas partes de linhas do arquivo de log ao vivo

2

Temos um arquivo de log que eu geralmente acompanho ao vivo com tail e uso o grep para filtrar as linhas que me interessam. No entanto, as linhas contêm muitos dados nos quais nem sempre estou interessado, mas eles têm sido difíceis para eu analisar, então eu só vejo as porções da linha que eu quero. O formato de cada entrada de linha é principalmente uma lista de tags e os dados (às vezes contendo espaços) cercados por aspas. Aqui estão algumas linhas de registro de amostra (higienizadas):

2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="CONNECT" srcip="10.11.12.13" dstip="14.3.1.4" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1234 (Campus2)" filteraction="REF_HttStu (Allow Policy)" size="6518" request="0x915a3e00" url="https://website.net/" referer="" error="" authtime="0" dnstime="1" cattime="73" avscantime="0" fullreqtime="61576999" device="0" auth="6" ua="" exceptions="" category="9998" reputation="unverified" categoryname="Uncategorized" country="United States" application="krux" app-id="826"
2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="GET" srcip="10.13.14.15" dstip="154.6.75.10" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1235 (Campus1)" filteraction="REF_HttStu (Allow Policy)" size="3161" request="0x6b4d5610" url="http://host.com/mini_banner.png" referer="http://www.web.com/computers.htm" error="" authtime="0" dnstime="0" cattime="64" avscantime="848" fullreqtime="50046" device="0" auth="6" ua="Mozilla/5.0 (X11; CrOS x86_64 9765.85.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.123 Safari/537.36" exceptions="" category="111" reputation="trusted" categoryname="Education/Reference" sandbox="-" content-type="image/png"

Uma coisa a notar é que todas as tags não estão presentes em todas as linhas. Por exemplo, o aplicativo e o ID do aplicativo estão presentes na primeira linha, mas não no segundo.

Usando as linhas acima como entrada de exemplo, um exemplo do que eu gostaria de ter como saída seria mostrar apenas as tags srcip, categoryname e url nessa ordem. A saída desejada seria algo como isto:

10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png

Estou à procura de uma solução que seja facilmente adaptável, por isso, posso ajustar as tags que são exibidas.

    
por Andrew S 30.11.2017 / 00:55

2 respostas

2

Seus dados são altamente estruturados como key="value" , para que você possa escreva um script de shell pequeno usando o gnu awk, que toma como argumento uma lista de nomes de chaves e apenas imprime esses valores. Por exemplo, myscript :

#!/bin/bash
awk -v lhs="$*" '
BEGIN{  FPAT = "[a-z-]*=\"[^\"]*\""
        nwant = split(lhs,want)
}
{       for(i=1;i<=NF;i++){
            start = match($i,/([a-z-]*)="([^"]*)"/,a)
            key[a[1]] = a[2]
        }
        for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
        printf "\n"
}'

que você chama de myscript srcip categoryname url . Isso define a variável awk lhs para os argumentos como uma única string, que são divididos em array want no início. As linhas são divididas por awk em campos que correspondem ao padrão key="value" usando a variável incorporada FPAT .

Em cada linha, dividimos cada campo com match() em 2 grupos capturados, para a chave e para a parte entre aspas duplas. Estes são colocados pelo awk no array a , e nós os salvamos em um array associativo key indexado pela string de chave.

Em seguida, para cada chave desejada, imprimimos o valor e o desmarcamos para a próxima linha (caso essa linha não tenha essa chave). Obviamente, isso pressupõe que todos os dados tenham a estrutura necessária e precisarão de alterações para manipular (") dentro do valor ou chaves com caracteres não-alfabéticos.

Versões do gnu awk (gawk) anteriores a 4.0 não possuem o FPAT embutido para dividir a linha em campos que correspondem a um padrão, então você precisa fazer isso sozinho:

#!/bin/bash
awk -v lhs="$*" '
BEGIN{ nwant = split(lhs,want) }
{       input = $0
        while(match(input,"[a-z-]*=\"[^\"]*\"")>0){
            field = substr(input,RSTART,RLENGTH)
            input = substr(input,RSTART+RLENGTH)
            start = match(field,/([a-z-]*)="([^"]*)"/,a)
            key[a[1]] = a[2]
        }
        for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
        printf "\n"
}'

Obviamente, você pode combinar as duas chamadas de correspondência em uma, mas isso mostra a diferença com a original.

    
por 30.11.2017 / 15:10
1

Usando (compatível com POSIX) sed ...

sed 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/  /' logfile

Nada interessante aqui, basta encontrar as chaves e cercar os valores com parens \(..\) , o que permite que eles sejam usados como referências anteriores. Em seguida, substituímos a cadeia por apenas as referências de referência, delimitadas por espaço, ordenadas por sua exigência: .

Saída:

10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png

Se os registros contiverem strings que não possuam todas essas chaves, você poderá usar:

sed -n 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/  /p' logfile

Isso só imprimirá linhas que correspondam ao padrão.

E, claro, se você quiser usá-los de forma fluida, basta remover o nome do arquivo e fazer [something sending logs to stdout] | sed ...

    
por 30.11.2017 / 02:38

Tags