Vous avez 4 heures
Je me suis dit que ça pourrait être marrant de vous faire participer aux casse-têtes auxquels je suis confronté. Je lance le truc pour voir si ça vous plaît/amuse, si il n’y a pas de retours je remballerai mon idée ha ha.
On m’a demandé de récupérer les logs du 22/01 à partir de 11h40 sur quelques 130 serveurs. On peut utiliser ansible ou un outil de ce type pour balancer la commande sur tous ces serveurs mais comment récupérer tous les logs (ligne entière) à partir de 11h40 ?
Ci-dessous 50 lignes de logs d’un serveur (j’ai trafiqué et tronqué les infos) qui vous serviront à tester la solution que vous proposez, je vous invite à les copier-coller dans un fichier sur votre poste pour effectuer vos tests. Tous les coups sont permis : Scripts (tous langages : Python, Perl…), shell one-liner, site web qui fournit la solution en 1 clic, corruption de l’auteur (je suis hétérosexuel et j’accepte les virements bancaires), etc.
monpetitserveur.net 87.122.70.72 - - [22/Jan/2019:00:54:21 +0100] "POST monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:00:54:22 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:00:55:52 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:01:26:23 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:01:26:23 +0100] "POST monpetitserveur.net 112.156.104.2 - - [22/Jan/2019:02:12:08 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:02:36:39 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:02:36:40 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:02:46:21 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:03:46:31 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:03:46:34 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:03:46:34 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:03:46:46 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:04:26:51 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:04:26:51 +0100] "POST monpetitserveur.net 105.204.123.56 - - [22/Jan/2019:05:00:17 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:05:27:22 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:05:27:22 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:05:27:22 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:05:57:47 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:05:57:59 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:06:57:41 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:08:38:50 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:08:38:50 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:08:39:08 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:08:39:23 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:08:59:15 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:08:59:20 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:09:06:19 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:10:19:40 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:10:19:41 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:10:19:51 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:10:49:44 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:10:49:45 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:11:19:51 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:11:22:17 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:11:40:57 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:11:40:57 +0100] "POST monpetitserveur.net 104.48.123.201 - - [22/Jan/2019:12:16:45 +0100] "GET monpetitserveur.net 84.12.145.4 - - [22/Jan/2019:12:49:41 +0100] "GET monpetitserveur.net 84.12.154.4 - - [22/Jan/2019:12:49:43 +0100] "GET monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:12:49:44 +0100] "POST monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:12:50:02 +0100] "GET monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:13:46:11 +0100] "GET monpetitserveur.net 53.56.8.95 - - [22/Jan/2019:13:48:09 +0100] "POST monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:13:48:09 +0100] "POST monpetitserveur.net 190.18.127.56 - - [22/Jan/2019:20:06:48 +0100] "POST monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:20:06:50 +0100] "POST
Vous avez le droit de poser des questions. Je laisse jusqu’à lundi 17h30 puis je fermerai les commentaires, ça laisse du temps pour ceux qui voudraient s’amuser dessus ce week-end. Je fournirai ensuite une solution (la mienne) ci-dessous.
En général on a un temps imparti pour effectuer une tâche : Vous avez 4 heures.
Pour ma part j’ai procédé ainsi awk -F'2019:|:[0-5][0-9][ ]' '($2 >= "11:40") {print}' file.log
, certainement pas la solution la plus simple ni la plus élégante mais elle fonctionne.
La solution la plus sexy à mes yeux vient de Maxime avec grep -vE "22/Jan/2019:(0|10|11:[0-3])" file.log
mais plus simple et compréhensible avec grep, Grinn a proposé egrep '\[22/Jan/2019:(11:[45][0-9]|1[2-9]|2[0-3]):' file.log
.
Ma préférée est celle de Linuz avec awk -v from="[22/Jan/2019:11:40:00" -v to="[22/Jan/2019:23:59:59" '$5>=from && $5<=to' file.log
, j’aime aussi beaucoup awk -F'/' 'substr($3,6,2)substr($3,9,2)>=1140 {print}' file.log
de unixmipfr.
Merci à tous de votre participation !
Déjà 38 avis pertinents dans Vous avez 4 heures
Les commentaires sont fermés.
Le fichier de logs correspond à celui du 22/01 (monpetitserveur-2019-01-22.log), le fichier de logs s’arrête à minuit puisque ce sont les logs du jour.
Tcho !
On admet que…
1. On peut se connecter par ssh sans mot de passe sur tous les serveurs,
2. On dispose de la liste des serveurs dans un fichier « listeserveurs »,
3. Que l’outil GNU parallel est installé localement,
4. Que l’outil grep est installé sur les serveurs distants *ET* qu’il est suffisamment récent pour gérer des expressions régulières
Soit le script bash suivant, qui va créer des fichiers « log_ ».
#!/bin/bash
logserveur() {
serveur=$1
# Sur le serveur, on greppe les logs du 22 janvier
# - à 11h quarante ou cinquante quelque chose
# - de 12 à 19h quelque chose
# - de 20 à 23h quelque chose
# Le grep est lancé sur le serveur distant pour minimiser ce qu'on fait transiter par le réseau.
# Le "-C" de ssh s'assure qu'on réduit autant que possible l'utilisation du réseau en compressant.
# L'utilisateur est omis, pour la lisibilité du truc. On aura paramétré son ~/.ssh/config pour choisir le bon. :)
if ssh -C $serveur 'grep -E " \[22/Jan/2019:(11:[45]|1[2-9]:|2[0-3]:)" /var/log/logsquinousinteressent' > "logs_$serveur"
then
echo "OK $serveur"
else
echo "SOUCI $serveur"
fi
}
# Rend la fonction logserveur() visible à GNU parallel
export -f logserveur
# Interrogation en parallèle des serveurs dans la le fichier « listeserveurs »,
# avec un maximum de 16 machines sondées simultanément. On peut ajuster le paramètre
# ou le virer pour laisser parallel lancer autant de process qu’il le peut…
parallel --jobs 16 logserveur :::: listeserveurs
echo "Fini..."
egrep '\[22/Jan/2019:(11:[45][0-9]|1[2-9]|2[0-3]):' fichier.de.log
grep -vE "22/Jan/2019:(0|10|11:[0-3])" file.log
Je pense que j’ai mal exposé le problème. Les logs que j’ai donné sont un exemple « type », sur les autres serveurs il y a des logs à toutes les heures (par exemple à 14h, 15h, 16h etc.). Il faut récupérer tous les logs à partir de 11h40 jusqu’à minuit.
Tcho !
Je crois que tu as la solution la plus sexy à mes yeux pour l’instant.
Tcho !
Ta réponse me semble très bien, merci d’avoir participé !
Tcho !
Ta réponse me semble correcte, merci de ta participation
Par rapport à la réponse de , le [0-9] dans
11:[45][0-9]
apporte quelque chose ?Tcho !
mini=${1-'22-Jan-2019 08:38'}
dmini=$(date -d "$mini" "+%s")
echo "Date mini: $mini == $dmini"
declare -a line=()
while IFS='[]' read -ra line ; do
d="${line[1]}"
d="${d//[\/]/-}"
d="${d/[:]/ }"
if [[ $(date -d "$d" "+%s") > "$dmini" ]]; then
echo "$d"
else
echo "$d < $mini" # pour test
fi
done < <(cat *.log )
cat logs | while read line; do echo "$line" | php -r '$line = file_get_contents("php://stdin"); $date = new DateTime(explode("]", explode("[", $line)[1])[0]); if ($date->getTimestamp() >= 1548153600) echo $line;'; done
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:11:40:57 +0100] "GET
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:11:40:57 +0100] "POST
monpetitserveur.net 104.48.123.201 - - [22/Jan/2019:12:16:45 +0100] "GET
monpetitserveur.net 84.12.145.4 - - [22/Jan/2019:12:49:41 +0100] "GET
monpetitserveur.net 84.12.154.4 - - [22/Jan/2019:12:49:43 +0100] "GET
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:12:49:44 +0100] "POST
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:12:50:02 +0100] "GET
monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET
monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:13:46:11 +0100] "GET
monpetitserveur.net 53.56.8.95 - - [22/Jan/2019:13:48:09 +0100] "POST
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:13:48:09 +0100] "POST
monpetitserveur.net 190.18.127.56 - - [22/Jan/2019:20:06:48 +0100] "POST
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:20:06:50 +0100] "POST
mini=${1-'22-Jan-2019 08:38'}
dmini=$(date -d "$mini" "+%s")
echo "Date mini: $mini == $dmini"
declare -a line=()
while IFS='[]' read -ra line ; do
d="${line[1]}"
d="${d//[\/]/-}"
d="${d/[:]/ }"
if [[ $(date -d "$d" "+%s") > "$dmini" ]]; then
echo "$d"
else
echo "$d < $mini" # pour test
fi
done < <(cat *.log )
ps: premier post non passé ?
Correct, perso j’évite le cat logs et j’ajoute à la fin < logs (cependant il faut un saut de ligne à la fin sinon il bouffe la dernière ligne).
Tcho !
On valide manuellement les commentaires ici. Ta proposition gère à partir de 11h40, j’en vois aucune trace ?
Tcho !
./log.sh "22-Jan-2019 11:40"
Date mini: 22-Jan-2019 11:40 == 1548153600
22-Jan-2019 00:54:21 +0100 < 22-Jan-2019 11:40
...
22-Jan-2019 11:22:17 +0100 < 22-Jan-2019 11:40
22-Jan-2019 11:40:57 +0100
...
22-Jan-2019 20:06:48 +0100
22-Jan-2019 20:06:50 +0100
#!/bin/bash
heuredebut="11"
heurefin="23"
date='22/Jan/2019'
for (( i=$heuredebut; i> /home/fabien/test/ctete/logextract
done
C’est pas top mais ca semble marcher
#!/bin/bash
heuredebut="11"
heurefin="23"
date='22/Jan/2019'
for (( i=$heuredebut; i> /home/fabien/test/ctete/logextract
fi
echo $i
cat /home/fabien/test/ctete/log | grep $date":"$i >> /home/fabien/test/ctete/logextract
done
Mais là tu prends tous les logs entre 11h00 et 11h39 avec ? Not good.
Tcho !
Mais du coup c’est quoi
mini=${1-’22-Jan-2019 08:38′}
? Le 08:38 surtout.Tcho !
correctif avec min et max (+ pour logs multi-jours ou plage de quelques heures)
#usage ./log.sh "22-Jan-2019 11:40" "22-Jan-2019 13:00"
mini=${1-'22-Jan-2019 08:38'} # valeur par défaut si $1 non entré
dmini=$(date -d "$mini" "+%s")
max=${2} # ici maxi c'est date/heure courante
dmax=$(date -d "$max" "+%s")
echo "Date mini: $mini == $dmini"
echo "Date maxi: $max == $dmax"
declare -a line=()
while IFS='[]' read -ra line ; do
d="${line[1]}"
d="${d//[\/]/-}"
d="$(date -d "${d/[:]/ }" "+%s")"
[[ "$d" -ge "$dmini" ]] && [[ "$d" < "$dmax" ]] && printf "%s[%s]%s\n" "${line[0]}" "${line[1]}" "${line[2]}"
done < <(cat *.log )
awk -F'/' 'substr($3,6,2)substr($3,9,2)>=1140 {print}' log_file
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:11:40:57 +0100] "GET
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:11:40:57 +0100] "POST
monpetitserveur.net 104.48.123.201 - - [22/Jan/2019:12:16:45 +0100] "GET
monpetitserveur.net 84.12.145.4 - - [22/Jan/2019:12:49:41 +0100] "GET
monpetitserveur.net 84.12.154.4 - - [22/Jan/2019:12:49:43 +0100] "GET
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:12:49:44 +0100] "POST
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:12:50:02 +0100] "GET
monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET
monpetitserveur.net 45.85.135.74 - - [22/Jan/2019:13:15:27 +0100] "GET
monpetitserveur.net 42.248.86.23 - - [22/Jan/2019:13:46:11 +0100] "GET
monpetitserveur.net 53.56.8.95 - - [22/Jan/2019:13:48:09 +0100] "POST
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:13:48:09 +0100] "POST
monpetitserveur.net 190.18.127.56 - - [22/Jan/2019:20:06:48 +0100] "POST
monpetitserveur.net 2a00:1450:1:815:124::1 - - [22/Jan/2019:20:06:50 +0100] "POST
Je comprends mieux, c’est chouette en bash même si par rapport à d’autres solutions proposées (notamment grep), ça parait bien lourd.
Tcho !
Très sympa, merci ! J’aime beaucoup awk, j’apprécie d’autant plus.
Tcho !
journalctl --since "2019-03-22 11:40:00"
journalctl --since="2019-01-22 22:40:00" --until="2019-01-23 00:00:00"
Je considère cette proposition comme erronée :
– Par défaut le journal systemd est circulaire, une fois la taille maximum du journal atteinte il vient écraser les entrées les plus anciennes. On peut donc se retrouver avec « seulement » deux heures de logs sur un serveur mal configuré et il y a de très fortes chances qu’il n’y ait plus rien du 22/01 quand on est le 22/03
– Le journal systemd logue tout ce qui tourne autour de systemd notamment les services, on peut balancer ce qu’on veut dans le journal en le configurant mais j’ai rarement vu balancer les logs web dedans
– A minima la proposition matche une date mais ne trie aucune entrée, sachant tout ce qui est balancé dans le journal il faudrait ensuite récupérer uniquement les logs web (en quelque sorte on retourne le problème)
Tcho !
perl -lne '
print if m{
\[22/Jan/2019
:(\d{2})
:(\d{2})
}x && ( ($1 > 11) || (($1 == 11) && ($2 >= 45 )) )
' *.log
La commande systemd adaptée : `journalctl –since « 2019-03-22 11:40:00 » -u apache2.service`. Évidemment, à adapter, dans mon cas ce sera haproxy.service (j’ai reporté tout mes logs web via HAProxy par simplicité). Et oui, mes logs web vont dans systemd.
Je trouve ça complexe sinon c’est pas mal.
Tcho !
Je ne suis pas d’accord sur ta façon de dire/présenter les choses. Le fonctionnement du journal systemd est circulaire, c’est le bon terme qui est utilisé, les anciennes entrées sont remplacées par les nouvelles. Si on passe par rsyslog par exemple, il n’y a aucune gestion de la rotation des logs, c’est logrotate qui s’en occupera.
Par défaut la config du journal systemd c’est de loguer dans /run/log/journal qui sera perdu au prochain démarrage. Si on le met dans /var/log/journal c’est par défaut 10% de l’espace total de la partition où sont stockés les fichiers, bien loin de ce que rsyslog et logrotate prendront comme espace puisque effectivement comme tu le dis ils peuvent le remplir.
Concernant les logs web à 14 jours, c’est jouer avec le feu puisque la loi Française demande 1 an mais la loi Européenne dit autre chose lol (https://korben.info/a-propos-de-duree-de-conservation-logs-de-connexion.html). Dans le doute et pour éviter tout problème, nous conservons 1 an chez nous.
Tcho !
Autre petite solution avec awk (tant que la date est en 5ème colonne) :
awk -v from="[22/Jan/2019:11:40:00" -v to="[22/Jan/2019:23:59:59" '$5>=from && $5<=to' test.log
Ha ha top, merci !
Tcho !
Il faut arrêter de dire qu’on trolle quand on n’est pas d’accord ou qu’on fait différemment. Comme d’hab on ne réfute pas les arguments, on ne les conteste pas mais on part sur autre chose pour dire « t’as tort ». Si vous voulez faire passer du gris pour du blanc c’est cool mais il faut pas s’attendre à ce que tout le monde suive.
Dans ton discours on dirait que je suis contre journald, c’est être contre de dire que c’est différent de rsyslog + logrotate ? C’est faux de dire que le fonctionnement du journal systemd est circulaire contrairement à rsyslog ?
On me demanderait presque de justifier que systemd-journald fait pas le boulot alors qu’à aucun moment je n’ai dit ça, c’est de l’interprétation, une forme de lecture supérieure des pensées d’autrui ?
J’aime particulièrement systemd et j’apprécie grandement le journal systemd ainsi que journalctl (et il n’y a pas de mais). Dans le cadre de l’article, ces logs ne passent pas par le journal systemd et non
journalctl --since "2019-03-22 11:40:00"
ne fait pas le boulot, ça remonterait tous les logs donc ça sert à rien. Je n’ai pas parlé du journal systemd dans l’article, on est très loin du fait que tout le monde n’utilise que lui, je dois justifier davantage qu’une réponse avec journalctl est erronée ?Je précise que la proposition est pas mauvaise en soi, c’est même très bien de rappeler les bases mais c’est juste à côté du problème posé. Si il y a eu 10 réponses avant qui ne parlaient pas de systemd, c’est pas pour rien.
Tcho !
Nous on ne logue que 14 jours parce que 1 an c’est bien gentil, mais ça prends de la place. 1 an de logs mails, de logs web, etc (surtout quand le site est bourré d’erreurs remplissant les errorlog) pour un site, ça représente déjà quelques dizaines de Gio. Si on les conserves sur l’infra du client (et c’est ce qu’on fait actuellement), ça lui coûterait plus cher en espace disque pour les logs que pour ses données, et ça remplirait nos hyperviseurs bien plus rapidement, ça serait pas rentable, aussi bien techniquement (plus d’espace consommé par chaque VM = moins de VM par hyperviseur) qu’économiquement (pareil, ratio VM vendues / hyperviseurs nécessaires qui diminue).
Si on les conserve sur une infra dédiée… ben avec quelques centaines de clients, pour un total que plus de 1500 serveurs (dédiés ou virtuels), et jusqu’à quelques centaines de sites par serveur pour les plus gros, ça commence à chiffrer sévère (en stockage, et en coût d’exploitation de l’infra… sans parler de toute la complexité que ça ajoute). 1 an de logs, c’est juste intenable techniquement parlant, et catastrophique économiquement parlant dans notre cas.
La loi Française a toujours été absurde, maintenant elle est carrément contradictoire à la loi Européenne, et il me semblait avoir lu que l’Europe avait indiqué que la loi Française ne pouvait être appliquée si on veut être dans les règles.
« Nan mais faut bien configurer journald au même titre que tu configures rsyslog et logrotate, sinon ça n’a aucun sens » => On est bien d’accord, juste qu’à titre perso je trouve la config par défaut de journald très casse-gueule
Intéressant ton retour sur les logs, je comprends en te lisant que tu parles d’un environnement professionnel. C’est pas toujours évident de saisir le contexte sur lequel on échange (perso, pro, association…). En simplifiant pas mal nous aussi on conserve deux semaines sur les différents serveurs mais simultanément on balance/centralise tous les logs sur un serveur (avec une rétention bien plus longue). Je me rends pas bien compte de votre volumétrie, un RAID 5 (+ hotspare) de 10 disques de 10 To par exemple, ça ne suffirait pas ?
Il y a aussi des solutions qui paraissent crades mais quand il n’y en a pas d’autres… pourquoi pas plusieurs raspberry pi avec chacun un dd externe de 4 To qui synchronisent les logs toutes les nuits (puis changer le dd externe quand il est full) ? Je préfère mettre un truc crade en place, que de pas mettre de solution en face d’un problème.
Tcho !
Tcho !