209

I want to do something like

dmesg | tail -f

but it doesn't work:

I use Mac OS X v10.6.7 (Snow Leopard). By doing that, tail will exit, instead of monitoring the output.

I wonder if there is a way to do it, or an equivalent command.

P.S., I don't think a while loop will be a good enough idea.

Ivan Xiao
  • 2,945

17 Answers17

206

You are probably looking for some combination of messages from various log files. Try:

tail -f /var/log/{messages,kernel,dmesg,syslog}

…to get a pretty good overview of the system. If you want more or less than that, research what log file the messages you want to see are being placed in.

Also look into using multitail to file and color code and filter multiple log files at once.

Edit: This wasn't very relevant when I answered this, but as this page gets a lot of hits I'm thought it worth mentioning since kernel 3.5, you can do this:

dmesg -w
Caleb
  • 6,129
101

On Linux, since kernel kernel 3.5.0 you can use:

dmesg -w

Also on systems with systemd you can use:

journalctl -kf
waterproof
  • 162
  • 7
Maxim
  • 2,461
  • 3
  • 17
  • 7
60

Just make it @#$%ing work

  1. You want to print output of dmesg, constantly, immediately
  2. Dmesg is printing the kernel ring buffer (see man dmesg)
  3. The kernel ring buffer is a special proc file, /proc/kmsg (see man proc)
  4. Read /proc/kmsg directly, ie cat /proc/kmsg.

Now, if you read the friendly proc manual, it'll sternly warn you to let only one user (who must be privileged) read /proc/kmsg at a time. Whatever syslog implementation you have should be doing this, and presumably it works with dmesg. I dunno, I'm out of my league here, just paraphrasing the manual. So while this is the "just make it @#$%ing work" way, consider the next couple methods first.

Man page approved: watch + dmesg

On one linux box I use with systemd init*, dmesg.log isn't written to very often, perhaps not at all? The best way I found to read the kernel log buffer continuously is with watch. Something like this should get you started (adjust for how many lines fit in your terminal):

watch 'dmesg | tail -50'

watch + dmesg + daemon + tail -f

A more convoluted solution might use watch to write dmesg output to file, which you could then tail -f. You'd probably want this running as a daemon. A proper daemon would also gzip and rotate logs. The following bash code is untested, unworking, and only intended to convey an idea. @Brooks Moses's answer has a working version.

watch 'dmesg >> /var/log/dmesg.log | tail -1'

* tangent, cause this is a question about an apple desktop os: when systemd is around, don't bother with dmesg; use journalctl -xf (maybe w/ -n 100 to also show the previous 100 lines)

djeikyb
  • 951
22

Here's a variant on djeikyb's answer that's actually tested, and fixes a couple of bugs.

watch 'sudo dmesg -c >> /tmp/dmesg.log; tail -n 40 /tmp/dmesg.log'

The important trick is that we're doing dmesg -c, which clears the ring buffer after it prints -- thus, each time through we're only printing what's new since the last time.

You'll need to be root to do that, thus the sudo. There's also a bugfix; instead of trying to both dump the output to a file and pipe it to tail (which doesn't work), we're just reading from the newly-written file.

We could do just dmesg > /tmp/dmesg.log and overwrite the whole file each iteration, but that's a lot of I/O and also risks losing the file if the computer crashes in the middle of an overwrite.

You could also do something similar that's more closely like tail -f with a while loop that executes dmesg -c and sleep 1 forever (see Ben Harris's answer). However, since this is actually clearing the kernel message buffer as it's running, you may also want to pipe things into a logfile in case you want them later.

8

This may work for you

while true;do sudo dmesg -c;done

Keep in mind that the '-c' flag clears the message buffer into stdout. The 'sudo' is unnecessary if you are root. If you feel this is eating too much of your CPU resource, try adding a 'sleep 1' before the loop is done.

5

I did this before seeing this post:

#!/usr/bin/env perl

use strict;
use warnings;

# "tail -f" for dmesg
# Keeps last printed line. Anything sorting "gt" will be newer

$|=1;

my $y = '';

while(1) {
    for my $k (`dmesg`) {
        if ($k gt $y) {
            print $k;
            $y = $k;
        }
    }
    sleep 1;
}
exit;
4

Here are some ideas for limited environments

Environments such as embedded or pre-boot, where watch, tail, cat, dd and other commands might not be available, might need different gymnastics.

This is what some lightweight Linux distributions do:

while dmesg -c >> /tmp/dmesg.log; do sleep 0.1; done & tail -f /tmp/dmesg.log

It backgrounds the while loop (with &) while tailing the generated output.

If you can't write to /tmp:

mount -t tmpfs - /tmp 

# or 
mount -t ramfs - /tmp 

# or use /dev/shm instead of /tmp - which is available in newer environments

If you don't have tail, you can

cat /tmp/dmesg.log

# or 
dd if=/tmp/dmesg.log 

# or
dd if=/tmp/dmesg.log 2>/dev/null

Or you might be in a busybox environment that doesn't have dmesg linked, then just:

busybox dmesg -c

You might also need to

busybox sleep

instead of sleep

If you don't have sleep:

while dmesg -c; do echo >/dev/null; done 

If you don't have "dmesg":

while sleep 0.1; do cat -v /proc/kmsg; done

This only works if nothing else is reading from here. You might also have a /dev/kmsg.

Bonus tip:

If you don't know what you have, and you don't have "ls", just:

busybox ls

# or simply:

echo *
Dagelf
  • 1,060
3

I use this alias in /root/.bashrc;

alias dwatch='watch -n 0.1 "dmesg | tail -n $((LINES-6))"'

which follows dmesg and adjusts the lines for whatever terminal it's called in.

edit: As lots of people have pointed out, it's as easy as dmesg -w since kernel 3.5.0.

drgibbon
  • 131
3

You might be able to do:

tail -f /var/log/messages
Ed L
  • 139
2

How about this:

dmesg | tail -f /dev/stdin
1

Follow kernel logs live (equal to dmesg command tail -f):

journalctl -t kernel -f

Recent kernel messages (1 hour):

journalctl --dmesg --since "1 hours ago"

Recent kernel messages (1 hour):

journalctl --dmesg --since "1 hours ago"

Recent kernel messages (1 hour):

journalctl -k --since "1 hours ago"

Concise recent kernel messages (1 hour):

journalctl -o short-precise -k -b -0 --dmesg --since "1 hours ago"
1

For anyone landing here looking to do this on Alpine Linux, the builtin BusyBox version of dmesg doesn't support the -w flag. To install a version that does, use one of:

apk add dmesg

or, grab the util-linux package which also contains other common tools like mount, lsblk, uuidgen, etc:

apk add util-linux

After that, dmesg -w will work as expected.

luckman212
  • 309
  • 2
  • 7
1

While dmesg -w is the way to go nowadays, you may also want to tail -f the output of an other command. A general way to handle it is to post-process the result of consecutive runs of that command.

Here's an example with dmesg, post-processed with awk; it uses an arbitrary delimiter 0x1C (which can be avoided if you directly run dmesg from within awk) injected in the stream to "separate" the outputs of each dmesg call:

while dmesg && printf '\034' && sleep 1; do : ; done |
awk -v RS='\034' -v ORS= '{
    print (index($0, prev) == 1 ? substr($0, length(prev)+1) : $0);
    prev = $0;
}'
Fravadona
  • 155
  • 7
0

I used this code to look for a special kernel event and piped it a "callback" process:

while true ; do dmesg -c ; sleep .1 ; done \
| grep --line-buffered  -o $pattern \
| ...
rzr
  • 314
  • 3
  • 8
0

On macOS, you can use the command log to watch logs on the command line. Use log -? or just log for help. It is a very good command line alternative to the GUI app /Applications/Utilities/Console.app. To continuously watch all system logs there is a stream mode:

log stream

The output is colourized and easy to read. Eventually, you may get too much information! In that case, I think that multitail recommended earlier in this thread by @Caleb is a very good option. Just select the files to watch:

multitail /var/log/system.log /var/log/*/launchd.log

PS: tested in macOS Monterey

ACosta
  • 1
0

Under the current Ubuntu (I am using Ubuntu 12.04 (Precise Pangolin)),

tail -f /var/log/syslog
6< <( cat /var/log/syslog |grep -F  'kernel: '; sudo cat /proc/kmsg) cat /dev/fd/6

( the sudo command need sudo privilege )

Please also try another one like: 6< <( dmesg; sudo cat /proc/kmsg) cat /dev/fd/6

-4

This might be useful:

dmesg | tail -f -

pipes the output of dmesg through tail using the - operator as a shortcut to standard output.