4

I'm stuck on trying to colorize tail -f output so that the IP address color is unique per IP address. I can't find anything by searching.

Here's some code that colors the current IP address alone but it's the same color for every IP.

tail -f /var/www/domain.com/logs/global.log | egrep --color=auto '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}'

I'm looking to have a unique color per IP address. So you can differentiate between users.

I've tried:

tail -f /var/www/domain.com/logs/global.log | GREP_COLOR='01;36' egrep --color -E '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}|$'

I'm trying to work out a way of defining the color based on what the IP is but i'm unsure on how to proceed.

But not much has helped so far. Am I on the right lines? Cheers


Results

Thanks to the help below here's a working compiled answer

# Color ip address only
tail -f /var/www/file | perl -pe 's/\d{1,3}\.\d{1,3}.(\d{1,3})\.\d{1,3}/\033[38;5;\1\2\3m$&\033[39m/g'

My new most used

# Color entire line
tail -f /var/file.log | perl -pe 's/^.*(\d{1,3})\.(\d{1,3}).(\d{1,3})\.(\d{1,3}).*$/\033[38;5;\2\2\3m$&\033[39m/g'
Jack
  • 3,271
  • 11
  • 48
  • 57
  • 1
    How many unique IP addresses are we talking here? Terminals generally support a limited set of colors. – bgoldst Sep 04 '16 at 23:11
  • 1
    Also, do you want to support dynamic assignment of colors to previously-unseen IP addresses? It's either that or predefining a map of statically-known IPs to colors. It's a bit of a tradeoff; dynamic would obviously allow new IPs to be colored whereas static would not, but dynamic would likely result in inconsistent coloring of the same IPs across runs of your command, which I imagine would be very undesirable. – bgoldst Sep 04 '16 at 23:45
  • Thinking more dynamic coloring. Not hugely fussed if colors are similar as long as it's simple enough to distinguish between users. I've tested the answer by Eric but it seems to strip out other content in the output but does color the IP dynamically. Thanks for your response. – Jack Sep 05 '16 at 10:34

1 Answers1

6

Here's a possibility in perl: tail -f YOURFILE| perl -pe 's/\d{1,3}\.\d{1,3}.(\d{1,3})\.\d{1,3}/\033[38;5;\1\2\3m$&\033[39m/g'

It replaces each IP-address looking substring with an ANSI color sequence based on its third octet.

It works the same in re2g: tail -f YOURFILE| re2g -gp '\d{1,3}\.\d{1,3}.(\d{1,3})\.\d{1,3}' -s $'\033[38;5;\\1\\2\\3m\\0\033[39m'

In perl, you can get a little fancier with your color choices though: tail -f YOURFILE| perl -pe 's/(\d{1,3})\.(\d{1,3}).(\d{1,3})\.(\d{1,3})/"\033[38;5;".(16+($1+$2+$3+$4)%214)."m$&\033[39m"/ge'. This version guarantees that the color falls into nice visible range and also bases the color on all four octets.

See also: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

Eric
  • 1,431
  • 13
  • 14
  • Thanks for your answer. It's working by coloring the IP dynamically and uniquely. However when I use your code it seems to turn all default text colors on my terminal to black (So I can't see the text anymore) for any other output code like `ls -l`. Also it seemed to strip out other content on that line and only show the IP address. Thank you for your answer though! It's like 70% there. I'll see if I can fiddle – Jack Sep 05 '16 at 10:36
  • 1
    I use a white-background terminal :) Just change `[38;5;0m` to have something other than a zero before the "m" in order to return the text to your chosen color. – Eric Sep 05 '16 at 12:25
  • 1
    This may work for you without having to explicitly choose a color. Change `[38;5;0m` to `[39m` or `[0m`. It depends on what your terminal's notion of a "default" color is. I've edited the answer to reflect the `[39m` option. – Eric Sep 05 '16 at 12:35
  • I see! Great answer! Thanks a lot for the help - all seems to be working with unique colors per IP. :) – Jack Sep 05 '16 at 12:54
  • And just to annoy you - Are you able to make a variation where it colors the whole line and not just the IP address? In the mean time I'll see if I can work it out myself. Cheers – Jack Sep 05 '16 at 13:01
  • 1
    Do you want the whole line colored or just from the IP onward? What if there are two IPs on a line? If you just want to color the whole line based on the first IP, just wrap the pattern with anchors: `s/^.*(\d{1,3})\.(\d{1,3}).(\d{1,3})\.(\d{1,3}).*$/…` – Eric Sep 05 '16 at 13:18
  • @eric - are you able to update so that it works with ipv6 also? IPV6 addresses all seem to be the same color – Jack Dec 10 '17 at 18:21