| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Parse::Syslog; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 8 |  |  | 8 |  | 105163 | use Carp; | 
|  | 8 |  |  |  |  | 23 |  | 
|  | 8 |  |  |  |  | 782 |  | 
| 4 | 8 |  |  | 8 |  | 10912 | use Symbol; | 
|  | 8 |  |  |  |  | 9333 |  | 
|  | 8 |  |  |  |  | 1022 |  | 
| 5 | 8 |  |  | 8 |  | 10240 | use Time::Local; | 
|  | 8 |  |  |  |  | 24643 |  | 
|  | 8 |  |  |  |  | 566 |  | 
| 6 | 8 |  |  | 8 |  | 9076 | use IO::File; | 
|  | 8 |  |  |  |  | 91816 |  | 
|  | 8 |  |  |  |  | 1165 |  | 
| 7 | 8 |  |  | 8 |  | 75 | use strict; | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 292 |  | 
| 8 | 8 |  |  | 8 |  | 41 | use vars qw($VERSION); | 
|  | 8 |  |  |  |  | 12 |  | 
|  | 8 |  |  |  |  | 5664 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | $VERSION = '1.10'; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | my %months_map = ( | 
| 13 |  |  |  |  |  |  | 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, | 
| 14 |  |  |  |  |  |  | 'Apr' => 3, 'May' => 4, 'Jun' => 5, | 
| 15 |  |  |  |  |  |  | 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, | 
| 16 |  |  |  |  |  |  | 'Oct' => 9, 'Nov' =>10, 'Dec' =>11, | 
| 17 |  |  |  |  |  |  | 'jan' => 0, 'feb' => 1, 'mar' => 2, | 
| 18 |  |  |  |  |  |  | 'apr' => 3, 'may' => 4, 'jun' => 5, | 
| 19 |  |  |  |  |  |  | 'jul' => 6, 'aug' => 7, 'sep' => 8, | 
| 20 |  |  |  |  |  |  | 'oct' => 9, 'nov' =>10, 'dec' =>11, | 
| 21 |  |  |  |  |  |  | ); | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | sub is_dst_switch($$$) | 
| 24 |  |  |  |  |  |  | { | 
| 25 | 0 |  |  | 0 | 0 | 0 | my ($self, $t, $time) = @_; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | # calculate the time in one hour and see if the difference is 3600 seconds. | 
| 28 |  |  |  |  |  |  | # if not, we are in a dst-switch hour | 
| 29 |  |  |  |  |  |  | # note that right now we only support 1-hour dst offsets | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | # cache the result | 
| 32 | 0 | 0 | 0 |  |  | 0 | if(defined $self->{is_dst_switch_last_hour} and | 
| 33 |  |  |  |  |  |  | $self->{is_dst_switch_last_hour} == $t->[3]<<5+$t->[2]) { | 
| 34 | 0 |  |  |  |  | 0 | return @{$self->{is_dst_switch_result}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 35 |  |  |  |  |  |  | } | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | # calculate a number out of the day and hour to identify the hour | 
| 38 | 0 |  |  |  |  | 0 | $self->{is_dst_switch_last_hour} = $t->[3]<<5+$t->[2]; | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | # calculating hour+1 (below) is a problem if the hour is 23. as far as I | 
| 41 |  |  |  |  |  |  | # know, nobody does the DST switch at this time, so just assume it isn't | 
| 42 |  |  |  |  |  |  | # DST switch if the hour is 23. | 
| 43 | 0 | 0 |  |  |  | 0 | if($t->[2]==23) { | 
| 44 | 0 |  |  |  |  | 0 | @{$self->{is_dst_switch_result}} = (0, undef); | 
|  | 0 |  |  |  |  | 0 |  | 
| 45 | 0 |  |  |  |  | 0 | return @{$self->{is_dst_switch_result}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | # let's see the timestamp in one hour | 
| 49 |  |  |  |  |  |  | # 0: sec, 1: min, 2: h, 3: day, 4: month, 5: year | 
| 50 | 0 |  |  |  |  | 0 | my $time_plus_1h = timelocal($t->[0], $t->[1], $t->[2]+1, $t->[3], $t->[4], $t->[5]); | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 0 | 0 |  |  |  | 0 | if($time_plus_1h - $time > 4000) { | 
| 53 | 0 |  |  |  |  | 0 | @{$self->{is_dst_switch_result}} = (3600, $time-$time%3600+3600); | 
|  | 0 |  |  |  |  | 0 |  | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  | else { | 
| 56 | 0 |  |  |  |  | 0 | @{$self->{is_dst_switch_result}} = (0, undef); | 
|  | 0 |  |  |  |  | 0 |  | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 0 |  |  |  |  | 0 | return @{$self->{is_dst_switch_result}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | # fast timelocal, cache minute's timestamp | 
| 63 |  |  |  |  |  |  | # don't cache more than minute because of daylight saving time switch | 
| 64 |  |  |  |  |  |  | # 0: sec, 1: min, 2: h, 3: day, 4: month, 5: year | 
| 65 |  |  |  |  |  |  | sub str2time($$$$$$$$) | 
| 66 |  |  |  |  |  |  | { | 
| 67 | 62 |  |  | 62 | 0 | 88 | my $self = shift @_; | 
| 68 | 62 |  |  |  |  | 115 | my $GMT = pop @_; | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 62 |  |  |  |  | 227 | my $lastmin = $self->{str2time_lastmin}; | 
| 71 | 62 | 100 | 100 |  |  | 720 | if(defined $lastmin and | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 72 |  |  |  |  |  |  | $lastmin->[0] == $_[1] and | 
| 73 |  |  |  |  |  |  | $lastmin->[1] == $_[2] and | 
| 74 |  |  |  |  |  |  | $lastmin->[2] == $_[3] and | 
| 75 |  |  |  |  |  |  | $lastmin->[3] == $_[4] and | 
| 76 |  |  |  |  |  |  | $lastmin->[4] == $_[5]) | 
| 77 |  |  |  |  |  |  | { | 
| 78 | 22 |  |  |  |  | 58 | $self->{last_time} = $self->{str2time_lastmin_time} + $_[0]; | 
| 79 | 22 |  | 50 |  |  | 124 | return $self->{last_time} + ($self->{dst_comp}||0); | 
| 80 |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 40 |  |  |  |  | 48 | my $time; | 
| 83 | 40 | 100 |  |  |  | 64 | if($GMT) { | 
| 84 | 6 |  |  |  |  | 27 | $time = timegm(@_); | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  | else { | 
| 87 | 34 |  |  |  |  | 118 | $time = timelocal(@_); | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | # compensate for DST-switch | 
| 91 |  |  |  |  |  |  | # - if a timewarp is detected (1:00 -> 1:30 -> 1:00): | 
| 92 |  |  |  |  |  |  | # - test if we are in a DST-switch-hour | 
| 93 |  |  |  |  |  |  | # - compensate if yes | 
| 94 |  |  |  |  |  |  | # note that we assume that the DST-switch goes like this: | 
| 95 |  |  |  |  |  |  | # time   1:00  1:30  2:00  2:30  2:00  2:30  3:00  3:30 | 
| 96 |  |  |  |  |  |  | # stamp   1     2     3     4     3     3     7     8 | 
| 97 |  |  |  |  |  |  | # comp.   0     0     0     0     2     2     0     0 | 
| 98 |  |  |  |  |  |  | # result  1     2     3     4     5     6     7     8 | 
| 99 |  |  |  |  |  |  | # old Time::Local versions behave differently (1 2  5 6 5 6 7 8) | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 40 | 50 | 66 |  |  | 2749 | if(!$GMT and !defined $self->{dst_comp} and | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 102 |  |  |  |  |  |  | defined $self->{last_time} and | 
| 103 |  |  |  |  |  |  | $self->{last_time}-$time > 1200 and | 
| 104 |  |  |  |  |  |  | $self->{last_time}-$time < 3600) | 
| 105 |  |  |  |  |  |  | { | 
| 106 | 0 |  |  |  |  | 0 | my ($off, $until) = $self->is_dst_switch(\@_, $time); | 
| 107 | 0 | 0 |  |  |  | 0 | if($off) { | 
| 108 | 0 |  |  |  |  | 0 | $self->{dst_comp} = $off; | 
| 109 | 0 |  |  |  |  | 0 | $self->{dst_comp_until} = $until; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | } | 
| 112 | 40 | 50 | 33 |  |  | 143 | if(defined $self->{dst_comp_until} and $time > $self->{dst_comp_until}) { | 
| 113 | 0 |  |  |  |  | 0 | delete $self->{dst_comp}; | 
| 114 | 0 |  |  |  |  | 0 | delete $self->{dst_comp_until}; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 40 |  |  |  |  | 196 | $self->{str2time_lastmin} = [ @_[1..5] ]; | 
| 118 | 40 |  |  |  |  | 100 | $self->{str2time_lastmin_time} = $time-$_[0]; | 
| 119 | 40 |  |  |  |  | 56 | $self->{last_time} = $time; | 
| 120 | 40 |  | 50 |  |  | 219 | return $time+($self->{dst_comp}||0); | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub _use_locale($) | 
| 124 |  |  |  |  |  |  | { | 
| 125 | 8 |  |  | 8 |  | 8239 | use POSIX qw(locale_h strftime); | 
|  | 8 |  |  |  |  | 75457 |  | 
|  | 8 |  |  |  |  | 58 |  | 
| 126 | 0 |  |  | 0 |  | 0 | my $old_locale = setlocale(LC_TIME); | 
| 127 | 0 |  |  |  |  | 0 | for my $locale (@_) { | 
| 128 | 0 | 0 |  |  |  | 0 | croak "new(): wrong 'locale' value: '$locale'" unless setlocale(LC_TIME, $locale); | 
| 129 | 0 |  |  |  |  | 0 | for my $month (0..11) { | 
| 130 | 0 |  |  |  |  | 0 | $months_map{strftime("%b", 0, 0, 0, 1, $month, 96)} = $month; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  | } | 
| 133 | 0 |  |  |  |  | 0 | setlocale(LC_TIME, $old_locale); | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | sub new($$;%) | 
| 138 |  |  |  |  |  |  | { | 
| 139 | 7 |  |  | 7 | 0 | 3970 | my ($class, $file, %data) = @_; | 
| 140 | 7 | 50 |  |  |  | 112 | croak "new() requires one argument: file" unless defined $file; | 
| 141 | 7 | 50 |  |  |  | 28 | %data = () unless %data; | 
| 142 | 7 | 50 |  |  |  | 49 | if(not defined $data{year}) { | 
| 143 | 0 |  |  |  |  | 0 | $data{year} = (localtime(time))[5]+1900; | 
| 144 |  |  |  |  |  |  | } | 
| 145 | 7 | 100 |  |  |  | 43 | $data{type} = 'syslog' unless defined $data{type}; | 
| 146 | 7 |  |  |  |  | 20 | $data{_repeat}=0; | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 7 | 50 |  |  |  | 119 | if(UNIVERSAL::isa($file, 'IO::Handle')) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 149 | 0 |  |  |  |  | 0 | $data{file} = $file; | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  | elsif(UNIVERSAL::isa($file, 'File::Tail')) { | 
| 152 | 0 |  |  |  |  | 0 | $data{file} = $file; | 
| 153 | 0 |  |  |  |  | 0 | $data{filetail}=1; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | elsif(! ref $file) { | 
| 156 | 7 | 50 |  |  |  | 26 | if($file eq '-') { | 
| 157 | 0 |  |  |  |  | 0 | my $io = new IO::Handle; | 
| 158 | 0 |  |  |  |  | 0 | $data{file} = $io->fdopen(fileno(STDIN),"r"); | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | else { | 
| 161 | 7 |  |  |  |  | 69 | $data{file} = new IO::File($file, "<"); | 
| 162 | 7 | 50 |  |  |  | 903 | defined $data{file} or croak "can't open $file: $!"; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  | else { | 
| 166 | 0 |  |  |  |  | 0 | croak "argument must be either a file-name or an IO::Handle object."; | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 7 | 50 |  |  |  | 31 | if(defined $data{locale}) { | 
| 170 | 0 | 0 |  |  |  | 0 | if(ref $data{locale} eq 'ARRAY') { | 
|  |  | 0 |  |  |  |  |  | 
| 171 | 0 |  |  |  |  | 0 | _use_locale @{$data{locale}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  | elsif(ref $data{locale} eq '') { | 
| 174 | 0 |  |  |  |  | 0 | _use_locale $data{locale}; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | else { | 
| 177 | 0 |  |  |  |  | 0 | croak "'locale' parameter must be scalar or array of scalars"; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 7 |  |  |  |  | 31 | return bless \%data, $class; | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | sub _year_increment($$) | 
| 185 |  |  |  |  |  |  | { | 
| 186 | 62 |  |  | 62 |  | 88 | my ($self, $mon) = @_; | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | # year change | 
| 189 | 62 | 100 |  |  |  | 160 | if($mon==0) { | 
|  |  | 100 |  |  |  |  |  | 
| 190 | 7 | 100 | 66 |  |  | 62 | $self->{year}++ if defined $self->{_last_mon} and $self->{_last_mon} == 11; | 
| 191 | 7 |  |  |  |  | 12 | $self->{enable_year_decrement} = 1; | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  | elsif($mon == 11) { | 
| 194 | 3 | 100 |  |  |  | 10 | if($self->{enable_year_decrement}) { | 
| 195 | 1 | 50 | 33 |  |  | 9 | $self->{year}-- if defined $self->{_last_mon} and $self->{_last_mon} != 11; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  | else { | 
| 199 | 52 |  |  |  |  | 119 | $self->{enable_year_decrement} = 0; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 62 |  |  |  |  | 124 | $self->{_last_mon} = $mon; | 
| 203 |  |  |  |  |  |  | } | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | sub _next_line($) | 
| 206 |  |  |  |  |  |  | { | 
| 207 | 69 |  |  | 69 |  | 82 | my $self = shift; | 
| 208 | 69 |  |  |  |  | 104 | my $f = $self->{file}; | 
| 209 | 69 | 50 |  |  |  | 142 | if(defined $self->{filetail}) { | 
| 210 | 0 |  |  |  |  | 0 | return $f->read; | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  | else { | 
| 213 | 69 |  |  |  |  | 2000 | return $f->getline; | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | sub _next_syslog($) | 
| 218 |  |  |  |  |  |  | { | 
| 219 | 146 |  |  | 146 |  | 174 | my ($self) = @_; | 
| 220 |  |  |  |  |  |  |  | 
| 221 | 146 |  |  |  |  | 359 | while($self->{_repeat}>0) { | 
| 222 | 84 |  |  |  |  | 104 | $self->{_repeat}--; | 
| 223 | 84 |  |  |  |  | 229 | return $self->{_repeat_data}; | 
| 224 |  |  |  |  |  |  | } | 
| 225 |  |  |  |  |  |  |  | 
| 226 | 62 |  |  |  |  | 97 | my $file = $self->{file}; | 
| 227 | 62 |  |  |  |  | 138 | line: while(defined (my $str = $self->_next_line)) { | 
| 228 |  |  |  |  |  |  | # date, time and host | 
| 229 |  |  |  |  |  |  | $str =~ /^ | 
| 230 |  |  |  |  |  |  | (\S{3})\s+(\d+)      # date  -- 1, 2 | 
| 231 |  |  |  |  |  |  | \s | 
| 232 |  |  |  |  |  |  | (\d+):(\d+):(\d+)    # time  -- 3, 4, 5 | 
| 233 |  |  |  |  |  |  | (?:\s<\w+\.\w+>)?    # FreeBSD's verbose-mode | 
| 234 |  |  |  |  |  |  | \s | 
| 235 |  |  |  |  |  |  | ([-\w\.\@:]+)        # host  -- 6 | 
| 236 |  |  |  |  |  |  | \s+ | 
| 237 |  |  |  |  |  |  | (?:\[LOG_[A-Z]+\]\s+)?  # FreeBSD | 
| 238 |  |  |  |  |  |  | (.*)                 # text  -- 7 | 
| 239 |  |  |  |  |  |  | $/x or do | 
| 240 | 59 | 50 |  |  |  | 2181 | { | 
| 241 | 0 |  |  |  |  | 0 | warn "WARNING: line not in syslog format: $str"; | 
| 242 | 0 |  |  |  |  | 0 | next line; | 
| 243 |  |  |  |  |  |  | }; | 
| 244 |  |  |  |  |  |  |  | 
| 245 | 59 |  |  |  |  | 127 | my $mon = $months_map{$1}; | 
| 246 | 59 | 50 |  |  |  | 120 | defined $mon or croak "unknown month $1\n"; | 
| 247 |  |  |  |  |  |  |  | 
| 248 | 59 |  |  |  |  | 205 | $self->_year_increment($mon); | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | # convert to unix time | 
| 251 | 59 |  |  |  |  | 280 | my $time = $self->str2time($5,$4,$3,$2,$mon,$self->{year}-1900,$self->{GMT}); | 
| 252 | 59 | 50 |  |  |  | 173 | if(not $self->{allow_future}) { | 
| 253 |  |  |  |  |  |  | # accept maximum one day in the present future | 
| 254 | 59 | 50 |  |  |  | 186 | if($time - time > 86400) { | 
| 255 | 0 |  |  |  |  | 0 | warn "WARNING: ignoring future date in syslog line: $str"; | 
| 256 | 0 |  |  |  |  | 0 | next line; | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 59 |  |  |  |  | 160 | my ($host, $text) = ($6, $7); | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | # last message repeated ... times | 
| 263 | 59 | 100 |  |  |  | 224 | if($text =~ /^(?:last message repeated|above message repeats) (\d+) time/) { | 
| 264 | 14 | 50 | 33 |  |  | 58 | next line if defined $self->{repeat} and not $self->{repeat}; | 
| 265 | 14 | 100 |  |  |  | 64 | next line if not defined $self->{_last_data}{$host}; | 
| 266 | 12 | 50 |  |  |  | 40 | $1 > 0 or do { | 
| 267 | 0 |  |  |  |  | 0 | warn "WARNING: last message repeated 0 or less times??\n"; | 
| 268 | 0 |  |  |  |  | 0 | next line; | 
| 269 |  |  |  |  |  |  | }; | 
| 270 | 12 |  |  |  |  | 27 | $self->{_repeat}=$1-1; | 
| 271 | 12 |  |  |  |  | 32 | $self->{_repeat_data}=$self->{_last_data}{$host}; | 
| 272 | 12 |  |  |  |  | 54 | return $self->{_last_data}{$host}; | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | # marks | 
| 276 | 45 | 100 |  |  |  | 99 | next if $text eq '-- MARK --'; | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | # some systems send over the network their | 
| 279 |  |  |  |  |  |  | # hostname prefixed to the text. strip that. | 
| 280 | 44 |  |  |  |  | 479 | $text =~ s/^$host\s+//; | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | # discard ':' in HP-UX 'su' entries like this: | 
| 283 |  |  |  |  |  |  | # Apr 24 19:09:40 remedy : su : + tty?? root-oracle | 
| 284 | 44 |  |  |  |  | 77 | $text =~ s/^:\s+//; | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | $text =~ /^ | 
| 287 |  |  |  |  |  |  | ([^:]+?)        # program   -- 1 | 
| 288 |  |  |  |  |  |  | (?:\[(\d+)\])?  # PID       -- 2 | 
| 289 |  |  |  |  |  |  | :\s+ | 
| 290 |  |  |  |  |  |  | (?:\[ID\ (\d+)\ ([a-z0-9]+)\.([a-z]+)\]\ )?   # Solaris 8 "message id" -- 3, 4, 5 | 
| 291 |  |  |  |  |  |  | (.*)            # text      -- 6 | 
| 292 |  |  |  |  |  |  | $/x or do | 
| 293 | 44 | 50 |  |  |  | 340 | { | 
| 294 | 0 |  |  |  |  | 0 | warn "WARNING: line not in syslog format: $str"; | 
| 295 | 0 |  |  |  |  | 0 | next line; | 
| 296 |  |  |  |  |  |  | }; | 
| 297 |  |  |  |  |  |  |  | 
| 298 | 44 | 50 |  |  |  | 129 | if($self->{arrayref}) { | 
| 299 | 0 |  |  |  |  | 0 | $self->{_last_data}{$host} = [ | 
| 300 |  |  |  |  |  |  | $time,  # 0: timestamp | 
| 301 |  |  |  |  |  |  | $host,  # 1: host | 
| 302 |  |  |  |  |  |  | $1,     # 2: program | 
| 303 |  |  |  |  |  |  | $2,     # 3: pid | 
| 304 |  |  |  |  |  |  | $6,     # 4: text | 
| 305 |  |  |  |  |  |  | ]; | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  | else { | 
| 308 | 44 |  |  |  |  | 495 | $self->{_last_data}{$host} = { | 
| 309 |  |  |  |  |  |  | timestamp => $time, | 
| 310 |  |  |  |  |  |  | host      => $host, | 
| 311 |  |  |  |  |  |  | program   => $1, | 
| 312 |  |  |  |  |  |  | pid       => $2, | 
| 313 |  |  |  |  |  |  | msgid     => $3, | 
| 314 |  |  |  |  |  |  | facility  => $4, | 
| 315 |  |  |  |  |  |  | level     => $5, | 
| 316 |  |  |  |  |  |  | text      => $6, | 
| 317 |  |  |  |  |  |  | }; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 | 44 |  |  |  |  | 246 | return $self->{_last_data}{$host}; | 
| 321 |  |  |  |  |  |  | } | 
| 322 | 6 |  |  |  |  | 236 | return undef; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | sub _next_metalog($) | 
| 326 |  |  |  |  |  |  | { | 
| 327 | 4 |  |  | 4 |  | 5 | my ($self) = @_; | 
| 328 | 4 |  |  |  |  | 6 | my $file = $self->{file}; | 
| 329 | 4 |  |  |  |  | 10 | line: while(my $str = $self->_next_line) { | 
| 330 |  |  |  |  |  |  | # date, time and host | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | $str =~ /^ | 
| 333 |  |  |  |  |  |  | (\S{3})\s+(\d+)   # date  -- 1, 2 | 
| 334 |  |  |  |  |  |  | \s | 
| 335 |  |  |  |  |  |  | (\d+):(\d+):(\d+) # time  -- 3, 4, 5 | 
| 336 |  |  |  |  |  |  | # host is not logged | 
| 337 |  |  |  |  |  |  | \s+ | 
| 338 |  |  |  |  |  |  | (.*)              # text  -- 6 | 
| 339 |  |  |  |  |  |  | $/x or do | 
| 340 | 3 | 50 |  |  |  | 119 | { | 
| 341 | 0 |  |  |  |  | 0 | warn "WARNING: line not in metalog format: $str"; | 
| 342 | 0 |  |  |  |  | 0 | next line; | 
| 343 |  |  |  |  |  |  | }; | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 3 |  |  |  |  | 7 | my $mon = $months_map{$1}; | 
| 346 | 3 | 50 |  |  |  | 9 | defined $mon or croak "unknown month $1\n"; | 
| 347 |  |  |  |  |  |  |  | 
| 348 | 3 |  |  |  |  | 7 | $self->_year_increment($mon); | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | # convert to unix time | 
| 351 | 3 |  |  |  |  | 17 | my $time = $self->str2time($5,$4,$3,$2,$mon,$self->{year}-1900,$self->{GMT}); | 
| 352 |  |  |  |  |  |  |  | 
| 353 | 3 |  |  |  |  | 8 | my $text = $6; | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | $text =~ /^ | 
| 356 |  |  |  |  |  |  | \[(.*?)\]        # program   -- 1 | 
| 357 |  |  |  |  |  |  | # no PID | 
| 358 |  |  |  |  |  |  | \s+ | 
| 359 |  |  |  |  |  |  | (.*)             # text      -- 2 | 
| 360 |  |  |  |  |  |  | $/x or do | 
| 361 | 3 | 50 |  |  |  | 15 | { | 
| 362 | 0 |  |  |  |  | 0 | warn "WARNING: text line not in metalog format: $text ($str)"; | 
| 363 | 0 |  |  |  |  | 0 | next line; | 
| 364 |  |  |  |  |  |  | }; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 3 | 50 |  |  |  | 5 | if($self->{arrayref}) { | 
| 367 |  |  |  |  |  |  | return [ | 
| 368 | 0 |  |  |  |  | 0 | $time,  # 0: timestamp | 
| 369 |  |  |  |  |  |  | 'localhost',  # 1: host | 
| 370 |  |  |  |  |  |  | $1,     # 2: program | 
| 371 |  |  |  |  |  |  | undef,  # 3: (no) pid | 
| 372 |  |  |  |  |  |  | $2,     # 4: text | 
| 373 |  |  |  |  |  |  | ]; | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | else { | 
| 376 |  |  |  |  |  |  | return { | 
| 377 | 3 |  |  |  |  | 23 | timestamp => $time, | 
| 378 |  |  |  |  |  |  | host      => 'localhost', | 
| 379 |  |  |  |  |  |  | program   => $1, | 
| 380 |  |  |  |  |  |  | text      => $2, | 
| 381 |  |  |  |  |  |  | }; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  | } | 
| 384 | 1 |  |  |  |  | 35 | return undef; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | sub next($) | 
| 388 |  |  |  |  |  |  | { | 
| 389 | 150 |  |  | 150 | 0 | 47254 | my ($self) = @_; | 
| 390 | 150 | 100 |  |  |  | 396 | if($self->{type} eq 'syslog') { | 
|  |  | 50 |  |  |  |  |  | 
| 391 | 146 |  |  |  |  | 290 | return $self->_next_syslog(); | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | elsif($self->{type} eq 'metalog') { | 
| 394 | 4 |  |  |  |  | 9 | return $self->_next_metalog(); | 
| 395 |  |  |  |  |  |  | } | 
| 396 | 0 |  |  |  |  |  | croak "Internal error: unknown type: $self->{type}"; | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | 1; | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | __END__ |