Adding color to your tail

Tail is a very useful tool for monitoring an error stream. Sometimes the output from tail can have too much information, and its black-and-white monotone output can be hard to follow with the eyes.

The basic: a Linux terminal has the capability to colorize text. For example:

1
echo -e "Sample text nicely highlighted"

will produce a simple text saying, well:

Sample text nicely highlighted

But with some terminal color tagging such as:

1
echo -e "Sample \e[36mtext\e[0m nicely highlighted"

The \e above is identical to \033. I’d suggest using \033 because it’s safer in a programming language such as PHP. PHP will not recognize \e, but it will recognize \033, as you’ll see below.

1
echo -e "Sample \033[36mtext\033[0m nicely highlighted"

Sample text nicely highlighted

Some basic coloring tables can be seen at bashguru.com:

1
2
3
4
5
6
7
8
9
Color     Foreground  Background
Black     30          40
Red       31          41
Green     32          42
Yellow    33          43
Blue      34          44
Magenta   35          45
Cyan      36          46
White     37          47

With the help of perl, which most likely comes with all Linux distros, here’s a way to colorize your tail output. Let’s assume that every time you log something you will have a date-time prefixing your log. For example:

1
2
3
4
5
6
7
[22-Dec-2011 20:28:45] E_DATASOMETHING ......
Too much information .......
Too much information .......
[22-Dec-2011 20:28:46] E_FATAL Something
Too much information .......
Too much information .......
Too much information .......

Let’s create a script that can colorize the date portion. Create an executable Linux bash file:

1
2
3
touch logwatch.sh
chmod 755 logwatch.sh
vim logwatch.sh

Then copy and paste the following into your empty logwatch.sh:

1
2
3
#!/bin/bash
vNow=$(date +"%d-%b-%Y")
tail -f ~username/errorlogfile.txt | perl -pe "s/$vNow/\e[1;30;32m$&\e[0m/g"

Voilà!

[22-Dec-2011 20:28:45] E_DATASOMETHING ……
Too much information …….
Too much information …….
[22-Dec-2011 20:28:46] E_FATAL Something
Too much information …….
Too much information …….
Too much information …….

If you need something more complex — say you want to highlight several words in the file — you can use the scripting power of PHP. (I’m rusty with my perl.) Save the script below as colorize.php, and you can have the words blah, na, wa, and highlighted on the fly:

1
tail -f test.txt | php colorize.php blah na wa --
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
//stream_set_blocking(STDIN, FALSE);
$fp = fopen("php://stdin", "r");
// Failed to connect to STDIN? (shouldn't really happen)
if (!$fp) {
    echo "Cannot connect with standard input";
    exit();
}

array_shift($argv);
$replacements = array();
foreach ($argv as $arg) {
    $replacements[] = "\033[36m$arg\033[0m";
}

// Read each line as it arrives on STDIN
while ($line = fgets($fp)) {
    echo str_ireplace($argv, $replacements, $line);
}

// Close connection to STDIN
fclose($fp);
echo "done!";
?>

A few useful additions.

The simpler path: grep –color. If you only need to highlight a single pattern, you don’t need perl or PHP at all — grep can do it, and the –color=always flag forces color even through a pipe (where grep otherwise drops it because stdout isn’t a terminal):

1
tail -f errorlog.txt | grep --color=always -E "E_FATAL|E_ERROR|.*"

The trailing .* is the trick that makes this work as a highlighter rather than a filter — it matches every line, so nothing gets dropped, but the alternation patterns still get colored where they appear. The -E flag enables extended regex.

The line-buffering gotcha. When you chain tail -f through several filters, each program in the pipeline buffers its output by default. The result: nothing appears on screen for several seconds, then a wall of lines all at once — useless for live monitoring. Force line-buffering on each stage:

1
tail -f errorlog.txt | grep --line-buffered "ERROR" | sed -u 's/old/new/'

–line-buffered is the GNU grep flag; -u is the equivalent for sed; for awk, use fflush() after each print. If you don’t see live output through your pipeline, this is almost always why.

Purpose-built tools. If colorizing logs is something you do often, two tools save you from rolling your own:

  • ccze — pipe a log into it (tail -f /var/log/syslog | ccze -A) and it auto-colorizes by recognizing common log formats (syslog, Apache, Squid, etc.). The -A flag emits ANSI for piping; without it, ccze prefers its own curses-based UI.
  • multitail — like tail -f but with split panes for watching multiple files at once, plus per-pattern highlighting via a config file. Heavier but powerful when you’re staring at three log files at the same time.

Both are in the standard repos for Debian/Ubuntu/Fedora — apt install ccze multitail or equivalent.

Two reset bookkeeping notes. If your colored output starts “leaking” — i.e. text after a match keeps showing up colored — your reset escape (\e[0m) didn’t fire. Common causes: a trailing newline got stripped before the reset, or you forgot the reset entirely. Always pair \e[Xm with \e[0m. And if you ever end up in a terminal stuck in some weird color state, the command reset (or tput reset) puts everything back to defaults.

This entry was posted in Linux, Operating System, Ubuntu. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


× 5 = forty