Obtém informações específicas de um arquivo de log

1

Eu quero pegar algumas partes do meu arquivo de log, eu tentei cortar parte da solicitação para obter o usuário, módulo, ação, doAjax e ajaxAction

Por exemplo, eu tenho

195.xx.x.x - - [25/Apr/2017:09:60:xx +0200] "POST /userx/index.php?m=contacts&a=form&...
192.xx.x.x - - [25/Apr/2017:09:45:xx +0200] "POST /usery/index.php?m=customer&doajax=request&action=getContacts...
197.xx.x.x - - [25/Apr/2017:09:20:xx +0200] "GET /userx/index.php?m=meeting&doajax=date&id=3

e eu quero ter:

[user]|[module]|[action]|[doAjax]|[ajaxAction] 
usery  contacts  form     null     null
userx  customer  null     request  getContacts
userz  meeting   null     date     null

Onde:

userx --> user  
m=xxx -->module   
a=xxx -->action  
doajax=xxx-->doAjax   
action=xxx-->ajaxAction  

Eu tentei usar awk , mas para cortar apenas a sétima coluna onde posso encontrar minha solicitação com este comando:

awk '{printf $7; next ; }' logfile

Então, como eu posso fazer para extrair o usuário, módulo, ação, doAjax e ajaxAction depois de imprimir apenas o meu pedido?

    
por Sara Quispe 26.04.2017 / 17:32

3 respostas

2

Um perl "one-liner":

$ perl -lne '
BEGIN{
    printf "%-10s%-10s%-10s%-10s%-15s\n", qw([user] [module] [action] [doAjax] [ajaxAction]);
} 
$usr = $mde = $act = $doAj = $ajAc = "null"; 
$usr=$1 if m|\s/([^/]+)/|; 
$mde=$1 if /m=(.+?)(&|$)/; 
$act=$1 if /a=(.+?)(&|$)/; 
$doAj=$1 if /doajax=(.+?)(&|$)/; 
$ajAc=$1 if /action=(.+?)(&|$)/; 
printf "%-10s%-10s%-10s%-10s%-15s\n", ($usr,$mde,$act,$doAj,$ajAc)' file 
[user]    [module]  [action]  [doAjax]  [ajaxAction]   
userx     contacts  form      null      null           
usery     customer  null      request   getContacts    
userx     meeting   null      date      null           

O truque básico aqui é procurar por cada uma das strings que identificam suas partes de URL e, se encontradas, definir a variável correspondente para ela. Em cada caso, procuramos o identificador seguido por um = (por exemplo, m= ) e, em seguida, um & ou o final da linha (&|$) . Como a parte correspondida é colocada entre parênteses (por exemplo, m=(.+?) ), podemos nos referir a ela como $2 e isso é o que é salvo em cada variável.

Se você realmente precisa ter o | como separador e não se opõe ao fato de que ele tornará a saída menos legível, você pode usar isso:

$ perl -lne '
BEGIN{
    printf "%s|%s|%s|%s|%s\n", qw([user] [module] [action] [doAjax] [ajaxAction]);
} 
$usr = $mde = $act = $doAj = $ajAc = "null"; 
$usr=$1 if m|\s/([^/]+)/|; 
$mde=$1 if /m=(.+?)(&|$)/; 
$act=$1 if /a=(.+?)(&|$)/; 
$doAj=$1 if /doajax=(.+?)(&|$)/; 
$ajAc=$1 if /action=(.+?)(&|$)/; 
print join "|", ($usr,$mde,$act,$doAj,$ajAc)' file 
[user]|[module]|[action]|[doAjax]|[ajaxAction]
userx|contacts|form|null|null
usery|customer|null|request|getContacts
userx|meeting|null|date|null

Uma abordagem melhor (saída mais legível) seria usar printf :

    
por 26.04.2017 / 18:26
2

Se você preferir fazer isso no awk, você pode fazer o seguinte. O Split permite dividir uma string com qualquer separador de campo.

awk  '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); print a[2], c[1], d[1], d[2] }' logfile

Isso gera as colunas desejadas.

userx contacts a form
usery customer doajax request
userx meeting doajax date

O passo restante é formatar. Matrizes no awk são associativas e podem ser indexadas com strings - veja aqui . Você pode fazer o seguinte; aqui, op (abreviação de output) é inicializado como null. Então, definimos op[d[1]]=d[2] .

awk  '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); op["a"]="null"; op["doajax"]="null"; op["ajaxaction"]="null"; op[d[1]]=d[2];print a[2], c[1], op["a"], op["doajax"], op["ajaxaction"] }' junk.txt 

[modificado para]

awk  '{split($7,a,"/"); split(a[3],b,"m="); split(b[2],c,"&"); split(c[2],d,"="); op["a"]="null"; op["doajax"]="null"; op["action"]="null"; op[d[1]]=d[2]; split(c[3],f,"="); split(f[2],g,"."); op[f[1]]=g[1]; print a[2], c[1], op["a"], op["doajax"], op["action"] }' junk.txt 

A saída é a seguinte

userx contacts form null null
usery customer null request getContacts
userx meeting null date null
    
por 26.04.2017 / 19:03
0
perl -lane '
BEGIN {
   print $H = join "|", map { s/.*/[$&]/r } @H = qw/user module action doAjax ajaxAction/;
   pos($H) = 0;
   push(@pos, pos($H)-$p), $p=pos($H) while $H =~ /\[/g;
   $fmt = join "", map { "\%-${_}s" } @pos[1..$#pos], length($H)-$p;
}

   my(%h, %H) = $F[-1] =~ /[?&]\K([^=]+)=([^&]+)/g;
   @H{@H} = ($F[-1] =~ m|^/([^/]+)|, @h{qw/m a doajax action/});
   print sprintf $fmt, map { $H{$_} // "null" } @H;
' logfile

Resultados

[user]|[module]|[action]|[doAjax]|[ajaxAction]
userx  contacts form     null     null
usery  customer null     request  getContacts
userx  meeting  null     date     null

Explicação

  1. Opções de Perl:

    -l torna ORS = RS = \n

    -a armazena campos na matriz @F obtida dividindo o registro atual em /\s+/ , portanto, por exemplo, $F[0] => $1, $F[1] => $2, ..., $F[-1] => $NF

    -n configura um loop implícito que lê o arquivo de entrada linha por linha E nenhuma saída a menos que seja solicitada.

  2. Bloco BEGIN:

    Primeiro, imprimimos o cabeçalho. Em seguida, determinamos o formato dinamicamente com base no cabeçalho. Para cada linha lida, configuramos um hash% h cujas chaves são as strings before = e os valores são a string depois de =. A cadeia a ser olhada é confinada por? ou & à esquerda e & a direita. Em seguida, configuramos outro hash% H cujas chaves são renomeadas como versões de% h hash. Em seguida, imprimimos o hash com base no formato que calculamos no bloco BEGIN.

por 27.04.2017 / 04:18