Categories
DailyOps

How to colorize command output

Colorize command output using grc a generic colouriser.

Installation

Install a generic colouriser for everything.

$ sudo apt install grc

Usage

It can help you with log files, command output, and configuration files.

$ sudo grc journalctl --lines 10 --unit kafka
-- Journal begins at Sat 2021-06-19 14:15:06 UTC, ends at Sat 2021-06-19 19:55:42 UTC. --
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,267] INFO [SocketServer listenerType=BROKER, nodeId=1] Starting socket server acceptors and processors (kafka.network.SocketServer)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,279] INFO [SocketServer listenerType=BROKER, nodeId=1] Started data-plane acceptor and processor(s) for endpoint : ListenerName(PLAINTEXT) (kafka.network.SocketServer)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,279] INFO [SocketServer listenerType=BROKER, nodeId=1] Started socket server acceptors and processors (kafka.network.SocketServer)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,281] INFO Kafka version: 2.8.0 (org.apache.kafka.common.utils.AppInfoParser)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,281] INFO Kafka commitId: ebb1d6e21cc92130 (org.apache.kafka.common.utils.AppInfoParser)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,281] INFO Kafka startTimeMs: 1624120078280 (org.apache.kafka.common.utils.AppInfoParser)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,282] INFO Kafka Server started (kafka.server.KafkaRaftServer)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,314] INFO [BrokerLifecycleManager id=1] The broker has been unfenced. Transitioning from RECOVERY to RUNNING. (kafka.server.BrokerLifecycleManager)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,822] INFO [Controller 1] Unfenced broker: UnfenceBrokerRecord(id=2, epoch=3) (org.apache.kafka.controller.ClusterControlManager)
Jun 19 16:27:58 kafka1.example.org kafka-server-start.sh[24851]: [2021-06-19 16:27:58,822] INFO [Controller 1] Unfenced broker: UnfenceBrokerRecord(id=1, epoch=2) (org.apache.kafka.controller.ClusterControlManager)
$ grc ss -tlpn
State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
LISTEN 0      128          0.0.0.0:22         0.0.0.0:*          
LISTEN 0      50                 *:9092             *:*          
LISTEN 0      50                 *:9093             *:*          
LISTEN 0      50                 *:45803            *:*          
LISTEN 0      128             [::]:22            [::]:* 
$ grcat conf.sysctl < /etc/sysctl.conf 
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additional system variables.
# See sysctl.conf (5) for information.
#

kernel.domainname = example.com

net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1

net.ipv4.tcp_syncookies = 1

kernel.sysrq = 0

It is extremely versatile.

Configuration

Applications/files are defined inside /etc/grc.conf file.

$ cat /etc/grc.conf 
[...]

# journalctl command
(^|[/\w\.]+/)journalctl?\s
conf.log

[...]

# ss command
(^|[/\w\.]+/)ss\s?
conf.ss

[...]

# sysctl command
(^|[/\w\.]+/)sysctl?\s
conf.sysctl

[...]

Configuration for each file/application is defined in /usr/share/grc/ directory.

$ cat /usr/share/grc/conf.log
# this configuration file is suitable for displaying kernel log files


# example of text substitution
#regexp=\bda?emon
#replace=angel
#colours=red
#======
# example of text substitution
#regexp=(\d\d):(\d\d):(\d\d)
#replace=\1h\2m\3s
#======

# display this line in yellow and stop further processing
regexp=.*last message repeated \d+ times$
colours=yellow
count=stop
======
# this is date
regexp=^... (\d| )\d \d\d:\d\d:\d\d(\s[\w\d]+?\s)
colours=green, green, red
count=once
======
# everything in parentheses
regexp=\(.+?\)
colours=green
count=more
======
# everything in `'
regexp=\`.+?\'
colours=bold yellow
count=more
======
# this is probably a pathname
regexp=/[\w/\.]+
colours=bold green
count=more
======
# name of process and pid
regexp=([\w/\.\-]+)(\[\d+?\])
colours=bold blue, bold red
count=more
======
# ip number
regexp=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
colours=bold magenta
count=more
======
# connect requires special attention
regexp=connect
colours=on_red
count=more
$ cat /usr/share/grc/conf.ss
# Local Address:Port
regexp=\s((?:\d+\.){3}\d+|\*|::1?|[\w\d\-\_\.]+):(\S+)\s+\s((?:\d+\.){3}\d+|\*|::1?|[\w\d\-\_\.]+):(\S+)
colours=default,bright_green,bright_red,cyan,magenta
=======
# ipx hostname
regexp=^IPX.*[\dABCDEF]+:[\dABCDEF]+
colours=green
=======
# protocols
regexp=(^tcp|^udp|^unix|^IPX|STREAM|DGRAM)
colours=magenta
=======
# protocols UDP
regexp=^udp
colours=yellow
=======
# protocols TCP
regexp=^tcp
colours=blue
=======
# status UNCONN
regexp=UNCONN
colours=dark red
=======
# status
regexp=FIN_WAIT.*
colours=red
=======
# status
regexp=SYN.*?
colours=bold red
=======
# status
regexp=LISTEN(ING)?
colours=bold blue
=======
# status
regexp=TIME_WAIT
colours=bold red
=======
# status
regexp=CLOS(E(_WAIT)?|ING)
colours=red
skip=yes
=======
# status
regexp=LAST_ACK
colours=red
=======
# status
regexp=ESTAB.*?\b|CONNECTED
colours=bold yellow
=======
# status
regexp=FREE
colours=bold green
=======
# status
regexp=DISCONNECTING
colours=red
=======
# status
regexp=CONNECTING
colours=green
=======
# status
regexp=UNKNOWN
colours=blink bold red
=======
# status
regexp=\[.*\]
colours=green
=======
# path
regexp=(\@)[\dabcdef]+
colours=green, bold green
=======
# timer
regexp=\d+sec
colours=yellow
=======
#Skip header
regexp=(Netid|State).*$
colours=default
$ cat /usr/share/grc/conf.sysctl 
# Main & Last key
regexp=(\w+)\.(\S+) = ?(.+)?$
colours=default,green,cyan,yellow
-
# subcategories
regexp=\w+\.(\S+(?=\.))\.
colours=unchanged,magenta
-
# error
regexp=sysctl: permission denied on key '([^']+)'
colours=red,bold red

This is enough to create the customized configuration.

Additional notes

The nice addition is zsh support out of the box.

$ cat /etc/grc.zsh
if [[ "$TERM" != dumb ]] && (( $+commands[grc] )) ; then

  # Supported commands
  cmds=(
    cc \
    configure \
    cvs \
    df \
    diff \
    dig \
    gcc \
    gmake \
    ifconfig \
    last \
    ldap \
    ls \
    make \
    mount \
    mtr \
    netstat \
    ping \
    ping6 \
    ps \
    traceroute \
    traceroute6 \
    wdiff \
    whois \
    iwconfig \
  );

  # Set alias for available commands.
  for cmd in $cmds ; do
    if (( $+commands[$cmd] )) ; then
      alias $cmd="grc --colour=auto $(whence $cmd)"
    fi
  done

  # Clean up variables
  unset cmds cmd
fi