Home > Software engineering >  Colorize terminal output by pattern
Colorize terminal output by pattern

Time:01-03

I have an app which generates some output:

$ my-app
[metadata] - [21:06:51 DBG] Some message 111 <s:Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware>
[metadata] - [21:06:52 DBG] Some message 222 <s:Microsoft.AspNetCore.Hosting.Diagnostics>
[metadata] - [21:06:52 ERR] Some message 223 <s:Microsoft.AspNetCore.Routing.Matching.DfaMatcher>
[metadata] - [21:06:54 DBG] Some message 333 <s:PocApi.MyApp.Foo>

I remove the [metadata] - part of the output as follows:

$ my-app | sed -r 's/.*\] - *//'
[21:06:51 DBG] Some message 111 <s:Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware>
[21:06:52 DBG] Some message 222 <s:Microsoft.AspNetCore.Hosting.Diagnostics>
[21:06:52 ERR] Some message 223 <s:Microsoft.AspNetCore.Routing.Matching.DfaMatcher>
[21:06:54 DBG] Some message 333 <s:PocApi.MyApp.Foo>

Now, I wish to color code the output (i.e., encode with ANSI color codes) so that:

  1. The text inside and including [ and ] is always grey.
  2. The message on lines which contain <s:PocApi are yellow.
  3. The message on lines which contain DBG are light grey.
  4. The message on lines which contain ERR are red.

Note, the message is always between ] and <.

Any ideas how I might do this? Maybe printf, but I don't see a way to do pattern matching. Thanks for the help.

Oh, and for what it's worth, my-app is a long-running application that streams output.

CodePudding user response:

For test purposes:

$ cat input
[21:06:51 DBG] Some message 111 <s:Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware>
[21:06:52 DBG] Some message 222 <s:Microsoft.AspNetCore.Hosting.Diagnostics>
[21:06:52 ERR] Some message 223 <s:Microsoft.AspNetCore.Routing.Matching.DfaMatcher>
[21:06:54 DBG] Some message 333 <s:PocApi.MyApp.Foo>

One awk idea:

while read -r line
do
    echo "${line}"
    sleep 2
done < input |
awk '
BEGIN       {          # foreground colors    # background colors
              red    = "\033[1;31m"           # 41m
              green  = "\033[1;32m"           # 42m
              yellow = "\033[1;33m"           # 43m
              blue   = "\033[1;34m"           # 44m
              purple = "\033[1;35m"           # 45m
              reset  = "\033[0m"
            }

/DBG/       { msg_color=blue   }
/<s:PocApi/ { msg_color=yellow }
/ERR/       { msg_color=red    }

            { line=$0

              pos=index(line,"]")
              out=green substr(line,1,pos) reset " " msg_color
              line=substr(line,pos 2)

              pos=index(line,"<")
              out=out substr(line,1,pos-2) reset substr(line,pos-1)
              print out
            }
'

This generates:

enter image description here

NOTES:

  • assumes all lines start with a [...] string followed at some point by a left arrow (<)
  • the while read ... do < input | is to simulate OP's long-running application that streams output to the sed ... | awk ... pipeline
  • OP hasn't provided rules for what happens when 2 (or more) rules apply to the same line (eg, line contains both DBG and <s:PocApi) so I've picked an arbitrary precedent (patterns matched later in script take precedence over patterns matched earlier in script)
  • assumes there's a single space before/after all messages and said spaces are not to be colorized
  • color codes were derived from this wiki page; OP should be able to find additional colors with a general web search on something like ansi color codes; also keep in mind available colors can vary based on the terminal (type)

CodePudding user response:

Using sed

$ sed -E "s/.[^[]*([^]]*ERR])([^<]*)/$(tput setaf 8)\1$(tput sgr 0)$(tput setaf 9)\2$(tput sgr 0)/;\
/DBG][^<]*<s:PocApi/s/.[^[]*([^]]*])([^<]*)/$(tput setaf 8)\1$(tput sgr 0)$(tput setaf 11)\2$(tput sgr 0)/;\
/<s:PocApi/ ! {s/.[^[]*([^]]*DBG])([^<]*)/$(tput setaf 8)\1$(tput sgr 0)$(tput setaf 7)\2$(tput sgr 0)/}" input_file
  • Related