Introdução
Bem-vindo ao mundo do processamento de texto com o AWK. Neste laboratório, você aprenderá a usar o comando awk para analisar arquivos de log, uma tarefa comum para administradores de sistemas e analistas de dados. O AWK é uma ferramenta poderosa para processar dados de texto estruturados no Linux, permitindo extrair, filtrar e transformar informações de forma eficiente.
Imagine que você é um administrador de sistemas júnior encarregado de analisar logs de servidor para identificar possíveis ameaças à segurança e problemas de desempenho. O comando awk será sua principal ferramenta para essa tarefa, permitindo que você examine rapidamente grandes arquivos de log e extraia insights significativos.
Examinando o Arquivo de Log
Vamos começar examinando o conteúdo do nosso arquivo de log de exemplo. Este arquivo contém logs de acesso ao servidor simulados que analisaremos ao longo deste laboratório.
Primeiro, navegue até o diretório do projeto:
cd ~/project
Agora, vamos visualizar as primeiras linhas do arquivo de log:
head -n 5 server_logs.txt
Você deverá ver uma saída semelhante a esta:
2023-08-01 08:15:23 192.168.1.100 GET /index.html 200
2023-08-01 08:16:45 192.168.1.101 GET /about.html 200
2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 08:18:12 192.168.1.103 GET /products.html 404
2023-08-01 08:19:05 192.168.1.104 GET /services.html 200
Este arquivo de log contém informações sobre solicitações ao servidor, incluindo data e hora, endereço IP, método HTTP, recurso solicitado e código de status.
Uso Básico do AWK - Imprimindo Campos Específicos
Agora que vimos a estrutura do nosso arquivo de log, vamos usar o AWK para extrair informações específicas. Por padrão, o AWK divide cada linha em campos com base em espaços em branco. Podemos nos referir a esses campos usando $1, $2, etc., onde $1 é o primeiro campo, $2 é o segundo, e assim por diante.
Vamos extrair os endereços IP (o terceiro campo) do nosso arquivo de log:
awk '{print $3}' server_logs.txt | head -n 5
Você deverá ver uma saída semelhante a esta:
192.168.1.100
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104
Neste comando:
awk '{print $3}'diz ao AWK para imprimir o terceiro campo de cada linha.- Usamos o pipe (
|) para enviar a saída para ohead -n 5para limitar a exibição às primeiras 5 linhas.
Agora, vamos imprimir tanto o endereço IP quanto o recurso solicitado:
awk '{print $3, $5}' server_logs.txt | head -n 5
Saída:
192.168.1.100 /index.html
192.168.1.101 /about.html
192.168.1.102 /login.php
192.168.1.103 /products.html
192.168.1.104 /services.html
Aqui, estamos imprimindo o terceiro campo (endereço IP) e o quinto campo (recurso solicitado) para cada linha.
Filtrando Entradas de Log
Um dos pontos fortes do AWK é sua capacidade de filtrar dados com base em condições. Vamos usar esse recurso para encontrar todas as solicitações POST em nosso arquivo de log, pois elas podem ser mais sensíveis à segurança do que as solicitações GET.
Execute o seguinte comando:
awk '$4 == "POST" {print $0}' server_logs.txt
Este comando pode imprimir centenas de linhas porque o arquivo de exemplo contém 5.000 entradas de log. Se você quiser apenas inspecionar uma amostra gerenciável enquanto aprende, adicione | head -n 10:
awk '$4 == "POST" {print $0}' server_logs.txt | head -n 10
A verificação ainda aceita o comando awk simples, então use a versão que ajudar você a ler a saída com mais conforto.
Vamos analisar a sintaxe deste comando para entender como a filtragem do AWK funciona:
$4 == "POST"- Este é um padrão ou condição que o AWK avalia para cada linha:$4refere-se ao quarto campo na linha atual (em nosso arquivo de log, este é o método HTTP)==é o operador de igualdade que verifica se dois valores são iguais"POST"é a string com a qual estamos comparando
{print $0}- Esta é a ação que o AWK executa quando a condição é verdadeira:- As chaves
{}envolvem a ação printé o comando para exibir texto$0representa a linha inteira atual (todos os campos)
- As chaves
A estrutura do comando segue o padrão do AWK: condição {ação}. O AWK lê cada linha e, se a condição for avaliada como verdadeira, ele executa a ação. Se nenhuma condição for especificada (como em nossos exemplos anteriores), a ação é executada para todas as linhas.
Você deverá ver uma saída semelhante a esta:
2023-08-01 08:17:30 192.168.1.102 POST /login.php 302
2023-08-01 09:23:45 192.168.1.110 POST /submit_form.php 200
2023-08-01 10:45:12 192.168.1.115 POST /upload.php 500
Agora, vamos encontrar todas as solicitações que resultaram em um status 404 (Não Encontrado):
awk '$6 == "404" {print $1, $2, $5}' server_logs.txt
Este comando segue o mesmo padrão, mas com valores diferentes:
- A condição
$6 == "404"verifica se o sexto campo (código de status) é igual a 404 - A ação
{print $1, $2, $5}imprime apenas campos específicos:$1- Primeiro campo (data)$2- Segundo campo (hora)$5- Quinto campo (recurso solicitado)
Essa impressão seletiva permite que você se concentre apenas nas informações de que precisa.
Saída:
2023-08-01 08:18:12 /products.html
2023-08-01 09:30:18 /nonexistent.html
2023-08-01 11:05:30 /missing_page.html
Você pode combinar várias condições usando operadores lógicos:
&¶ E (ambas as condições devem ser verdadeiras)||para OU (pelo menos uma condição deve ser verdadeira)!para NÃO (nega uma condição)
Por exemplo, para encontrar todas as solicitações POST que resultaram em um erro (código de status >= 400):
awk '$4 == "POST" && $6 >= 400 {print $0}' server_logs.txt
Esses filtros podem ajudá-lo a identificar rapidamente possíveis problemas ou atividades suspeitas em seus logs de servidor.
Contando e Resumindo Dados
O AWK é excelente para contar ocorrências e resumir dados. Vamos usá-lo para contar o número de solicitações para cada código de status HTTP.
Execute este comando:
awk '{count[$6]++} END {for (code in count) print code, count[code]}' server_logs.txt | sort -n
Este comando é mais complexo, então vamos dividi-lo passo a passo:
{count[$6]++}- Esta é a ação principal realizada para cada linha:counté um array (array associativo ou dicionário) que estamos criando[$6]usa o valor do 6º campo (código de status) como índice/chave do array++é o operador de incremento, adicionando 1 ao valor atual- Portanto, para cada linha, incrementamos o contador para o código de status específico encontrado
END {for (code in count) print code, count[code]}- Isso é executado após o processamento de todas as linhas:ENDé um padrão especial que corresponde ao final da entrada{...}contém a ação a ser executada após todo o processamento da entradafor (code in count)é um loop que percorre todas as chaves no arraycountprint code, count[code]imprime cada código de status e sua contagem
| sort -n- Envia a saída para o comando sort, que classifica numericamente
Quando o AWK processa um array como count[$6]++, ele automaticamente:
- Cria o array se ele não existir
- Cria um novo elemento com valor 0 se a chave não existir
- Em seguida, incrementa o valor em 1
Você deverá ver uma saída semelhante a esta:
200 3562
301 45
302 78
304 112
400 23
403 8
404 89
500 15
Este resumo mostra rapidamente a distribuição dos códigos de status em seu arquivo de log.
Agora, vamos encontrar os 5 recursos acessados com mais frequência:
awk '{count[$5]++} END {for (resource in count) print count[resource], resource}' server_logs.txt | sort -rn | head -n 5
Este comando segue um padrão semelhante com algumas alterações:
{count[$5]++}- Conta as ocorrências do 5º campo (o recurso solicitado)END {for (resource in count) print count[resource], resource}- Após processar todas as linhas:- Imprime a contagem primeiro, seguida pelo recurso
- Essa mudança de ordem facilita a classificação numérica por contagem
| sort -rn- Classifica numericamente em ordem reversa (contagens mais altas primeiro)| head -n 5- Limita a saída às primeiras 5 linhas (os 5 principais resultados)
Saída:
1823 /index.html
956 /about.html
743 /products.html
512 /services.html
298 /contact.html
Esses comandos AWK demonstram o poder de usar arrays para contagem e resumo. Você pode adaptar esse padrão para contar qualquer campo ou combinação de campos em seus dados.
Por exemplo, para contar o número de solicitações por endereço IP:
awk '{count[$3]++} END {for (ip in count) print ip, count[ip]}' server_logs.txt
Para contar solicitações por método e status:
awk '{key=$4"-"$6; count[key]++} END {for (k in count) print k, count[k]}' server_logs.txt
Esses resumos podem ajudá-lo a entender os padrões de tráfego e identificar recursos populares (ou problemáticos) em seu servidor.
Criando um Relatório Simples
Para nossa tarefa final, vamos criar um relatório HTML simples resumindo algumas informações importantes do nosso arquivo de log. Usaremos um script AWK armazenado em um arquivo separado para esta operação mais complexa.
Esta etapa combina várias ideias do AWK das seções anteriores:
- contadores como
total++ - arrays como
ip_count[$3]++ - um bloco
ENDque imprime o resumo final
Se o script parecer longo à primeira vista, concentre-se em um bloco de cada vez. Você não precisa memorizar o arquivo inteiro antes de executá-lo.
Primeiro, crie um arquivo chamado log_report.awk com o seguinte conteúdo:
Dicas: Copie o conteúdo abaixo e cole-o no seu terminal para criar o arquivo.
cat << 'EOF' > log_report.awk
BEGIN {
print "<html><body>"
print "<h1>Server Log Summary</h1>"
total = 0
errors = 0
}
{
total++
if ($6 >= 400) errors++
ip_count[$3]++
resource_count[$5]++
}
END {
print "<p>Total requests: " total "</p>"
print "<p>Error rate: " (errors/total) * 100 "%</p>"
print "<h2>Top 5 IP Addresses</h2>"
print "<ul>"
for (ip in ip_count) {
top_ips[ip] = ip_count[ip]
}
n = asort(top_ips, sorted_ips, "@val_num_desc")
for (i = 1; i <= 5 && i <= n; i++) {
for (ip in ip_count) {
if (ip_count[ip] == sorted_ips[i]) {
print "<li>" ip ": " ip_count[ip] " requests</li>"
break
}
}
}
print "</ul>"
print "<h2>Top 5 Requested Resources</h2>"
print "<ul>"
for (resource in resource_count) {
top_resources[resource] = resource_count[resource]
}
n = asort(top_resources, sorted_resources, "@val_num_desc")
for (i = 1; i <= 5 && i <= n; i++) {
for (resource in resource_count) {
if (resource_count[resource] == sorted_resources[i]) {
print "<li>" resource ": " resource_count[resource] " requests</li>"
break
}
}
}
print "</ul>"
print "</body></html>"
}
EOF
Vamos entender este script AWK seção por seção:
Bloco BEGIN: Executa antes de processar quaisquer linhas de entrada
BEGIN { print "<html><body>" ## Inicia a estrutura HTML print "<h1>Server Log Summary</h1>" total = 0 ## Inicializa o contador para o total de solicitações errors = 0 ## Inicializa o contador para solicitações com erro }Bloco de Processamento Principal: Executa para cada linha do arquivo de entrada
{ total++ ## Incrementa o contador total de solicitações if ($6 >= 400) errors++ ## Conta respostas de erro (códigos de status >= 400) ip_count[$3]++ ## Conta solicitações por endereço IP (campo 3) resource_count[$5]++ ## Conta solicitações por recurso (campo 5) }Bloco END: Executa após o processamento de todas as linhas de entrada
END { ## Imprime estatísticas de resumo print "<p>Total requests: " total "</p>" print "<p>Error rate: " (errors/total) * 100 "%</p>" ## Processa e imprime os 5 principais endereços IP ## ... ## Processa e imprime os 5 principais recursos solicitados ## ... print "</body></html>" ## Finaliza a estrutura HTML }
Antes de prosseguir, observe o fluxo geral:
BEGINimprime as tags HTML de abertura e inicializa os contadores.- O bloco do meio processa cada linha de log e atualiza os totais.
ENDimprime o relatório final após cada linha ter sido analisada.
Vamos examinar a lógica de classificação para os principais IPs (a seção de recursos funciona da mesma maneira):
## Copia as contagens para um novo array para classificação
for (ip in ip_count) {
top_ips[ip] = ip_count[ip]
}
## Classifica o array por valor em ordem decrescente
n = asort(top_ips, sorted_ips, "@val_num_desc")
## Imprime as 5 principais entradas
for (i = 1; i <= 5 && i <= n; i++) {
## Encontra o IP original que corresponde a esta contagem
for (ip in ip_count) {
if (ip_count[ip] == sorted_ips[i]) {
print "<li>" ip ": " ip_count[ip] " requests</li>"
break
}
}
}
Neste script:
- A função
asort()classifica o array "@val_num_desc"é um argumento especial que diz para classificar numericamente por valor em ordem decrescente- Os loops aninhados encontram e imprimem as 5 principais entradas
Você pode pensar nos loops aninhados desta forma:
- o primeiro loop decide quais contagens pertencem aos 5 primeiros
- o segundo loop encontra qual endereço IP ou recurso produziu cada contagem
Esse padrão de busca é mais avançado do que as etapas anteriores, então é normal se esta for a primeira parte do laboratório que parece um script real em vez de um comando de uma linha.
Agora, vamos executar nosso script AWK para gerar o relatório:
awk -f log_report.awk server_logs.txt > log_report.html
A opção -f diz ao AWK para ler o script do arquivo especificado:
-f log_report.awk- Lê o script AWK do arquivolog_report.awkserver_logs.txt- Processa este arquivo usando o script> log_report.html- Redireciona a saída para o arquivolog_report.html
Você pode visualizar o conteúdo do relatório usando o comando cat:
cat log_report.html
Se a saída HTML parecer difícil de ler no terminal, visualize apenas a primeira parte primeiro:
head -n 15 log_report.html
Este relatório fornece um resumo do total de solicitações, taxa de erro, os 5 principais endereços IP e os 5 principais recursos solicitados. Em um cenário real, você poderia abrir este arquivo HTML em um navegador da web para uma visualização formatada.
A abordagem que usamos neste script demonstra como o AWK pode ser usado para tarefas de análise de dados mais complexas. Você pode estender este script para incluir estatísticas adicionais ou visualizações diferentes com base em suas necessidades específicas.
Resumo
Parabéns! Você concluiu este laboratório sobre o uso do comando AWK para análise de logs. Vamos recapitular o que você aprendeu:
- Uso básico do AWK: Imprimir campos específicos de um arquivo de texto estruturado.
- Filtragem de dados: Usar condições no AWK para selecionar entradas de log específicas.
- Contagem e resumo: Usar o AWK para gerar estatísticas a partir de dados de log.
- Criação de relatórios: Escrever scripts AWK mais complexos para gerar relatórios formatados.
Essas habilidades serão inestimáveis para analisar arquivos de log, processar dados e gerar relatórios em seu trabalho futuro como administrador de sistemas ou analista de dados.
Aqui estão alguns parâmetros e recursos adicionais do AWK que não abordamos neste laboratório:
-F: Especifica um separador de campo diferente de espaço em branco.-v: Atribui um valor a uma variável.NR: Uma variável embutida que representa o número do registro atual.NF: Uma variável embutida que representa o número de campos no registro atual.- Blocos
BEGINeEND: Padrões especiais para inicialização e finalização. - Funções embutidas: Funções matemáticas, funções de string e muito mais.
Lembre-se, a prática é a chave para dominar o AWK. Tente modificar os comandos e scripts deste laboratório para analisar diferentes aspectos do arquivo de log ou para processar outros tipos de dados de texto estruturados.



