filter log/ filenames into sw.command
[dell-switch] / syslog-count-link.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 # count Dell and Microtik syslog for port and stp events
6
7 ## report all logs:
8 # sudo cat /var/log/switch/sw-[a-z][0-9]*.log | ./syslog-count-link.pl | less -S
9 #
10 ## tail logs and report status on kill -HUP
11 # sudo tail -f /var/log/switch/sw-[a-z][0-9]*.log | ./syslog-count-link.pl &
12
13 use Data::Dump qw(dump);
14 use POSIX qw(strftime);
15
16 my $timeout = $ENV{TIMEOUT} || 60; # forget switch after sec
17 # timeout should be smaller than stp refresh inverval or
18 # stp messages will accumulate forever
19
20 my $name = $0;
21 $name =~ s/.*\/([^\/]+)$/$1/;
22 $name =~ s/\.pl$//;
23 my $dir = "/dev/shm/$name";
24 mkdir $dir unless -e $dir;
25
26 our $stat;
27
28 sub print_stats {
29         open(my $fh, '>', "$dir/stats");
30
31         foreach my $host ( sort keys %$stat ) {
32                 foreach my $port ( sort {
33                         my $a1 = $a; $a1 =~ s/\D+//g;
34                         my $b1 = $b; $b1 =~ s/\D+//g;
35                         no warnings;
36                         $a1 <=> $b1;
37                 } keys %{ $stat->{$host} } ) {
38                         next if $port =~ m/^_/;
39                         my $dt = time() - $stat->{$host}->{$port}->[0];
40                         if ( $dt > $timeout ) {
41                                 delete $stat->{$host}->{$port};
42                                 next;
43                         }
44                         my $out = sprintf "%-12s %-8s %-2d %s\n", $host, $port, $dt, $stat->{$host}->{$port}->[1];
45                         print $out;
46                         print $fh $out;
47                 }
48         }
49
50         close($fh);
51 }
52
53 sub reset_stats {
54         if ( -e "$dir/reset" && unlink "$dir/reset" ) {
55                 $stat = {};
56                 warn "# reset stats\n";
57         }
58 }
59
60
61 $SIG{HUP} = sub {
62         print_stats();
63         reset_stats;
64 };
65
66 warn "kill -HUP $$  # to dump stats\n";
67 {
68         open(my $fh, '>', "$dir/pid");
69         print $fh $$;
70         close($fh);
71 }
72
73 sub stat_host_port {
74         my ( $host, $port, $state ) = @_;
75         if ( ! exists $stat->{$host}->{$port} ) {
76                 $stat->{$host}->{$port} = [-1, $state];
77         } else {
78                 $stat->{$host}->{$port}->[1] .= $state;
79         }
80         $stat->{$host}->{$port}->[0] = time();
81         #warn "# stat_host_port ",dump($stat);
82 }
83
84
85 my $host_re = '[\w-]+';
86 my $port_re = '[\w/]+';
87
88 while(<>) {
89         chomp;
90         s/[\r\n]+//;
91
92         reset_stats;
93
94         next if m/^$/;
95         next if m/%PIX-/; # ignore PIX logs
96
97         ## Dell old
98         if ( m/(\S+)\s%LINK-[IW]-(\w+):\s*(\w+)/ ) {
99                 my ($host,$state,$port) = ($1,$2,$3);
100                 stat_host_port( $host, $port, substr($state,0,1) );
101         } elsif ( m/(\S+)\s%STP-W-PORTSTATUS:\s([\w\/]+)(?: of instance \d+)?: STP status (\w+)/ ) {
102                 my ($host,$port,$state) = ($1,$2,substr($3,0,1) );
103                 stat_host_port( $host, $port, $state =~ m/f/i ? '-' : $state );
104
105
106         ## Dell new
107         } elsif ( m/LINK - (\w+) - Hostname: <($host_re)>, ($port_re)/ ) {
108                 my ($state, $host, $port ) = ($1,$2,$3);
109                 stat_host_port( $host, $port, substr($state,0,1) );
110         } elsif ( m/STP - PORTSTATUS - Hostname: <($host_re)>,($port_re): STP status (\w+)/ ) {
111                 my ($host,$port,$state) = ($1,$2,$3);
112                 stat_host_port( $host, $port, '-' );
113
114
115         ## Mikrotik
116         } elsif ( m/($host_re) \w+: ([\w\-]+) link (\w+)/ ) {
117                 my ($host, $port, $state ) = ($1,$2,$3);
118                 stat_host_port( $host, $port, substr($state,0,1) );
119
120
121         } elsif ( m/($host_re) TRAPMGR.* %% Spanning Tree Topology Change: (\d+)/ ) {
122                 my ( $host, $state ) = ( $1, $2 );
123                 stat_host_port( $host, 'STP', $2 );
124
125
126         } elsif ( m'==> /var/log/' ) {
127                 # ignore tail output
128                 next;
129         } else {
130                 warn "IGNORE: [$_]\n";
131                 next;
132         }
133
134         if ( -e "$dir/dump" || $ENV{DUMP} ) {
135                 print "### ",strftime("%Y-%m-%d %H:%M:%S",localtime(time)), "\n";
136                 print_stats;
137         }
138 }
139
140
141
142 warn "# stat = ", dump($stat);
143 print_stats;
144
145