Convertir l'horodatage dmesg au format de date personnalisé

112

J'essaie de comprendre l'horodatage dmesg et j'ai du mal à le convertir pour le changer au format de date java / date personnalisée.

Toute aide est très appréciée.

Exemple de journal dmesg:

[14614.647880] airo(eth1): link lost (missed beacons)

Merci!

ukanth
la source

Réponses:

180

Comprendre l' dmesghorodatage est assez simple: c'est le temps en secondes depuis le démarrage du noyau. Ainsi, ayant le temps de démarrage ( uptime), vous pouvez additionner les secondes et les afficher dans le format de votre choix.

Ou mieux, vous pouvez utiliser l' -Toption de ligne de commande dmesget analyser le format lisible par l'homme.

Depuis la page de manuel :

-T, --ctime
    Print human readable timestamps. The timestamp could be inaccurate!

    The time source used for the logs is not updated after system SUSPEND/RESUME.
Drescherjm
la source
10
Quelle commande accepte -T? Mon dmesg ne le fait pas, aucune page de manuel ne le dit. (Linux Mint Debian Edition).
gyorgyabraham
1
Le mien ( dmesgde util-linux 2.20.1sous Ubuntu 13.04)
2
Non disponible dans redhat et / ou oracle linux 5.6, rpm -qf /bin/dmesg => util-linux-2.13-0.56.0.2.el5
michael
7
Cette option est apparue dans util-linux 2.20, selon les notes de publication
ks1322
1
@xealits merci pour le suivi, c'est gentil de votre part :) En ce qui concerne la question, je pense que la partie de compréhension est mineure et le "convertir cela pour le changer au format de date java / date personnalisée". était la partie essentielle, mais votre opinion pourrait différer. Bonne journée;)
32

Avec l'aide de dr answer, j'ai écrit une solution de contournement qui permet de convertir votre fichier .bashrc. Il ne cassera rien si vous n'avez pas d'horodatage ou d'horodatage déjà correct.

dmesg_with_human_timestamps () {
    $(type -P dmesg) "$@" | perl -w -e 'use strict;
        my ($uptime) = do { local @ARGV="/proc/uptime";<>}; ($uptime) = ($uptime =~ /^(\d+)\./);
        foreach my $line (<>) {
            printf( ($line=~/^\[\s*(\d+)\.\d+\](.+)/) ? ( "[%s]%s\n", scalar localtime(time - $uptime + $1), $2 ) : $line )
        }'
}
alias dmesg=dmesg_with_human_timestamps

Aussi, une bonne lecture sur la logique de conversion d'horodatage dmesg et comment activer les horodatages lorsqu'il n'y en a pas: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

Lucas Cimon
la source
amélioration mineure: vous pouvez supprimer 'tail -1' dans le pipeline et laisser awk manger des lignes et imprimer à partir de la dernière ligne dans son tampon. local dmesg_bin=$(type -a dmesg | awk 'END { print $NF }')
Brian Onn
@Lucas: pouvez-vous expliquer l'utilisation de 'type -a dmesg | ...' au lieu de $ (quel dmesg)? Y a-t-il un avantage à un tuyau à 3 étages pour obtenir ce chemin?
Stabledog
@Stabledog: bonne question. Pour une explication sur les raisons d'utiliser typeover which, consultez cette question . J'ai cependant édité ma réponse pour éviter le triple tube inutile.
Lucas Cimon
cet extrait de code bash / perl a fonctionné pour moi, j'ai une vieille machine RHEL5.7 dont je dois m'occuper et dmesg n'a aucune option pour imprimer l'horodatage en temps humain.
Paul M le
17

Pour les systèmes sans "dmesg -T" tels que RHEL / CentOS 6, j'ai aimé la fonction "dmesg_with_human_timestamps" fournie par lucas-cimon plus tôt. Il a un peu de mal avec certaines de nos boîtes avec une grande disponibilité. Il s'avère que les horodatages du noyau dans dmesg sont dérivés d'une valeur de disponibilité conservée par les processeurs individuels. Au fil du temps, cela se désynchronise avec l'horloge temps réel. En conséquence, la conversion la plus précise pour les entrées dmesg récentes sera basée sur l'horloge du processeur plutôt que sur / proc / uptime. Par exemple, sur une boîte CentOS 6.6 particulière ici:

# grep "\.clock" /proc/sched_debug  | head -1
  .clock                         : 32103895072.444568
# uptime
 15:54:05 up 371 days, 19:09,  4 users,  load average: 3.41, 3.62, 3.57
# cat /proc/uptime
32123362.57 638648955.00

En tenant compte du temps de fonctionnement du processeur en millisecondes, il y a un décalage de près de 5 heures et demie ici. J'ai donc révisé le script et l'ai converti en bash natif dans le processus:

dmesg_with_human_timestamps () {
    FORMAT="%a %b %d %H:%M:%S %Y"

    now=$(date +%s)
    cputime_line=$(grep -m1 "\.clock" /proc/sched_debug)

    if [[ $cputime_line =~ [^0-9]*([0-9]*).* ]]; then
        cputime=$((BASH_REMATCH[1] / 1000))
    fi

    dmesg | while IFS= read -r line; do
        if [[ $line =~ ^\[\ *([0-9]+)\.[0-9]+\]\ (.*) ]]; then
            stamp=$((now-cputime+BASH_REMATCH[1]))
            echo "[$(date +"${FORMAT}" --date=@${stamp})] ${BASH_REMATCH[2]}"
        else
            echo "$line"
        fi
    done
}

alias dmesgt=dmesg_with_human_timestamps
Allen Belletti
la source
La fonction ne fonctionnait pas dans zsh. J'ai dû le faire en bash proprement dit. Cela dit, sur une boîte avec 221 jours de disponibilité, cette solution avait l'horodatage à la minute du réel. D'autres solutions ont montré que l'événement de cause première se produisait plus de 2 heures plus tôt dans la journée. Merci, Allen. Vous avez sauvé mon après-midi.
Trenton le
Les machines RHEL5.x ne semblent pas avoir / proc / sched_debug :-(
Paul M
14

Donc KevZero a demandé une solution moins kludgy, alors j'ai proposé ce qui suit:

sed -r 's#^\[([0-9]+\.[0-9]+)\](.*)#echo -n "[";echo -n $(date --date="@$(echo "$(grep btime /proc/stat|cut -d " " -f 2)+\1" | bc)" +"%c");echo -n "]";echo -n "\2"#e'

Voici un exemple:

$ dmesg|tail | sed -r 's#^\[([0-9]+\.[0-9]+)\](.*)#echo -n "[";echo -n $(date --date="@$(echo "$(grep btime /proc/stat|cut -d " " -f 2)+\1" | bc)" +"%c");echo -n "]";echo -n "\2"#e'
[2015-12-09T04:29:20 COT] cfg80211:   (57240000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 0 mBm), (N/A)
[2015-12-09T04:29:23 COT] wlp3s0: authenticate with dc:9f:db:92:d3:07
[2015-12-09T04:29:23 COT] wlp3s0: send auth to dc:9f:db:92:d3:07 (try 1/3)
[2015-12-09T04:29:23 COT] wlp3s0: authenticated
[2015-12-09T04:29:23 COT] wlp3s0: associate with dc:9f:db:92:d3:07 (try 1/3)
[2015-12-09T04:29:23 COT] wlp3s0: RX AssocResp from dc:9f:db:92:d3:07 (capab=0x431 status=0 aid=6)
[2015-12-09T04:29:23 COT] wlp3s0: associated
[2015-12-09T04:29:56 COT] thinkpad_acpi: EC reports that Thermal Table has changed
[2015-12-09T04:29:59 COT] i915 0000:00:02.0: BAR 6: [??? 0x00000000 flags 0x2] has bogus alignment
[2015-12-09T05:00:52 COT] thinkpad_acpi: EC reports that Thermal Table has changed

Si vous voulez qu'il fonctionne un peu mieux, placez plutôt l'horodatage de proc dans une variable :)

runejuhl
la source
4

Dans les versions récentes de dmesg, vous pouvez simplement appeler dmesg -T.

Steffen Heil
la source
3
La même réponse a déjà été donnée par RC deux ans avant la vôtre.
josch
4

Si vous n'avez pas l' -Toption dmesgcomme par exemple sur Andoid, vous pouvez utiliser la busyboxversion. Ce qui suit résout également d'autres problèmes:

  1. Le [0.0000]format est précédé de quelque chose qui ressemble à des informations de couleur mal placées, des préfixes comme <6>.
  2. Créez des nombres entiers à partir de flottants.

Il est inspiré de ce billet de blog .

#!/bin/sh                                                                                                               
# Translate dmesg timestamps to human readable format                                                                   

# uptime in seconds                                                                                                     
uptime=$(cut -d " " -f 1 /proc/uptime)                                                                                  

# remove fraction                                                                                                       
uptime=$(echo $uptime | cut -d "." -f1)                                                                                 

# run only if timestamps are enabled                                                                                    
if [ "Y" = "$(cat /sys/module/printk/parameters/time)" ]; then                                                          
  dmesg | sed "s/[^\[]*\[/\[/" | sed "s/^\[[ ]*\?\([0-9.]*\)\] \(.*\)/\\1 \\2/" | while read timestamp message; do      
    timestamp=$(echo $timestamp | cut -d "." -f1)                                                                       
    ts1=$(( $(busybox date +%s) - $uptime + $timestamp ))                                                               
    ts2=$(busybox date -d "@${ts1}")                                                                                    
    printf "[%s] %s\n" "$ts2" "$message"                                                                                
  done                                                                                                                  
else                                                                                                                    
  echo "Timestamps are disabled (/sys/module/printk/parameters/time)"                                                   
fi                                                                                                                      

Notez cependant que cette implémentation est assez lente.

Anne van Rossum
la source
3

vous aurez besoin de référencer le "btime" dans / proc / stat, qui correspond à l'époque Unix au dernier démarrage du système. Ensuite, vous pouvez vous baser sur cette heure de démarrage du système, puis ajouter les secondes écoulées données dans dmesg pour calculer l'horodatage de chaque événement.

imcom
la source