En essayant de trouver un moyen simple de regarder les événements récents (de moins de 10 minutes), j'ai essayé ceci:
awk "/^$(date --date="-10 min" "+%b %_d %H:%M")/{p++} p" /root/test.txt
mais ça ne marche pas comme prévu ...
Les fichiers de log sont sous forme:
Dec 18 09:48:54 Blah
Dec 18 09:54:47 blah bla
Dec 18 09:55:33 sds
Dec 18 09:55:38 sds
Dec 18 09:57:58 sa
Dec 18 09:58:10 And so on...
Vous pouvez faire correspondre la plage de dates en utilisant une simple comparaison de chaînes, par exemple:
d1=$(date --date="-10 min" "+%b %_d %H:%M")
d2=$(date "+%b %_d %H:%M")
while read line; do
[[ $line > $d1 && $line < $d2 || $line =~ $d2 ]] && echo $line
done
Par exemple, si d1='Dec 18 10:19'
et d2='Dec 18 10:27'
, le résultat sera:
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
Ou en utilisant awk
si vous le souhaitez:
awk -v d1="$d1" -v d2="$d2" '$0 > d1 && $0 < d2 || $0 ~ d2'
Voici le bel outil Gamme que vous souhaitez de -10 à maintenant
sed -n "/^$(date --date='10 minutes ago' '+%b %_d %H:%M')/,\$p" /var/log/blaaaa
Simple et efficace:
Perl -MDate::Parse -ne 'print if/^(.{15})\s/&&str2time($1)>time-600' /path/log
Cette version imprime l’événement des 10 dernières minutes, jusqu’àmaintenant, à l’aide de la fonction time
.
Vous pouvez tester ceci avec:
Sudo cat /var/log/syslog |
Perl -MDate::Parse -ne '
print if /^(\S+\s+\d+\s+\d+:\d+:\d+)\s/ && str2time($1) > time-600'
Notez que la première représentation utilise uniquement les 15 premiers caractères de chaque ligne}, alors que la seconde construction utilise des détails plus détaillés regexp.
En tant que script Perl: last10m.pl
#!/usr/bin/Perl -wn
use strict;
use Date::Parse;
print if /^(\S+\s+\d+\s+\d+:\d+:\d+)\s/ && str2time($1) > time-600
Signification non relative à l'heure actuelle, mais à la dernière entrée du fichier journal:
Il existe deux méthodes pour récupérer fin de période:
date -r logfile +%s
tail -n1 logfile | Perl -MDate::Parse -nE 'say str2time($1) if /^(.{15})/'
Si logiquement, l'heure de dernière modification du fichier journal doit être l'heure de la dernière entrée.
Donc, la commande pourrait devenir:
Perl -MDate::Parse -ne 'print if/^(.{15})\s/&&str2time($1)>'$(
date -r logfile +%s)
ou vous pouvez prendre les dernière entrée comme référence:
Perl -MDate::Parse -E 'open IN,"<".$ARGV[0];seek IN,-200,2;while (<IN>) {
$ref=str2time($1) if /^(\S+\s+\d+\s+\d+:\d+:\d+)/;};seek IN,0,0;
while (<IN>) {print if /^(.{15})\s/&&str2time($1)>$ref-600}' logfile
La deuxième version semble plus forte, mais n’a accès au fichier qu’une fois.
En tant que script Perl, cela pourrait ressembler à:
#!/usr/bin/Perl -w
use strict;
use Date::Parse;
my $ref; # The only variable I will use in this.
open IN,"<".$ARGV[0]; # Open (READ) file submited as 1st argument
seek IN,-200,2; # Jump to 200 character before end of logfile. (This
# could not suffice if log file hold very log lines! )
while (<IN>) { # Until end of logfile...
$ref=str2time($1) if /^(\S+\s+\d+\s+\d+:\d+:\d+)/;
}; # store time into $ref variable.
seek IN,0,0; # Jump back to the begin of file
while (<IN>) {
print if /^(.{15})\s/&&str2time($1)>$ref-600;
}
Il y a un très rapide pure bash script:
Warning : Cette utilisation récente bashismes, nécessite $BASH_VERSION
4.2 ou supérieur.
#!/bin/bash
declare -A month
for i in {1..12};do
LANG=C printf -v var "%(%b)T" $(((i-1)*31*86400))
month[$var]=$i
done
printf -v now "%(%s)T" -1
printf -v ref "%(%m%d%H%M%S)T" $((now-600))
while read line;do
printf -v crt "%02d%02d%02d%02d%02d" ${month[${line:0:3}]} \
$((10#${line:4:2})) $((10#${line:7:2})) $((10#${line:10:2})) \
$((10#${line:13:2}))
# echo " $crt < $ref ??" # Uncomment this line to print each test
[ $crt -gt $ref ] && break
done
cat
Stockez ce script et exécutez:
cat >last10min.sh
chmod +x last10min.sh
Sudo cat /var/log/syslog | ./last10min.sh
Remplacez simplement la ligne 10, mais vous devez placer le nom de fichier dans le script et ne pas l'utiliser comme filtre:
#!/bin/bash
declare -A month
for i in {1..12};do
LANG=C printf -v var "%(%b)T" $(((i-1)*31*86400))
month[$var]=$i
done
read now < <(date -d "$(tail -n1 $1|head -c 15)" +%s)
printf -v ref "%(%m%d%H%M%S)T" $((now-600))
export -A month
{
while read line;do
printf -v crt "%02d%02d%02d%02d%02d" ${month[${line:0:3}]} \
$((10#${line:4:2})) $((10#${line:7:2})) $((10#${line:10:2})) \
$((10#${line:13:2}))
[ $crt -gt $ref ] && break
done
cat
} <$1
Dans bash , vous pouvez utiliser la commande date
pour analyser les horodatages. Le spécificateur de format "% s" convertit la date donnée en nombre de secondes depuis le 1970-01-01 00:00:00 UTC . Cet entier simple est facile et précis pour faire de l'arithmétique de base.
Si vous souhaitez enregistrer les messages des 10 dernières minutes de l’heure réelle:
now10=$(($(date +%s) - (10 * 60)))
while read line; do
[ $(date -d "${line:0:15}" +%s) -gt $now10 ] && printf "$line\n"
done < logfile
Notez que l'expression ${line:0:15}
est un bash paramètre de développement qui donne les 15 premiers caractères de la ligne, c'est-à-dire l'horodatage lui-même.
Si vous souhaitez que les messages du journal des 10 dernières minutes soient relatifs à la fin du journal:
$ lastline=$(tail -n1 logfile)
$ last10=$(($(date -d "$lastline" +%s) - (10 * 60)))
$ while read line; do
> [ $(date -d "${line:0:15}" +%s) -gt $last10 ] && printf "$line\n"
> done < logfile
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
$
Voici une légère amélioration des performances par rapport à ce qui précède:
$ { while read line; do
> [ $(date -d "${line:0:15}" +%s) -gt $last10 ] && printf "$line\n" && break
> done ; cat ; } < logfile
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
$
Cela suppose que les entrées du journal sont dans un ordre chronologique strict. Une fois que nous avons fait correspondre l’horodatage en question, nous quittons la boucle for, puis nous utilisons simplement cat
pour vider les entrées restantes.
En python, vous pouvez faire comme suit:
from datetime import datetime
astack=[]
with open("x.txt") as f:
for aline in f:
astack.append(aline.strip())
lasttime=datetime.strptime(astack[-1], '%b %d %I:%M:%S')
for i in astack:
if (lasttime - datetime.strptime(i, '%b %d %I:%M:%S')).seconds <= 600:
print i
Placez les lignes du fichier dans une pile (une liste python). ouvrez le dernier élément et obtenez la différence entre les éléments de date successifs jusqu'à ce que la différence soit inférieure à 600 secondes.
Courant sur votre entrée, je reçois ce qui suit:
Dec 18 10:19:16
Dec 18 10:19:23
Dec 18 10:21:03
Dec 18 10:22:54
Dec 18 10:27:32
Vous pouvez passer des jours, des heures, des minutes ou des secondes en tant que paramètre et il recherchera l'expression et le fichier spécifié (ou le répertoire, auquel cas il ajoutera '/ *' au nom):
Dans votre cas, appelez simplement le script comme suit: $ 0 -m 10 "expression" log_file
Remarque: si vous connaissez l'emplacement de 'Ruby', changez le Shebang (première ligne du script), Pour des raisons de sécurité.
#! /usr/bin/env Ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
begin
total_amount = Integer ARGV[1]
rescue ArgumentError
$stderr.print "error: parameter 'time' must be an Integer\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
if ARGV[0] == "-m"
gap = Rational(60, 86400)
time_str = "%b %d %H:%M"
elsif ARGV[0] == "-s"
gap = Rational(1, 86400)
time_str = "%b %d %H:%M:%S"
elsif ARGV[0] == "-h"
gap = Rational(3600, 86400)
time_str = "%b %d %H"
elsif ARGV[0] == "-d"
time_str = "%b %d"
gap = 1
else
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
pn = Pathname.new(ARGV[3])
if pn.exist?
log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
$stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
search_str = ARGV[2]
now = DateTime.now
total_amount.times do
now -= gap
system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end