1. Melhor solução: Python
Usar bash
para tarefas como essas pode ser um pouco complexo demais, porque não possui ferramentas suficientes para essa finalidade. Certamente isso pode ser feito, mas com muito esforço. Portanto, precisamos de um conjunto de ferramentas que nos permita analisar o arquivo de log de maneira mais simples. O Python oferece esse conjunto de ferramentas via datetime
module.
O script python apresentado a seguir leva 3 argumentos na linha de comando: registro de data e hora de início com aspas simples ou dupla, registro de data e hora de finalização com aspas simples ou dupla e o arquivo a ser lido. O formato dos timestamps deve ser consistente com o formato 'Mon day HH: MM: SS'.
#!/usr/bin/env python
import datetime as dt
import sys
def convert_to_seconds(timestring):
year = str(dt.date.today().year)
dtobj = dt.datetime.strptime( year + ' ' + timestring , '%Y %b %d %H:%M:%S' )
return int(dtobj.strftime('%s'))
beginning = convert_to_seconds(sys.argv[1])
ending = convert_to_seconds(sys.argv[2])
with open(sys.argv[3]) as log:
for line in log:
logstamp = " ".join(line.strip().split()[0:3])
s_logstamp = convert_to_seconds(logstamp)
if s_logstamp < beginning: continue
if s_logstamp >= beginning and s_logstamp <= ending:
print(line.strip())
sys.stdout.flush()
if s_logstamp > ending: break
Teste executado em /var/log/syslog
:
$ ./read_log_range.py 'Feb 8 13:57:00' 'Feb 8 14:00:00' /var/log/syslog
Feb 8 13:57:59 eagle gnome-session[28631]: (nm-applet:28825): GdkPixbuf-CRITICAL **: gdk_pixbuf_composite: assertion 'dest_x >= 0 && dest_x + dest_width <= dest->width' failed
Feb 8 13:59:55 eagle org.gtk.vfs.Daemon[28480]: ** (process:2259): WARNING **: Couldn't create directory monitor on smb://x-gnome-default-workgroup/. Error: Operation not supported by backend
Feb 8 13:59:59 eagle gnome-session[28631]: (nm-applet:28825): GdkPixbuf-CRITICAL **: gdk_pixbuf_composite: assertion 'dest_x >= 0 && dest_x + dest_width <= dest->width' failed
2. Bash
Naturalmente, é possível fazer isso em bash
, com o uso dos utilitários date
e awk
para extrair os registros de data e hora e as conversões. Abaixo está a implementação bash
do mesmo script python.
#!/usr/bin/env bash
#set -x
str_to_seconds(){
date -d"$1" +%s
}
main(){
local date1=$1
local date2=$2
local logfile=$3
local s_date1=$(str_to_seconds "$date1")
local s_date2=$(str_to_seconds "$date2")
while IFS= read -r line;
do
timestamp=$(awk '{print $1,$2,$3}' <<< "$line")
s_timestamp=$(str_to_seconds "$timestamp")
[ $s_timestamp -lt $s_date1 ] && continue
if [ $s_timestamp -ge $s_date1 ] && [ $s_timestamp -le $s_date2 ]
then
printf "%s\n" "$line"
fi
[ $s_timestamp -gt $s_date2 ] && break
done < "$logfile"
}
main "$@"
3. Comparação das duas abordagens
Naturalmente, a versão bash
demora muito mais tempo. O shell não é feito para processamento de grande quantidade de dados, como logs. Por exemplo, na minha máquina com SSD e processador dual core, o shell demorou um tempo significativo para ler quase 13.000 arquivos de linha:
$ time ./read_log_range.sh 'Feb 8 13:56:00' 'Feb 8 14:00:00' '/var/log/syslog' &> /dev/null
0m39.18s real 0m02.48s user 0m02.68s system
$ wc -l /var/log/syslog
12878 /var/log/syslog
Até mesmo várias otimizações com instruções if
não ajudaram. Compare isso com sua alternativa em python:
$ time ./read_log_range.py 'Feb 8 13:56:00' 'Feb 8 14:00:00' '/var/log/syslog' &> /dev/null
0m00.60s real 0m00.53s user 0m00.07s system
$ wc -l /var/log/syslog
12878 /var/log/syslog
Como você pode ver, o Python foi cerca de 65 vezes mais rápido que sua contraparte bash
.