File Coverage

lib/App/RouterColorizer.pm
Criterion Covered Total %
statement 406 431 94.2
branch 17 18 94.4
condition 4 4 100.0
subroutine 25 25 100.0
pod 1 1 100.0
total 453 479 94.5


line stmt bran cond sub pod time code
1             #!/usr/bin/env perl
2              
3             #
4             # Copyright (C) 2021-2023 Joelle Maslak
5             # All Rights Reserved - See License
6             #
7              
8             # ABSTRACT: Colorize router CLI output
9              
10 10     10   2022926 use v5.22;
  10         105  
11 10     10   74 use strict;
  10         18  
  10         221  
12 10     10   50 use warnings;
  10         27  
  10         433  
13              
14             package App::RouterColorizer;
15             $App::RouterColorizer::VERSION = '1.231650';
16 10     10   5831 use Moose;
  10         4764564  
  10         65  
17              
18 10     10   79206 use feature 'signatures';
  10         29  
  10         1767  
19 10     10   102 no warnings 'experimental::signatures';
  10         36  
  10         557  
20              
21 10     10   6903 use English;
  10         37692  
  10         70  
22 10     10   10067 use Import::Into;
  10         5985  
  10         386  
23 10     10   97 use List::Util qw(any);
  10         34  
  10         762  
24 10     10   5855 use Regexp::Common qw/net number/;
  10         28430  
  10         97  
25              
26             # Ugly! But we need multidimensional arrays to work to get access to the
27             # syntactic sugar in Regexp::Common. Unfortunately, this feature didn't
28             # exist until recently (it was defaulting to being on).
29             BEGIN {
30 10 50   10   179368 if ( $PERL_VERSION gt v5.33.0 ) {
31 0         0 feature->import::into( __PACKAGE__, qw(multidimensional) );
32             }
33             }
34              
35             our $GREEN = "\e[32m"; # Green ANSI code
36             our $RED = "\e[1;31m"; # Bold + Red ANSI code
37             our $ORANGE = "\e[33m"; # Orange
38             our $INFO = "\e[36m"; # Cyan
39             our $RESET = "\e[0m";
40              
41             our @BGCOLORS = (
42             "\e[30m\e[47m", # black on white
43             "\e[35m\e[47m", # magenta on white
44             "\e[90m\e[47m", # gray on white
45             "\e[30m\e[41m", # black on red
46             "\e[90m\e[41m", # gray on red
47             "\e[37m\e[41m", # white on red
48             "\e[30m\e[42m", # black on green
49             "\e[30m\e[43m", # black on yellow (orange)
50             "\e[31m\e[43m", # red on yellow (orange)
51             "\e[37m\e[44m", # white on blue
52             "\e[30m\e[45m", # black on magenta
53             "\e[37m\e[45m", # white on magenta
54             "\e[30m\e[46m", # black on cyan
55             "\e[30m\e[100m", # black on gray
56             "\e[97m\e[100m", # white on gray
57             );
58              
59             our $NUM = qr/$RE{num}{real}/;
60             our $INT = qr/$RE{num}{int}{-sign => ''}/;
61             our $POSINT = qr/(?!0)$INT/;
62             our $LOWLIGHT = qr/ (?: -[3-9][0-9]\. [0-9]{1,2} )
63             | (?: - \s Inf)
64             | (?: -2 [5-9] \. [0-9]{1,2} )/xx;
65             our $VERYLL = qr/ (?: -[4-9][0-9]\. [0-9]{1,2} )/xx;
66             our $LIGHT = qr/ (?: $NUM ) | (?: N\/A ) /xx;
67              
68             our $GOODRETURNLOSS = qr/ (?: 29\.[0-9]+ )
69             | (?: [3-9][0-9]+\.[0-9]+ )/xx;
70             our $WARNRETURNLOSS = qr/ (?: 2[0-8]\.[0-9]+ )
71             | (?: 1[6-9]\.[0-9]+ )/xx;
72             our $BADRETURNLOSS = qr/ (?: 1[0-5]\.[0-9]+ )
73             | (?: [0-9]\.[0-9]+ )/xx;
74              
75             our $IPV4CIDR = qr/ $RE{net}{IPv4}
76             (?: \/
77             (?:
78             (?:[12][0-9])
79             | (?:3[0-2])
80             | (?:[0-9])
81             )
82             )?
83             /xx;
84              
85             our $IPV6CIDR = qr/ $RE{net}{IPv6}
86             (?: \/
87             (?:
88             (?:1[01][0-9])
89             | (?:12[0-8])
90             | (?:[1-9][0-9])
91             | (?:[0-9])
92             )
93             )?
94             /xx;
95              
96             our $BIGALARMS = qr/critical|major|minor|warning/;
97             our $LITTLEALARMS = qr/info/;
98             our $BIGOVERRIDES = qr/ (?:\QRx Remote Fault\E)
99             | (?:\QFar End Client Signal Fail\E)
100             /xx;
101              
102             our @INTERFACE_IGNORES = ( "bytes", "packets input", "packets output", "multicast" );
103             our @INTERFACE_INFOS = ( "PAUSE input", "PAUSE output", "pause input" );
104              
105             our $STP_GOOD = qr/forwarding|FWD/;
106             our $STP_WARN = qr/learning|LRN/;
107             our $STP_BAD = qr/discarding|BLK/;
108             our $STP_TYPES = qr/designated|root|alternate|Desg|Root|Altn/;
109              
110             our @bgcolors = (
111             "\e[30m\e[47m", # black on white
112             "\e[30m\e[41m", # black on red
113             "\e[30m\e[42m", # black on green
114             "\e[30m\e[43m", # black on yellow (orange)
115             "\e[37m\e[44m", # white on blue
116             "\e[30m\e[45m", # black on magenta
117             "\e[30m\e[46m", # black on cyan
118             );
119              
120 4994     4994 1 106306 sub format_text ( $self, $text ) {
  4994         7834  
  4994         7639  
  4994         6861  
121             # Remove Arista "more" prompt
122 4994         10219 $text =~ s/ \x1b \[ \Q3m --More-- \E \x1b \[ 23m \x1b \[ K \r \x1b \[ K //gmsxx;
123              
124             # Break into lines
125 4994         7812 my $output = '';
126 4994         20458 while ( $text =~ m/([^\n\r]*[\r]?[\n]?)/g ) {
127 10053         23352 $output .= $self->_parse_line($1);
128             }
129 4994         19361 return $output;
130             }
131              
132 10053     10053   14176 sub _parse_line ( $self, $text ) {
  10053         14288  
  10053         22195  
  10053         14240  
133 10053         34820 my ( $line, $eol ) = $text =~ m/([^\n]*)(\n?)/;
134              
135             # We want to strip out the control characters at the start of the
136             # line. This is kind of black magic...
137 10053         18423 my $preamble = '';
138 10053 100       24177 if ( $line =~ s/^ ( .* (?<! \x1b \[23m) \x1b (?: \[K | M)) //sxx ) {
139 9         25 $preamble = $1;
140             }
141              
142             # Arista "More" prompt (should this be in the Arista parse-line?)
143 10053         15076 $line =~ s/ ^ ( \x1b \[ \Q3m --More-- \E .* \x0d \x1b \[K )//sxx;
144              
145             # A space that is backspaced over
146 10053         14825 $line =~ s/ \Q \E \x08 //gxx;
147              
148 10053         14430 my $trailer = "";
149 10053 100       30869 if ( $line =~ s/(\x0d) $//sxx ) {
150 4929         11046 $trailer = $1;
151             }
152              
153 10053         21807 $line = $self->_parse_line_arista($line);
154 10053         23545 $line = $self->_parse_line_vyos($line);
155 10053         20431 $line = $self->_parse_line_junos($line);
156 10053         23884 $line = $self->_parse_line_ciena($line);
157              
158             # IPv4
159 10053         35080 $line =~ s/($IPV4CIDR)/$self->_ipv4ify($1)/egxx;
  73         231  
160              
161             # IPv6
162 10053         307826 $line =~ s/ ( (?<! [a-fA-F0-9:\-]) $IPV6CIDR (?! [\w:\.\/]) ) /$self->_ipv6ify($1)/egxx;
  17         68  
163              
164             # Numbers
165             # We need to make sure we don't highlight undesirably, such as in an
166             # escape sequence.
167 10053         27944 $line =~ s/ (
168             (?<! [:\.0-9]) (?<! \e \[) (?<! \e \[\?)
169             [0-9]+ (?! [:0-9])
170 8150         18499 ) /$self->_numerify($1)/egxx;
171              
172 10053         65633 return "$preamble$line$trailer$eol";
173             }
174              
175 10053     10053   14729 sub _parse_line_arista ( $self, $line ) {
  10053         14721  
  10053         15805  
  10053         13854  
176             #
177             # Arista & Cisco
178             #
179              
180             # BGP
181 10053         14985 $line =~ s/^ ( \Q BGP state is Established\E \N* ) $/$self->_colorize($1, $GREEN)/exx;
  2         10  
182 10053         15030 $line =~ s/^ ( \Q BGP state is \E \N* ) $/$self->_colorize($1, $RED)/exx;
  2         19  
183              
184 10053         14342 $line =~
185 6         48 s/^ ( \Q Last \E (?: sent || rcvd) \ (?: socket-error || notification) : \N+ ) $/$self->_colorize($1, $INFO)/exx;
186              
187 10053         14957 $line =~
188 2         8 s/^ ( \ \ (?: Inbound || Outbound) \Q route map is \E \N* )$/$self->_colorize($1, $INFO)/exx;
189 10053         14717 $line =~
190 0         0 s/^ ( \Q Inherits configuration from and member of peer-group \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
191              
192 10053         14025 $line =~
193 8         24 s/^ ( \Q \E (?: IPv4 | IPv6) \Q Unicast: \E \N* ) $/$self->_colorize($1, $INFO)/exx;
194 10053         14332 $line =~
195 5         26 s/^ ( \Q Configured maximum total number of routes is \E \d+ (?: \Q, warning limit is \E \d+ )? ) $/$self->_colorize($1, $INFO)/exx;
196              
197             # BGP Errors
198 10053         94200 my $errors = qr/
199             ^
200             \Q \E
201             (?:
202             \QAS path loop detection\E
203             | \QEnforced First AS\E
204             | \QMalformed MPBGP routes\E
205             | \QAS path loop detection\E
206             | \QOriginator ID matches local router ID\E
207             | \QNexthop matches local IP address\E
208             | \QResulting in removal of all paths in update (treat as withdraw)\E
209             | \QResulting in AFI\E \/ \QSAFI disable\E
210             | \QResulting in attribute ignore\E
211             | \QDisabled AFI\E \/ \QSAFIs\E
212             | \QIPv4 labeled-unicast NLRIs dropped due to excessive labels\E
213             | \QIPv6 labeled-unicast NLRIs dropped due to excessive labels\E
214             | \QIPv4 local address not available\E
215             | \QIPv6 local address not available\E
216             | \QUnexpected IPv6 nexthop for IPv4 routes\E
217             )
218             \Q: \E
219             $POSINT
220             $
221             /xx;
222 10053         35262 $line =~ s/($errors)/$self->_colorize($1, $RED)/e;
  0         0  
223              
224 10053         16862 $line =~ s/^ ( \QBGP neighbor is \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  5         17  
225 10053         15265 $line =~ s/^ ( (?: Local | Remote) \Q TCP address is \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  7         47  
226              
227             #
228             # Interfaces
229             #
230              
231             # We look for information lines
232 10053 100       40108 if ( $line =~ m/^ ((?:$INT [^,]+, )*$INT [^,]+)$/ ) {
233             my (%values) =
234 690         2863 map { reverse split / /, $_, 2 } split ', ', $1;
  1617         5528  
235              
236 690 100   2250   4118 if ( any { exists( $values{$_} ) } @INTERFACE_IGNORES ) {
  2250 100       5095  
    100          
237             # Do nothing.
238 1329     1329   3226 } elsif ( any { exists( $values{$_} ) } @INTERFACE_INFOS ) {
239 128         339 $line = $self->_colorize( $line, $INFO );
240 1070     1070   1797 } elsif ( any { $values{$_} } keys %values ) {
241 16         73 $line = $self->_colorize( $line, $RED );
242             } else {
243 363         981 $line = $self->_colorize( $line, $GREEN );
244             }
245             }
246              
247 10053         26307 my $INTERFACE = qr/ [A-Z] \S+ /xx;
248 10053         20795 my $INTSHORT = qr/ [A-Z][a-z][0-9] \S* /xx;
249              
250             # "show int" up/down
251 10053         32227 $line =~
252 43         142 s/^ ( $INTERFACE \Q is up, line protocol is up\E (:? \Q (connected)\E )? \s? ) $/$self->_colorize($1, $GREEN)/exx;
253 10053         27683 $line =~
254 34         98 s/^ ( $INTERFACE \Q is administratively down,\E \N+ ) $/$self->_colorize($1, $ORANGE)/exx;
255 10053         28332 $line =~
256 11         48 s/^ ( $INTERFACE \Q is \E \N+ \Q, line protocol is \E \N+ ) $/$self->_colorize($1, $RED)/exx;
257              
258 10053         16353 $line =~ s/^ ( \Q Up \E \N+ ) $/$self->_colorize($1, $GREEN)/exx;
  36         108  
259 10053         14651 $line =~ s/^ ( \Q Down \E \N+ ) $/$self->_colorize($1, $RED)/exx;
  38         136  
260              
261             # "show int" description lines
262 10053         15207 $line =~ s/^ ( (?: \Q \E|\Q \E)? \Q Description: \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  72         219  
263              
264             # "show int" rates
265 10053         33687 $line =~
266 170         485 s/^ ( \Q \E $NUM \s \w+ \s (?: input | output) \s rate \s $NUM \s \N+ ) $/$self->_colorize($1, $INFO)/exx;
267              
268             # "show int status"
269 10053         26797 $line =~ s/^ ( $INTSHORT \N+ \Q connected \E \N+ ) $/$self->_colorize($1, $GREEN)/exx;
  38         119  
270 10053         26194 $line =~ s/^ ( $INTSHORT \N+ \Q disabled \E \N+ ) $/$self->_colorize($1, $ORANGE)/exx;
  34         118  
271 10053         25192 $line =~ s/^ ( $INTSHORT \N+ \Q errdisabled \E \N+ ) $/$self->_colorize($1, $RED)/exx;
  0         0  
272 10053         24809 $line =~ s/^ ( $INTSHORT \N+ \Q notconnect \E \N+ ) $/$self->_colorize($1, $RED)/exx;
  10         39  
273              
274             # "show int description"
275 10053         23128 $line =~
276 36         115 s/^ ( $INTSHORT \s+ up \s+ up (?: \s+ \N+)? ) $/$self->_colorize($1, $GREEN)/exx;
277 10053         24712 $line =~
278 33         96 s/^ ( $INTSHORT \s+ \Qadmin down\E \s+ \S+ (?: \s+ \N+)? ) $/$self->_colorize($1, $ORANGE)/exx;
279 10053         22623 $line =~
280 5         15 s/^ ( $INTSHORT \s+ down \s+ \S+ (?: \s+ \N+)? ) $/$self->_colorize($1, $RED)/exx;
281              
282             # "show int transceiver" (Arista)
283 10053         32398 $line =~
284 16         51 s/^ ( $INTSHORT (?: \s+ $LIGHT){4} \s+ $LOWLIGHT \s+ \S+ \s ago ) $/$self->_colorize($1, $RED)/exx;
285 10053         27660 $line =~
286 8         28 s/^ ( $INTSHORT (?: \s+ $LIGHT){5} \s+ \S+ \s ago ) $/$self->_colorize($1, $INFO)/exx;
287 10053         23248 $line =~
288 0         0 s/^ ( $INTSHORT (?: \s+ N\/A ){6} \s* ) $/$self->_colorize($1, $ORANGE)/exx;
289              
290             # "show int transceiver" (Cisco)
291 10053         32998 $line =~
292 1         5 s/^ ( $INTSHORT (?: \s+ $LIGHT){3} \s+ $LOWLIGHT ) \s+ $/$self->_colorize($1, $RED)/exx;
293 10053         28447 $line =~
294 3         10 s/^ ( $INTSHORT (?: \s+ $LIGHT){4} ) \s+ $/$self->_colorize($1, $INFO)/exx;
295              
296             #
297             # LLDP Neighbors Detail
298             #
299 10053         29819 $line =~
300 0         0 s/^ ( \QInterface\E \s \S+ \s detected \s $POSINT \Q LLDP neighbors:\E ) $/$self->_colorize($1, $INFO)/exx;
301 10053         26475 $line =~
302 0         0 s/^ ( \Q Neighbor \E \S+ \s age \s $POSINT \s seconds ) $/$self->_colorize($1, $INFO)/exx;
303 10053         16010 $line =~
304 0         0 s/^ ( \Q Discovered \E \N+ \Q; Last changed \E \N+ \s ago ) $/$self->_colorize($1, $INFO)/exx;
305 10053         13989 $line =~ s/^ ( \Q - System Name: \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  0         0  
306 10053         14901 $line =~ s/^ ( \Q Port ID :\E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  0         0  
307 10053         13704 $line =~ s/^ ( \Q Management Address : \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  0         0  
308              
309             #
310             # Show Spanning-Tree
311             #
312 10053         30426 $line =~
313 13         41 s/^ ( $INTSHORT \s+ $STP_TYPES\s+ $STP_GOOD \s+ [0-9]+ \s+ [0-9]+\.[0-9]+ \s+ P2p .* ) $/$self->_colorize($1, $GREEN)/exx;
314 10053         29018 $line =~
315 1         13 s/^ ( $INTSHORT \s+ $STP_TYPES\s+ $STP_WARN \s+ [0-9]+ \s+ [0-9]+\.[0-9]+ \s+ P2p .* ) $/$self->_colorize($1, $ORANGE)/exx;
316 10053         28204 $line =~
317 2         13 s/^ ( $INTSHORT \s+ $STP_TYPES\s+ $STP_BAD \s+ [0-9]+ \s+ [0-9]+\.[0-9]+ \s+ P2p .* ) $/$self->_colorize($1, $RED)/exx;
318              
319              
320             # show bgp rpki cache (Arista)
321 10053         15094 $line =~ s/^ (State: \s synced) $/$self->_colorize($1, $GREEN)/exx;
  1         5  
322 10053         14392 $line =~ s/^ (State: \s .* ) $/$self->_colorize($1, $RED)/exx;
  1         6  
323              
324 10053         14557 $line =~ s/^ (Connection: \s Active \s .*) $/$self->_colorize($1, $GREEN)/exx;
  1         5  
325 10053         14197 $line =~ s/^ (Connection: \s .* ) $/$self->_colorize($1, $RED)/exx;
  0         0  
326              
327 10053         49306 return $line;
328             }
329              
330 10053     10053   14086 sub _parse_line_junos ( $self, $line ) {
  10053         13624  
  10053         14275  
  10053         13319  
331              
332             #
333             # JunOS
334             #
335              
336             # Show Interfaces
337 10053         14446 $line =~
338 53         139 s/^ ( \QPhysical interface: \E \S+ \Q Enabled, Physical link is Up\E ) $/$self->_colorize($1, $GREEN)/exx;
339 10053         14051 $line =~
340 36         104 s/^ ( \QPhysical interface: \E \S+ \Q Enabled, Physical link is Down\E ) $/$self->_colorize($1, $RED)/exx;
341 10053         13412 $line =~
342 0         0 s/^ ( \QPhysical interface: \E \S+ \s \S+ \Q Physical link is Down\E ) $/$self->_colorize($1, $ORANGE)/exx;
343 10053         13865 $line =~
344 2         22 s/^ ( \QPhysical interface: \E \S+ ) $/$self->_colorize($1, $INFO)/exx;
345              
346 10053         14849 $line =~ s/^ ( \Q Logical interface \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  72         170  
347              
348 10053         13623 $line =~ s/^ ( \Q Last flapped : \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  40         102  
349              
350 10053         31085 $line =~ s/^ ( \Q Input rate : \E $NUM \N+ ) $/$self->_colorize($1, $INFO)/exx;
  29         68  
351 10053         28028 $line =~ s/^ ( \Q Output rate : \E $NUM \N+ ) $/$self->_colorize($1, $INFO)/exx;
  29         86  
352              
353 10053         28592 $line =~ s/^ ( \Q Input packets : \E $NUM \N+ ) $/$self->_colorize($1, $INFO)/exx;
  44         122  
354 10053         27514 $line =~ s/^ ( \Q Output packets: \E $NUM \N+ ) $/$self->_colorize($1, $INFO)/exx;
  44         105  
355              
356 10053         15356 $line =~ s/^ ( \Q Active alarms : None\E ) $/$self->_colorize($1, $GREEN)/exx;
  12         38  
357 10053         13608 $line =~ s/^ ( \Q Active alarms : \E \N+ ) $/$self->_colorize($1, $RED)/exx;
  13         41  
358 10053         14716 $line =~ s/^ ( \Q Active defects : None\E ) $/$self->_colorize($1, $GREEN)/exx;
  12         57  
359 10053         14210 $line =~ s/^ ( \Q Active defects : \E \N+ ) $/$self->_colorize($1, $RED)/exx;
  13         38  
360              
361 10053         23533 my $AE = qr/ (?: ae [0-9\.]+ ) /xx;
362 10053         21035 my $BME = qr/ (?: bme [0-9\.]+ ) /xx;
363 10053         19731 my $CBP = qr/ (?: cbp [0-9\.]+ ) /xx;
364 10053         19718 my $ETH = qr/ (?: [gx] e- [0-9\/\.]+ ) /xx;
365 10053         19457 my $IRB = qr/ (?: irb [0-9\/\.]* ) /xx;
366 10053         19945 my $JSRV = qr/ (?: jsrv [0-9\.]* ) /xx;
367 10053         18862 my $LO = qr/ (?: lo [0-9\.]+ ) /xx;
368 10053         18798 my $ME = qr/ (?: me [0-9\.]+ ) /xx;
369 10053         18526 my $PFE = qr/ (?: pf [eh] - [0-9\/\.]+ ) /xx;
370 10053         18998 my $PIP = qr/ (?: pip [0-9\/\.]+ ) /xx;
371 10053         18554 my $VCP = qr/ (?: vcp- [0-9\/\.]+ ) /xx;
372 10053         18530 my $VLAN = qr/ (?: vlan\. [0-9]+ ) /xx;
373 10053         19132 my $OTHER = qr/
374             (:? fti|fxp|gr|ip|lsq|lt|mt|sp|pp|ppd|ppe|st ) (:?-)? [0-9\/\.]+
375             | gr-\S+
376             | dsc | esi | gre | ipip | jsrv | lsi
377             | mtun | pimd | pime | rbeb | tap | vlan | vme | vtep
378             /xx;
379              
380 10053         59442 my $IFACES = qr/$AE|$BME|$CBP|$ETH|$IRB|$LO|$ME|$JSRV|$PFE|$PIP|$VCP|$VLAN|$OTHER/xx;
381              
382 10053         32925 $line =~ s/^ ( (?: $IFACES) \s+ up \s+ up \N* ) $/$self->_colorize($1, $GREEN)/exx;
  116         318  
383 10053         25816 $line =~ s/^ ( $ETH \s+ VCP ) $/$self->_colorize($1, $GREEN)/exx;
  0         0  
384 10053         26633 $line =~ s/^ ( (?: $IFACES) \s+ up \s+ down \N* ) $/$self->_colorize($1, $RED)/exx;
  64         168  
385 10053         25083 $line =~ s/^ ( (?: $IFACES) \s+ down \s+ \N* ) $/$self->_colorize($1, $ORANGE)/exx;
  1         5  
386              
387             # Errors
388 10053         14651 $line =~ s/^ ( \Q Bit errors \E \s+ 0 ) $/$self->_colorize($1, $GREEN)/exx;
  1         12  
389 10053         14203 $line =~ s/^ ( \Q Bit errors \E \s+ 0 ) $/$self->_colorize($1, $GREEN)/exx;
  0         0  
390 10053         13832 $line =~ s/^ ( \Q Errored blocks \E \s+ [1-9][0-9]+ ) $/$self->_colorize($1, $RED)/exx;
  0         0  
391 10053         14038 $line =~ s/^ ( \Q Errored blocks \E \s+ 0 ) $/$self->_colorize($1, $GREEN)/exx;
  1         7  
392 10053         13839 $line =~
393 4         11 s/^ ( \Q FEC \E \S+ \s Errors (?: \s Rate)? \s+ 0 ) $/$self->_colorize($1, $GREEN)/exx;
394 10053         13789 $line =~
395 0         0 s/^ ( \Q FEC \E \S+ \s Errors (?: \s Rate)? \s+ \N+ ) $/$self->_colorize($1, $RED)/exx;
396              
397             # show interfaces diagnostics optics
398 10053         28202 $line =~ s/^ ( \Q Laser output power \E \s+ : \s $NUM \N+ ) $/$self->_colorize($1, $RED)/exx;
  0         0  
399 10053         32494 $line =~
400 0         0 s/^ ( \Q Laser output power \E \s+ : \s+ $NUM \Q mW \/ \E $LOWLIGHT \s dBm ) $/$self->_colorize($1, $RED)/exx;
401 10053         32018 $line =~
402 2         7 s/^ ( \Q Laser output power \E \s+ : \s+ $NUM \Q mW \/ \E $LIGHT \s dBm ) $/$self->_colorize($1, $INFO)/exx;
403 10053         30053 $line =~
404 1         5 s/^ ( \Q Laser receiver power \E \s+ : \s+ $NUM \Q mW \/ \E $LOWLIGHT \s dBm ) $/$self->_colorize($1, $RED)/exx;
405 10053         29940 $line =~
406 1         5 s/^ ( \Q Laser receiver power \E \s+ : \s+ $NUM \Q mW \/ \E $LIGHT \s dBm ) $/$self->_colorize($1, $INFO)/exx;
407 10053         31873 $line =~
408 1         16 s/^ ( \Q Receiver signal average optical power \E \s+ : \s+ $NUM \Q mW \/ \E $LOWLIGHT \s dBm ) $/$self->_colorize($1, $RED)/exx;
409 10053         32395 $line =~
410 1         4 s/^ ( \Q Receiver signal average optical power \E \s+ : \s+ $NUM \Q mW \/ \E $LIGHT \s dBm ) $/$self->_colorize($1, $INFO)/exx;
411              
412 10053         62000 return $line;
413             }
414              
415 10053     10053   14090 sub _parse_line_vyos ( $self, $line ) {
  10053         14128  
  10053         16057  
  10053         13312  
416              
417             #
418             # VyOS (Stuff the Arista/Cisco commands did not do)
419             #
420              
421             # BGP
422 10053         15350 $line =~ s/^ ( \Q BGP state = \E (?!Established) \N* ) $/$self->_colorize($1, $RED)/exx;
  0         0  
423 10053         14355 $line =~
424 1         6 s/^ ( \Q BGP state = Established\E \N* ) $/$self->_colorize($1, $GREEN)/exx;
425              
426 10053         14578 $line =~
427 2         7 s/^ ( \Q Route map for \E (?: incoming|outgoing ) \Q advertisements is \E \N* ) $/$self->_colorize($1, $INFO)/exx;
428 10053         15118 $line =~ s/^ ( \Q \E \S+ \Q peer-group member\E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  1         5  
429              
430 10053         31112 $line =~ s/^ ( \Q \E $INT \Q accepted prefixes\E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  1         4  
431              
432 10053         15312 $line =~ s/^ ( \QLocal host: \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  1         5  
433 10053         14104 $line =~ s/^ ( \QForeign host: \E \N+ ) $/$self->_colorize($1, $INFO)/exx;
  1         4  
434              
435 10053         19843 return $line;
436             }
437              
438 10053     10053   14272 sub _parse_line_ciena ( $self, $line ) {
  10053         14396  
  10053         14550  
  10053         13627  
439              
440             #
441             # Ciena
442             #
443              
444             # Admin/Operational state for multiple commands
445 10053         15325 $line =~
446 8         29 s/^ ( \| \s? \QAdmin State \E \s+ \| ) ( \s? \QEnabled \E ) ( \N+ ) $/$1.$self->_colorize($2, $GREEN).$3/exx;
447 10053         14185 $line =~
448 1         5 s/^ ( \| \s? \QAdmin State \E \s+ \| ) ( \s? \QDisabled \E ) ( \N+ ) $/$1.$self->_colorize($2, $ORANGE).$3/exx;
449 10053         13837 $line =~
450 10         35 s/^ ( \| \s? \QAdmin State \E \s+ \| ) ( [^|]+ ) ( \N+ ) $/$1.$self->_colorize($2, $RED).$3/exx;
451              
452 10053         14262 $line =~
453 7         30 s/^ ( \| \s? \QOperational State \E \s+ \| ) ( \s? \QUp \E ) ( \N+ ) $/$1.$self->_colorize($2, $GREEN).$3/exx;
454 10053         13959 $line =~
455 1         5 s/^ ( \| \s? \QOperational State \E \s+ \| ) ( \s? \QInitializing \E ) ( \N+ ) $/$1.$self->_colorize($2, $ORANGE).$3/exx;
456 10053         13707 $line =~
457 10         31 s/^ ( \| \s? \QOperational State \E \s+ \| ) ( [^|]+ ) ( \N+ ) $/$1.$self->_colorize($2, $RED).$3/exx;
458              
459             # xcvr show xcvr N/N
460 10053         33537 $line =~ s/ ^ ( \| ) ( \Q Tx Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ ) $/
461 1         8 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5/exx;
462 10053         29946 $line =~ s/ ^ ( \| ) ( \Q Tx Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ ) $/
463 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5/exx;
464              
465 10053         28328 $line =~ s/ ^ ( \| ) ( \Q Rx Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ ) $/
466 1         9 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5/exx;
467 10053         27967 $line =~ s/ ^ ( \| ) ( \Q Rx Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ ) $/
468 1         7 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5/exx;
469              
470             # xcvr show xcvr status
471 10053         29488 $line =~
472             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Tx Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ ) $/
473 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5/exx;
474 10053         29405 $line =~
475             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Tx Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ ) $/
476 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5/exx;
477 10053         28031 $line =~
478             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Rx Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ ) $/
479 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5/exx;
480 10053         28768 $line =~
481             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Rx Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ ) $/
482 1         5 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5/exx;
483              
484             # ptp show ptp x/x [status]
485 10053         16267 $line =~
486             s/^ ( \| (?: \s Transmitter)? \Q State \E \s+ \| ) ( \Q Enabled \E \s+ ) ( \| ) ( \Q Up \E|\Q Enabled \E )( \N+ ) $/
487 6         20 $1.$self->_colorize($2, $GREEN).$3.$self->_colorize($4, $GREEN).$5/exx;
488 10053         14396 $line =~
489             s/^ ( \| (?: \s Transmitter)? \Q State \E \s+ \| ) ( \Q Enabled \E \s+ ) ( \| ) ( [^|]+ )( \N+ ) $/
490 3         12 $1.$self->_colorize($2, $GREEN).$3.$self->_colorize($4, $RED).$5/exx;
491 10053         14539 $line =~
492             s/^ ( \| (?: \s Transmitter)? \Q State \E \s+ \| ) ( \Q Disabled \E \s+ ) ( \| ) ( [^|]+ )( \N+ ) $/
493 2         10 $1.$self->_colorize($2, $ORANGE).$3.$self->_colorize($4, $ORANGE).$5/exx;
494              
495 10053         33361 $line =~
496             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ )$/
497 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5.$self->_colorize($6, $RED).$7/exx;
498 10053         32884 $line =~
499             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ )$/
500 1         5 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5.$self->_colorize($6, $INFO).$7/exx;
501 10053         31915 $line =~
502             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ )$/
503 1         6 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5.$self->_colorize($6, $RED).$7/exx;
504 10053         32594 $line =~
505             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ )$/
506 4         15 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5.$self->_colorize($6, $INFO).$7/exx;
507              
508 10053         32924 $line =~
509             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Aggregate Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ )$/
510 0         0 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5.$self->_colorize($6, $RED).$7/exx;
511 10053         31879 $line =~
512             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Aggregate Power (dBm)\E \s* ) ( \| ) ( \s+ $VERYLL \s+ ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ )$/
513 0         0 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $RED).$5.$self->_colorize($6, $INFO).$7/exx;
514 10053         30944 $line =~
515             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Aggregate Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \| ) ( \s+ $VERYLL \s+ ) ( \N+ )$/
516 0         0 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5.$self->_colorize($6, $RED).$7/exx;
517 10053         31517 $line =~
518             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Actual Aggregate Power (dBm)\E \s* ) ( \| ) ( \s+ $LIGHT \s+ ) ( \| ) ( \s+ $LIGHT \s+ ) ( \N+ )$/
519 1         10 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5.$self->_colorize($6, $INFO).$7/exx;
520              
521 10053         32468 $line =~
522             s/ ^ ( \| \s+ [0-9]* \s* \| ) ( \Q Span Loss (dB)\E \s* ) ( \| ) ( \s+ $NUM \s+ ) ( \| ) ( \s+ $NUM \s+ ) ( \| )$/
523 1         8 $1.$self->_colorize($2, $INFO).$3.$self->_colorize($4, $INFO).$5.$self->_colorize($6, $INFO).$7/exx;
524              
525 10053         29953 $line =~
526             s/^ ( \| \s+ \| ) ( \Q Optical Return Loss \E \( \QdB\E \) ) ( \s+ \| \s+ ) ( $GOODRETURNLOSS ) (\s+ \| ) $/
527 1         5 $1.$self->_colorize($2, $GREEN).$3.$self->_colorize($4, $GREEN).$5/exx;
528 10053         29424 $line =~
529             s/^ ( \| \s+ \| ) ( \Q Optical Return Loss \E \( \QdB\E \) ) ( \s+ \| \s+ ) ( $WARNRETURNLOSS ) (\s+ \| ) $/
530 1         5 $1.$self->_colorize($2, $ORANGE).$3.$self->_colorize($4, $ORANGE).$5/exx;
531 10053         28810 $line =~
532             s/^ ( \| \s+ \| ) ( \Q Optical Return Loss \E \( \QdB\E \) ) ( \s+ \| \s+ ) ( $BADRETURNLOSS ) (\s+ \| ) $/
533 1         7 $1.$self->_colorize($2, $RED).$3.$self->_colorize($4, $RED).$5/exx;
534              
535             # alarm show
536 10053         32191 $line =~ s/ ^ ( \| ) ( \s* [0-9]* ) ( \| ) ( \s+ ) ( \| ) ( [^|]+ ) ( \| ) ( \s+ [0-9]+ )
537             ( \| ) ( \s* $BIGALARMS|$LITTLEALARMS \s* ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
538             ( \| ) ( \s+ $BIGOVERRIDES \s+ ) ( \| ) $/
539 3         11 $1.$self->_colorize($2, $ORANGE).
540             $3.$self->_colorize($4, $ORANGE).
541             $5.$self->_colorize($6, $ORANGE).
542             $7.$self->_colorize($8, $ORANGE).
543             $9.$self->_colorize($10, $ORANGE).
544             $11.$self->_colorize($12, $ORANGE).
545             $13.$self->_colorize($14, $ORANGE).
546             $15.$self->_colorize($16, $ORANGE).
547             $17/exx;
548 10053         27793 $line =~ s/ ^ ( \| ) ( \s* [0-9]* ) ( \| ) ( \s+ ) ( \| ) ( [^|]+ ) ( \| ) ( \s+ [0-9]+ )
549             ( \| ) ( \s* $BIGALARMS|$LITTLEALARMS \s* ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) $/
550 1         5 $1.$self->_colorize($2, $RED).
551             $3.$self->_colorize($4, $RED).
552             $5.$self->_colorize($6, $RED).
553             $7.$self->_colorize($8, $RED).
554             $9.$self->_colorize($10, $RED).
555             $11.$self->_colorize($12, $RED).
556             $13.$self->_colorize($14, $RED).
557             $15.$self->_colorize($16, $RED).
558             $17/exx;
559 10053         27733 $line =~
560             s/ ^ ( \| ) ( \s+ [0-9]* ) ( \| ) ( \s+ \QY\E \s* ) ( \| ) ( [^|]+ ) ( \| ) ( \s+ [0-9]+ )
561             ( \| ) ( \s* $BIGALARMS \s* ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) $/
562 8         31 $1.$self->_colorize($2, $ORANGE).
563             $3.$self->_colorize($4, $ORANGE).
564             $5.$self->_colorize($6, $ORANGE).
565             $7.$self->_colorize($8, $ORANGE).
566             $9.$self->_colorize($10, $ORANGE).
567             $11.$self->_colorize($12, $ORANGE).
568             $13.$self->_colorize($14, $ORANGE).
569             $15.$self->_colorize($16, $ORANGE).
570             $17/exx;
571 10053         27080 $line =~
572             s/ ^ ( \| ) ( \s+ [0-9]* ) ( \| ) ( \s+ \QY\E \s* ) ( \| ) ( [^|]+ ) ( \| ) ( \s+ [0-9]+ )
573             ( \| ) ( \s* $LITTLEALARMS \s* ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) $/
574 1         5 $1.$self->_colorize($2, $INFO).
575             $3.$self->_colorize($4, $INFO).
576             $5.$self->_colorize($6, $INFO).
577             $7.$self->_colorize($8, $INFO).
578             $9.$self->_colorize($10, $INFO).
579             $11.$self->_colorize($12, $INFO).
580             $13.$self->_colorize($14, $INFO).
581             $15.$self->_colorize($16, $INFO).
582             $17/exx;
583              
584             # Errors
585 10053         15786 $line =~ s/ ^ ( \QSHELL \E \S+ \Q FAILURE\E \N+ ) $/$self->_colorize($1, $RED)/exx;
  2         8  
586              
587             # ptp show
588 10053         14689 $line =~
589             s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( \Q Ena \E ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
590             ( \| ) ( [^|]+ ) ( \| ) ( \QUp\E \s+ ) ( \| ) ( [^|]+ )
591             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) /
592 15         45 $1.$self->_colorize($2, $GREEN).
593             $3.$self->_colorize($4, $GREEN).
594             $5.$self->_colorize($6, $GREEN).
595             $7.$self->_colorize($8, $GREEN).
596             $9.$self->_colorize($10, $GREEN).
597             $11.$self->_colorize($12, $GREEN).
598             $13.$self->_colorize($14, $GREEN).
599             $15.$self->_colorize($16, $GREEN).
600             $17.$self->_colorize($18, $GREEN).
601             $19.$self->_colorize($20, $GREEN).
602             $21.$self->_colorize($22, $GREEN).
603             $23/exx;
604 10053         14189 $line =~
605             s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( \Q Ena \E ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
606             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
607             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) /
608 8         24 $1.$self->_colorize($2, $RED).
609             $3.$self->_colorize($4, $RED).
610             $5.$self->_colorize($6, $RED).
611             $7.$self->_colorize($8, $RED).
612             $9.$self->_colorize($10, $RED).
613             $11.$self->_colorize($12, $RED).
614             $13.$self->_colorize($14, $RED).
615             $15.$self->_colorize($16, $RED).
616             $17.$self->_colorize($18, $RED).
617             $19.$self->_colorize($20, $RED).
618             $21.$self->_colorize($22, $RED).
619             $23/exx;
620 10053         14555 $line =~
621             s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( \Q Dis \E ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
622             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ )
623             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) /
624 0         0 $1.$self->_colorize($2, $ORANGE).
625             $3.$self->_colorize($4, $ORANGE).
626             $5.$self->_colorize($6, $ORANGE).
627             $7.$self->_colorize($8, $ORANGE).
628             $9.$self->_colorize($10, $ORANGE).
629             $11.$self->_colorize($12, $ORANGE).
630             $13.$self->_colorize($14, $ORANGE).
631             $15.$self->_colorize($16, $ORANGE).
632             $17.$self->_colorize($18, $ORANGE).
633             $19.$self->_colorize($20, $ORANGE).
634             $21.$self->_colorize($22, $ORANGE).
635             $23/exx;
636              
637             # module show
638 10053         19316 $line =~ s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( \Q Enabled \E \s+ )
639             ( \| ) ( [^|]+ ) ( \| ) ( \Q Up \E \s+ ) ( \| ) ( [^|]+ ) ( \| ) $ /
640 1         6 $1.$self->_colorize($2, $GREEN).
641             $3.$self->_colorize($4, $GREEN).
642             $5.$self->_colorize($6, $GREEN).
643             $7.$self->_colorize($8, $GREEN).
644             $9.$self->_colorize($10, $GREEN).
645             $11.$self->_colorize($12, $GREEN).
646             $13/exx;
647 10053         14752 $line =~ s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( \Q Enabled \E \s+ )
648             ( \| ) ( [^|]+ ) ( \| ) ( \Q Initializing \E \s+ ) ( \| ) ( [^|]+ ) ( \| ) $ /
649 1         6 $1.$self->_colorize($2, $ORANGE).
650             $3.$self->_colorize($4, $ORANGE).
651             $5.$self->_colorize($6, $ORANGE).
652             $7.$self->_colorize($8, $ORANGE).
653             $9.$self->_colorize($10, $ORANGE).
654             $11.$self->_colorize($12, $ORANGE).
655             $13/exx;
656 10053         15131 $line =~ s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( \Q Enabled \E \s+ )
657             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) $ /
658 1         6 $1.$self->_colorize($2, $RED).
659             $3.$self->_colorize($4, $RED).
660             $5.$self->_colorize($6, $RED).
661             $7.$self->_colorize($8, $RED).
662             $9.$self->_colorize($10, $RED).
663             $11.$self->_colorize($12, $RED).
664             $13/exx;
665 10053         14504 $line =~ s/ ^ ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( \Q Disabled \E \s+ )
666             ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) ( [^|]+ ) ( \| ) $ /
667 0         0 $1.$self->_colorize($2, $ORANGE).
668             $3.$self->_colorize($4, $ORANGE).
669             $5.$self->_colorize($6, $ORANGE).
670             $7.$self->_colorize($8, $ORANGE).
671             $9.$self->_colorize($10, $ORANGE).
672             $11.$self->_colorize($12, $ORANGE).
673             $13/exx;
674              
675             # Success for dumps
676 10053         14630 $line =~ s/^ ( \QSuccess! Preparing state dump...\E \s* ) $/ $self->_colorize($1, $GREEN)/exx;
  1         5  
677              
678             # Logout message
679 10053         13824 $line =~ s/^ ( \QTerminal will be disconnected in 1 minute if it remains inactive.\E )/
680 1         7 $self->_colorize($1, $RED)/exx;
681              
682             # Warning message
683 10053         14011 $line =~ s/^ (\QWARNING:\E) / $self->_colorize($1, $ORANGE)/exx;
  1         5  
684 10053         14274 $line =~ s/^ (\Q You cannot abort the restart operation once it has started.\E ) $/
685 1         7 $self->_colorize($1, $ORANGE)/exx;
686              
687             # Error messages when something isn't disabled first
688 10053         14444 $line =~ s/^ (\QERROR: \E .* disabled ) $/ $self->_colorize($1, $RED)/exx;
  1         6  
689              
690              
691 10053         41272 return $line;
692             }
693              
694 73     73   115 sub _ipv4ify ( $self, $ip ) {
  73         109  
  73         163  
  73         101  
695 73         273 my ( $subnet, $len ) = split "/", $ip;
696 73   100     338 $len //= 32;
697              
698 73         206 my (@oct) = split /\./, $subnet;
699 73         128 my $val = 0;
700 73         208 foreach my $i (@oct) {
701 292         392 $val *= 256;
702 292         540 $val += $i;
703             }
704 73         147 $val = $val * 256 + $len;
705 73         274 my $color = $BGCOLORS[ $val % scalar(@BGCOLORS) ];
706 73         192 return $self->_colorize( $ip, $color );
707             }
708              
709 17     17   32 sub _ipv6ify ( $self, $ip ) {
  17         26  
  17         42  
  17         33  
710 17         61 my ( $subnet, $len ) = split "/", $ip;
711 17   100     81 $len //= 128;
712              
713 17         50 my ( $first, $second ) = split "::", $subnet;
714              
715 17         47 my (@fparts) = split /:/, $first;
716 17         68 push( @fparts, ( '', '', '', '', '', '', '', '' ) );
717 17         86 @fparts = @fparts[ 0 .. 7 ];
718              
719 17         28 my (@sparts);
720 17 100       45 if ( defined($second) ) {
721 15         45 (@sparts) = reverse split /:/, $second;
722             }
723 17         66 push( @sparts, ( '', '', '', '', '', '', '', '' ) );
724 17         64 @sparts = reverse @sparts[ 0 .. 7 ];
725              
726 17         31 my $val = 0;
727 17         69 for my $i ( 0 .. 7 ) {
728 136         181 $val *= 16;
729 136         278 $val += hex( $fparts[$i] . $sparts[$i] );
730             }
731 17         37 $val *= 32;
732 17         36 $val += $len;
733              
734 17         65 my $color = $BGCOLORS[ $val % scalar(@BGCOLORS) ];
735 17         51 return $self->_colorize( $ip, $color );
736             }
737              
738 8150     8150   11134 sub _numerify ( $self, $num ) {
  8150         11605  
  8150         15261  
  8150         10699  
739 8150         11244 my $output = "";
740 8150         17949 while ( length($num) > 3 ) {
741 1096         2431 $output = substr( $num, -3 ) . $output;
742 1096         2262 $num = substr( $num, 0, length($num) - 3 );
743              
744 1096         1535 my $next3;
745 1096 100       2238 if ( length($num) > 3 ) {
746 418         734 $next3 = substr( $num, -3 );
747 418         716 $num = substr( $num, 0, length($num) - 3 );
748             } else {
749 678         984 $next3 = $num;
750 678         1013 $num = '';
751             }
752 1096         2046 $output = $self->_highlight($next3) . $output;
753             }
754 8150         14435 $output = $num . $output;
755              
756 8150         31822 return $output;
757             }
758              
759 1096     1096   1526 sub _highlight ( $self, $str ) {
  1096         1446  
  1096         1515  
  1096         1480  
760 1096         3921 return "\e[4m$str\e[24m";
761             }
762              
763 2330     2330   3295 sub _colorize ( $self, $text, $color ) {
  2330         3498  
  2330         4844  
  2330         3500  
  2330         3022  
764 2330         5251 $text = $color . $text;
765 2330         7874 $text =~ s/ \Q$RESET\E / $color /;
766 2330         4116 $text = $text . $RESET;
767 2330         7652 return $text;
768             }
769              
770             __END__
771              
772             =pod
773              
774             =encoding UTF-8
775              
776             =head1 NAME
777              
778             App::RouterColorizer - Colorize router CLI output
779              
780             =head1 VERSION
781              
782             version 1.231650
783              
784             =head1 DESCRIPTION
785              
786             This module colorizes the output of router output, using.
787              
788             The output will be colorized based on detection of key strings as they
789             might be sent from Arista, Cisco, Juniper, and VyOS routers/switches and
790             Ciena WDM devices. It may also work on other router outputs, but these
791             have not been used for development.
792              
793             =head1 METHODS
794              
795             =head2 new
796              
797             my $colorizer = App::RouterColorizer->new()
798              
799             Instnatiates a new instance of C<App::RouterColorizer>.
800              
801             =head2 format_text
802              
803             $colorized_text = $colorizer->format_text($text)
804              
805             This method colorizes/formats the text, as provided in C<$text>.
806              
807             /usr/bin/ssh router.example.com | router-colorizer.pl
808              
809             =head1 COLOR CODING
810              
811             Color coding is used, which assumes a black background on your terminal.
812             The colors used indicate different kinds of output. Note that most lines
813             of output are not colorized, only "important" (as defined by me!) lines
814             are colorized.
815              
816             =over 4
817              
818             =item C<green>
819              
820             Green text is used to signify "good" values. For instance, in the output
821             from C<show interfaces> on an Arista router, seeing lines indicating the
822             circuit is "up" and not showing errors will show in green.
823              
824             =item C<orange>
825              
826             Orange text is used to show things that aren't "good" but also aren't "bad."
827             For instance, administratively down interfaces in C<show interfaces status>
828             will typically show as orange.
829              
830             =item C<red>
831              
832             Red text indicates error conditions, such as errors being seen on the
833             output of C<show interfaces>.
834              
835             =item C<cyan>
836              
837             Cyan text indicates potentially important text, seperated out from text
838             that is not-so-important. For instance, in C<show bgp neighbors>, cyan
839             is used to point out lines indicating which route map is being used.
840              
841             =back
842              
843             =head1 IP Address Colorization
844              
845             IP addresses are also colorized. These are colorized one of several colors,
846             all with a colorized background, based on the IP/CIDR address. Thus, an
847             IP address like C<1.2.3.4> will always be the same color, which should make
848             it easier to spot potential transposition or copy mistakes (if it shows up
849             sometimes as white-on-blue, but other times as black-on-red, it's not the
850             same address!).
851              
852             =head1 Number Grouping/Underlines
853              
854             The progarm also underlines alternating groups of 3 digits as they appear
855             in digit strings. This is used to assist people who might have dyslexia
856             or other visual processing differences, to allow them to quickly determine
857             if 1000000 is 1,000,000 or 10,000,000.
858              
859             =head1 Methods
860              
861             =head1 BUGS
862              
863             None known, however it is certainly possible that I am less than perfect. If
864             you find any bug you believe has security implications, I would greatly
865             appreciate being notified via email sent to C<jmaslak@antelope.net> prior
866             to public disclosure. In the event of such notification, I will attempt to
867             work with you to develop a plan for fixing the bug.
868              
869             All other bugs can be reported via email to C<jmaslak@antelope.net> or by
870             using the GitHub issue tracker
871             at L<https://github.com/jmaslak/App-RouterColorizer/issues>
872              
873             =head1 AUTHOR
874              
875             Joelle Maslak <jmaslak@antelope.net>
876              
877             =head1 COPYRIGHT AND LICENSE
878              
879             This software is copyright (c) 2021-2023 by Joelle Maslak.
880              
881             This is free software; you can redistribute it and/or modify it under
882             the same terms as the Perl 5 programming language system itself.
883              
884             =cut