http://www.perlmonks.org?node_id=1004070

cspctec has asked for the wisdom of the Perl Monks concerning the following question:

UPDATE: Problem solved! Thanks everyone for all of the help!

Hi, I have the following data:

---------- <DATA> ------------ Oct 17 10:35:39 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:39) Oct 17 10:35:40 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:40) Oct 17 10:35:41 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:41) Oct 17 10:35:42 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:42) Oct 17 10:35:43 esw001tff2 [Root]Server reset. Occurred 1 time. (2012 +17 10:35:43) Oct 17 10:35:44 esw001tff2 [Root]Server reset. Occurred 1 time. (2012 +17 10:35:44) Oct 17 10:35:45 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:45) Oct 17 10:35:46 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:46) Oct 17 10:35:47 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:47) Oct 17 10:35:48 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:48) Oct 17 10:35:49 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:49) Oct 17 10:35:50 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:50)

I'll try to explain what I'm trying to do the best I can. I'm trying to get an output that looks like the following:

DEVICE --> esw001tff2 DATE --> Oct 17 TIME --> 10:35:39 ERROR --> IP Spoofing from 255.255.255.255 to 255.255.255.255! Occurr +ed 1 time. The above error occurred 7 times

The code I'm using looks like the following:

my %error_count; my (@data = <DATA>, @list, @splitter); foreach (@data) { $error_count{$1}++ if m/\](.*)\(20/, @data; @splitter = split (/\s/, @data); push (@list, @splitter); } for (keys %error_count) { print "DEVICE\t--> $list[3]\n"; print "DATE\t--> $list[0] $list[1]\n"; print "TIME\t--> $list[2]\n"; print "ERROR\t--> "$_\n"; print "\nThe above error occurred $error_count{$_} times\n"; }

The problem is, I can't get the array to update with the hash output. In the output, it gives me the correct count of the errors, but it just takes the first device, time and date and sticks them in the output. I need the device, date and time to be correct with the count.

For the time, I just need the first time that the error occurred, like on this one the time for the IP Spoofing would be 10:35:39, and root login failure would be 10:35:47

This code is the code I remember from work. I don't have the actual code with me, but I wrote it all so it should be accurate

Thank you if you can help

Replies are listed 'Best First'.
Re: Counting keys in a hash
by choroba (Cardinal) on Nov 15, 2012 at 22:45 UTC
    Your code does not even compile. Moreover, the logic with @list is wrong: you should keep all the information in the hash, not just the count. Like this:
    #!/usr/bin/perl use warnings; use strict; my %error_count; while (<DATA>) { if (my ($error) = m/\](.*)\(20/) { $error_count{$error}{count}++; $error_count{$1}{list} //= [split /\s+/]; # Only remembers th +e first time. } } for (keys %error_count) { my @list = @{ $error_count{$_}{list} }; print "DEVICE\t--> $list[3]\n"; print "DATE\t--> $list[0] $list[1]\n"; print "TIME\t--> $list[2]\n"; print "ERROR\t--> $_\n"; print "\nThe above error occurred $error_count{$_}{count} times\n" +; } __DATA__ Oct 17 10:35:39 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:39) Oct 17 10:35:40 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:40) Oct 17 10:35:41 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:41) Oct 17 10:35:42 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:42) Oct 17 10:35:43 esw001tff2 [Root]Server reset. Occurred 1 time. (2012 +17 10:35:43) Oct 17 10:35:44 esw001tff2 [Root]Server reset. Occurred 1 time. (2012 +17 10:35:44) Oct 17 10:35:45 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:45) Oct 17 10:35:46 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:46) Oct 17 10:35:47 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:47) Oct 17 10:35:48 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:48) Oct 17 10:35:49 esw001tff2 [Root]Root login failure! Occurred 1 time. +(2012 17 10:35:49) Oct 17 10:35:50 esw001tff2 [Root]IP Spoofing from 255.255.255.255 to 2 +55.255.255.255! Occurred 1 time. (2012 17 10:35:50)
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Counting keys in a hash
by NetWallah (Canon) on Nov 16, 2012 at 06:01 UTC
    This is probably closer to what you are looking for.
    It can handle multiple devices, and multiple occurrences of different errors for each device.
    #!/usr/bin/perl use warnings; use strict; my %devinfo; while (<DATA>) { next unless my ($date,$time, $device, $err) = /(\w+ \d+) ([\d:]+)\s( +\S+) \[[^\]]+\]([^\(]+)\s?\(\d+/; $devinfo{$device}{$err}{COUNT}++; $devinfo{$device}{$err}{FIRST_TIME} ||= [$date, $time]; } for my $dev (sort keys %devinfo) { print "DEVICE\t--> $dev ==============\n"; for my $err (keys %{ $devinfo{$dev} }) { my $errinfo = $devinfo{$dev}{$err}; print "DATE\t--> $errinfo->{FIRST_TIME}[0]\n"; print "TIME\t--> $errinfo->{FIRST_TIME}[1]\n"; print "ERROR\t--> $err\n"; print "\nThe above error occurred $errinfo->{COUNT} times\n\n"; } } __DATA__ <put data here>
    Output, with your data:
    DEVICE --> esw001tff2 ============== DATE --> Oct 17 TIME --> 10:35:43 ERROR --> Server reset. Occurred 1 time. The above error occurred 2 times DATE --> Oct 17 TIME --> 10:35:39 ERROR --> IP Spoofing from 255.255.255.255 to 255.255.255.255! Occu +rred 1 time. The above error occurred 7 times DATE --> Oct 17 TIME --> 10:35:47 ERROR --> Root login failure! Occurred 1 time. The above error occurred 3 times

                 "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

      Thank you NetWallah, that is what I was looking for

      I have put your code in but I'm not getting a match with the regular expression (it's saying uninitialized value in pattern match m//)... it's probably because the data I had for you to look at is not exact. I am at work right now, so let me post the exact data below...

      ----DATA---- Oct 17 10:35:35 esw110tf222 ssg5-serial: NetScreen device id=000123456 +78 [Root]system-alert-000008: IP Spoofing! From 255.255.255.255 to 0. +0.0.0, proto 1 (zone Untrust int ethernet0/4). Occurred 1 times. (201 +2-1017 10:35:35) Oct 17 10:35:35 esw110tf222 ssg5-serial: NetScreen device id=000123456 +78 [Root]system-alert-000008: IP Spoofing! From 255.255.255.255 to 0. +0.0.0, proto 1 (zone Untrust int ethernet0/4). Occurred 1 times. (201 +2-1017 10:35:35)

      I tried my own regex:

      m/\](.*)\(20/;
      But it still throws the same error...

      I think this is really close now... can you help fix it for that data?

        Change the line to :
        next unless my ($date,$time, $device, $err) = /(\w+ \d+) ([\d:]+)\s +(\S+).+\[[^\]]+\]([^\(]+)/;
        This is a LOT more forgiving than the original, and allows your new data to pass through, producing:
        DEVICE --> esw110tf222 ============== DATE --> Oct 17 TIME --> 10:35:35 ERROR --> system-alert-000008:IP Spoofing! From 255.255.255.255 to 0 +.0.0.0, proto 1 The above error occurred 2 times

                     "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius