Filename | /var/www/foswiki11/lib/Foswiki/Logger/PlainFile.pm |
Statements | Executed 158 statements in 2.93ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
3 | 3 | 2 | 364µs | 2.50ms | log | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 181µs | 184µs | BEGIN@6 | Foswiki::Logger::PlainFile::
3 | 1 | 1 | 96µs | 1.81ms | _rotate | Foswiki::Logger::PlainFile::
3 | 1 | 1 | 64µs | 100µs | _getLogForLevel | Foswiki::Logger::PlainFile::
4 | 2 | 1 | 36µs | 36µs | _time2month | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 16µs | 16µs | BEGIN@10 | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 13µs | 26µs | BEGIN@4 | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 13µs | 72µs | BEGIN@35 | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 10µs | 25µs | BEGIN@7 | Foswiki::Logger::PlainFile::
2 | 1 | 1 | 10µs | 10µs | _stat | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 10µs | 15µs | BEGIN@5 | Foswiki::Logger::PlainFile::
3 | 1 | 1 | 9µs | 9µs | _time | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 9µs | 9µs | new | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 5µs | 5µs | BEGIN@33 | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 4µs | 4µs | BEGIN@9 | Foswiki::Logger::PlainFile::
1 | 1 | 1 | 4µs | 4µs | BEGIN@32 | Foswiki::Logger::PlainFile::
0 | 0 | 0 | 0s | 0s | hasNext | Foswiki::Logger::PlainFile::EventIterator::
0 | 0 | 0 | 0s | 0s | new | Foswiki::Logger::PlainFile::EventIterator::
0 | 0 | 0 | 0s | 0s | next | Foswiki::Logger::PlainFile::EventIterator::
0 | 0 | 0 | 0s | 0s | eachEventSince | Foswiki::Logger::PlainFile::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki::Logger::PlainFile; | ||||
3 | |||||
4 | 2 | 29µs | 2 | 40µs | # spent 26µs (13+13) within Foswiki::Logger::PlainFile::BEGIN@4 which was called:
# once (13µs+13µs) by Foswiki::logger at line 4 # spent 26µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@4
# spent 13µs making 1 call to strict::import |
5 | 2 | 25µs | 2 | 20µs | # spent 15µs (10+5) within Foswiki::Logger::PlainFile::BEGIN@5 which was called:
# once (10µs+5µs) by Foswiki::logger at line 5 # spent 15µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@5
# spent 5µs making 1 call to warnings::import |
6 | 2 | 195µs | 2 | 186µs | # spent 184µs (181+3) within Foswiki::Logger::PlainFile::BEGIN@6 which was called:
# once (181µs+3µs) by Foswiki::logger at line 6 # spent 184µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@6
# spent 3µs making 1 call to utf8::import |
7 | 2 | 26µs | 2 | 39µs | # spent 25µs (10+14) within Foswiki::Logger::PlainFile::BEGIN@7 which was called:
# once (10µs+14µs) by Foswiki::logger at line 7 # spent 25µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@7
# spent 14µs making 1 call to Assert::import |
8 | |||||
9 | 2 | 22µs | 1 | 4µs | # spent 4µs within Foswiki::Logger::PlainFile::BEGIN@9 which was called:
# once (4µs+0s) by Foswiki::logger at line 9 # spent 4µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@9 |
10 | 2 | 72µs | 1 | 16µs | # spent 16µs within Foswiki::Logger::PlainFile::BEGIN@10 which was called:
# once (16µs+0s) by Foswiki::logger at line 10 # spent 16µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@10 |
11 | 1 | 14µs | our @ISA = ('Foswiki::Logger'); | ||
12 | |||||
13 | =begin TML | ||||
14 | |||||
15 | ---+ package Foswiki::Logger::PlainFile | ||||
16 | |||||
17 | Plain file implementation of the Foswiki Logger interface. Mostly | ||||
18 | compatible with TWiki (and Foswiki 1.0.0) log files, except that dates | ||||
19 | are recorded using ISO format, and include the time, and it dies when | ||||
20 | a log can't be written (rather than printing a warning). | ||||
21 | |||||
22 | This logger implementation maps groups of levels to a single logfile, viz. | ||||
23 | * =debug= messages are output to $Foswiki::cfg{Log}{Dir}/debug.log | ||||
24 | * =info= messages are output to $Foswiki::cfg{Log}{Dir}/events.log | ||||
25 | * =warning=, =error=, =critical=, =alert=, =emergency= messages are | ||||
26 | output to $Foswiki::cfg{Log}{Dir}/error.log. | ||||
27 | * =error=, =critical=, =alert=, and =emergency= messages are also | ||||
28 | written to standard error (the webserver log file, usually) | ||||
29 | |||||
30 | =cut | ||||
31 | |||||
32 | 2 | 21µs | 1 | 4µs | # spent 4µs within Foswiki::Logger::PlainFile::BEGIN@32 which was called:
# once (4µs+0s) by Foswiki::logger at line 32 # spent 4µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@32 |
33 | 2 | 29µs | 1 | 5µs | # spent 5µs within Foswiki::Logger::PlainFile::BEGIN@33 which was called:
# once (5µs+0s) by Foswiki::logger at line 33 # spent 5µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@33 |
34 | |||||
35 | 2 | 1.81ms | 2 | 130µs | # spent 72µs (13+59) within Foswiki::Logger::PlainFile::BEGIN@35 which was called:
# once (13µs+59µs) by Foswiki::logger at line 35 # spent 72µs making 1 call to Foswiki::Logger::PlainFile::BEGIN@35
# spent 59µs making 1 call to constant::import |
36 | |||||
37 | # Map from a log level to the root of a log file name | ||||
38 | 1 | 5µs | our %LEVEL2LOG = ( | ||
39 | debug => 'debug', | ||||
40 | info => 'events', | ||||
41 | warning => 'error', | ||||
42 | error => 'error', | ||||
43 | critical => 'error', | ||||
44 | alert => 'error', | ||||
45 | emergency => 'error' | ||||
46 | ); | ||||
47 | |||||
48 | 1 | 1µs | our %nextCheckDue = ( | ||
49 | debug => 0, | ||||
50 | events => 0, | ||||
51 | error => 0, | ||||
52 | ); | ||||
53 | |||||
54 | # Symbols used so we can override during unit testing | ||||
55 | 1 | 200ns | our $dontRotate = 0; | ||
56 | 3 | 12µs | # spent 9µs within Foswiki::Logger::PlainFile::_time which was called 3 times, avg 3µs/call:
# 3 times (9µs+0s) by Foswiki::Logger::PlainFile::log at line 76, avg 3µs/call | ||
57 | 2 | 14µs | # spent 10µs within Foswiki::Logger::PlainFile::_stat which was called 2 times, avg 5µs/call:
# 2 times (10µs+0s) by Foswiki::Logger::PlainFile::_rotate at line 293, avg 5µs/call | ||
58 | |||||
59 | # spent 9µs within Foswiki::Logger::PlainFile::new which was called:
# once (9µs+0s) by Foswiki::logger at line 2078 of /var/www/foswiki11/lib/Foswiki.pm | ||||
60 | 1 | 500ns | my $class = shift; | ||
61 | 1 | 12µs | return bless( {}, $class ); | ||
62 | } | ||||
63 | |||||
64 | =begin TML | ||||
65 | |||||
66 | ---++ ObjectMethod log($level, @fields) | ||||
67 | |||||
68 | See Foswiki::Logger for the interface. | ||||
69 | |||||
70 | =cut | ||||
71 | |||||
72 | # spent 2.50ms (364µs+2.14) within Foswiki::Logger::PlainFile::log which was called 3 times, avg 833µs/call:
# once (112µs+1.73ms) by Foswiki::Plugins::load at line 205 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (91µs+251µs) by Foswiki::logEvent at line 2269 of /var/www/foswiki11/lib/Foswiki.pm
# once (162µs+150µs) by Foswiki::Plugins::enable at line 272 of /var/www/foswiki11/lib/Foswiki/Plugins.pm | ||||
73 | 3 | 15µs | my ( $this, $level, @fields ) = @_; | ||
74 | |||||
75 | 3 | 11µs | 3 | 100µs | my $log = _getLogForLevel($level); # spent 100µs making 3 calls to Foswiki::Logger::PlainFile::_getLogForLevel, avg 33µs/call |
76 | 3 | 8µs | 3 | 9µs | my $now = _time(); # spent 9µs making 3 calls to Foswiki::Logger::PlainFile::_time, avg 3µs/call |
77 | 3 | 11µs | 3 | 1.81ms | _rotate( $LEVEL2LOG{$level}, $log, $now ); # spent 1.81ms making 3 calls to Foswiki::Logger::PlainFile::_rotate, avg 605µs/call |
78 | 3 | 15µs | 3 | 207µs | my $time = Foswiki::Time::formatTime( $now, 'iso', 'gmtime' ); # spent 207µs making 3 calls to Foswiki::Time::formatTime, avg 69µs/call |
79 | |||||
80 | # Unfortunate compatibility requirement; need the level, but the old | ||||
81 | # logfile format doesn't allow us to add fields. Since we are changing | ||||
82 | # the date format anyway, the least pain is to concatenate the level | ||||
83 | # to the date; Foswiki::Time::ParseTime can handle it, and it looks | ||||
84 | # OK too. | ||||
85 | 3 | 5µs | unshift( @fields, "$time $level" ); | ||
86 | 10 | 19µs | my $message = | ||
87 | 13 | 51µs | '| ' . join( ' | ', map { s/\|/&vbar;/g; $_ } @fields ) . ' |'; | ||
88 | |||||
89 | 3 | 600ns | my $file; | ||
90 | 3 | 2µs | my $mode = '>>'; | ||
91 | |||||
92 | # Item10764, SMELL UNICODE: actually, perhaps we should open the stream this | ||||
93 | # way for any encoding, not just utf8. Babar says: check what Catalyst does. | ||||
94 | 3 | 30µs | 3 | 5µs | if ( $Foswiki::cfg{Site}{CharSet} # spent 5µs making 3 calls to utf8::is_utf8, avg 2µs/call |
95 | && $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/ ) | ||||
96 | { | ||||
97 | $mode .= ":encoding($Foswiki::cfg{Site}{CharSet})"; | ||||
98 | } | ||||
99 | elsif ( utf8::is_utf8($message) ) { | ||||
100 | require Encode; | ||||
101 | $message = Encode::encode( $Foswiki::cfg{Site}{CharSet}, $message, 0 ); | ||||
102 | } | ||||
103 | 3 | 75µs | if ( open( $file, $mode, $log ) ) { | ||
104 | 3 | 23µs | print $file "$message\n"; | ||
105 | 3 | 66µs | close($file); | ||
106 | } | ||||
107 | else { | ||||
108 | if ( !-w $log ) { | ||||
109 | die | ||||
110 | "ERROR: Could not open logfile $log for write. Your admin should 'configure' now and fix the errors!\n"; | ||||
111 | } | ||||
112 | |||||
113 | # die to force the admin to get permissions correct | ||||
114 | die 'ERROR: Could not write ' . $message . ' to ' . "$log: $!\n"; | ||||
115 | } | ||||
116 | 3 | 37µs | if ( $level =~ /^(error|critical|alert|emergency)$/ ) { | ||
117 | print STDERR "$message\n"; | ||||
118 | } | ||||
119 | } | ||||
120 | |||||
121 | { | ||||
122 | |||||
123 | # Private subclass of LineIterator that splits events into fields | ||||
124 | 1 | 300ns | package Foswiki::Logger::PlainFile::EventIterator; | ||
125 | 1 | 78µs | require Foswiki::LineIterator; | ||
126 | 1 | 5µs | @Foswiki::Logger::PlainFile::EventIterator::ISA = ('Foswiki::LineIterator'); | ||
127 | |||||
128 | sub new { | ||||
129 | my ( $class, $fh, $threshold, $level ) = @_; | ||||
130 | my $this = $class->SUPER::new($fh); | ||||
131 | $this->{_threshold} = $threshold; | ||||
132 | $this->{_level} = $level; | ||||
133 | return $this; | ||||
134 | } | ||||
135 | |||||
136 | sub hasNext { | ||||
137 | my $this = shift; | ||||
138 | return 1 if defined $this->{_nextEvent}; | ||||
139 | while ( $this->SUPER::hasNext() ) { | ||||
140 | my @line = split( /\s*\|\s*/, $this->SUPER::next() ); | ||||
141 | shift @line; # skip the leading empty cell | ||||
142 | next unless scalar(@line) && defined $line[0]; | ||||
143 | if ( | ||||
144 | $line[0] =~ s/\s+$this->{_level}\s*$// # test the level | ||||
145 | # accept a plain 'old' format date with no level only if reading info (statistics) | ||||
146 | || $line[0] =~ /^\d{1,2} [a-z]{3} \d{4}/i | ||||
147 | && $this->{_level} eq 'info' | ||||
148 | ) | ||||
149 | { | ||||
150 | $line[0] = Foswiki::Time::parseTime( $line[0] ); | ||||
151 | next | ||||
152 | unless ( defined $line[0] ) | ||||
153 | ; # Skip record if time doesn't decode. | ||||
154 | if ( $line[0] >= $this->{_threshold} ) { # test the time | ||||
155 | $this->{_nextEvent} = \@line; | ||||
156 | return 1; | ||||
157 | } | ||||
158 | } | ||||
159 | } | ||||
160 | return 0; | ||||
161 | } | ||||
162 | |||||
163 | sub next { | ||||
164 | my $this = shift; | ||||
165 | my $data = $this->{_nextEvent}; | ||||
166 | undef $this->{_nextEvent}; | ||||
167 | return $data; | ||||
168 | } | ||||
169 | } | ||||
170 | |||||
171 | =begin TML | ||||
172 | |||||
173 | ---++ StaticMethod eachEventSince($time, $level) -> $iterator | ||||
174 | |||||
175 | See Foswiki::Logger for the interface. | ||||
176 | |||||
177 | This logger implementation maps groups of levels to a single logfile, viz. | ||||
178 | * =info= messages are output together. | ||||
179 | * =warning=, =error=, =critical=, =alert=, =emergency= messages are | ||||
180 | output together. | ||||
181 | This method cannot | ||||
182 | |||||
183 | =cut | ||||
184 | |||||
185 | sub eachEventSince { | ||||
186 | my ( $this, $time, $level ) = @_; | ||||
187 | my $log = _getLogForLevel($level); | ||||
188 | |||||
189 | # Find the year-month for the current time | ||||
190 | my $now = _time(); | ||||
191 | my $nowLogYear = Foswiki::Time::formatTime( $now, '$year', 'servertime' ); | ||||
192 | my $nowLogMonth = Foswiki::Time::formatTime( $now, '$mo', 'servertime' ); | ||||
193 | |||||
194 | # Find the year-month for the first time in the range | ||||
195 | my $logYear = Foswiki::Time::formatTime( $time, '$year', 'servertime' ); | ||||
196 | my $logMonth = Foswiki::Time::formatTime( $time, '$mo', 'servertime' ); | ||||
197 | |||||
198 | # Get the names of all the logfiles in the time range | ||||
199 | my @logs; | ||||
200 | while ( !( $logMonth == $nowLogMonth && $logYear == $nowLogYear ) ) { | ||||
201 | my $logfile = $log; | ||||
202 | my $logTime = $logYear . sprintf( "%02d", $logMonth ); | ||||
203 | $logfile =~ s/\.log$/.$logTime/g; | ||||
204 | push( @logs, $logfile ); | ||||
205 | $logMonth++; | ||||
206 | if ( $logMonth == 13 ) { | ||||
207 | $logMonth = 1; | ||||
208 | $logYear++; | ||||
209 | } | ||||
210 | } | ||||
211 | |||||
212 | # Finally the current log | ||||
213 | push( @logs, $log ); | ||||
214 | |||||
215 | my @iterators; | ||||
216 | foreach my $logfile (@logs) { | ||||
217 | next unless -r $logfile; | ||||
218 | my $fh; | ||||
219 | if ( open( $fh, '<', $logfile ) ) { | ||||
220 | push( | ||||
221 | @iterators, | ||||
222 | new Foswiki::Logger::PlainFile::EventIterator( | ||||
223 | $fh, $time, $level | ||||
224 | ) | ||||
225 | ); | ||||
226 | } | ||||
227 | else { | ||||
228 | |||||
229 | # Would be nice to report this, but it's chicken and egg and | ||||
230 | # besides, empty logfiles can happen. | ||||
231 | print STDERR "Failed to open $logfile: $!" if (TRACE); | ||||
232 | } | ||||
233 | } | ||||
234 | return new Foswiki::ListIterator( \@iterators ) if scalar(@iterators) == 0; | ||||
235 | return $iterators[0] if scalar(@iterators) == 1; | ||||
236 | return new Foswiki::AggregateIterator( \@iterators ); | ||||
237 | } | ||||
238 | |||||
239 | # Get the name of the log for a given reporting level | ||||
240 | # spent 100µs (64+36) within Foswiki::Logger::PlainFile::_getLogForLevel which was called 3 times, avg 33µs/call:
# 3 times (64µs+36µs) by Foswiki::Logger::PlainFile::log at line 75, avg 33µs/call | ||||
241 | 3 | 5µs | my $level = shift; | ||
242 | 3 | 5µs | 3 | 4µs | ASSERT( defined $LEVEL2LOG{$level} ) if DEBUG; # spent 4µs making 3 calls to Assert::ASSERTS_OFF, avg 1µs/call |
243 | 3 | 15µs | my $log = $Foswiki::cfg{Log}{Dir} . '/' . $LEVEL2LOG{$level} . '.log'; | ||
244 | |||||
245 | # SMELL: Expand should not be needed, except if bin/configure tries | ||||
246 | # to log to locations relative to $Foswiki::cfg{WorkingDir}, DataDir, etc. | ||||
247 | # Windows seemed to be the most difficult to fix - this was the only thing | ||||
248 | # that I could find that worked all the time. | ||||
249 | 3 | 18µs | 3 | 32µs | Foswiki::Configure::Load::expandValue($log); # spent 32µs making 3 calls to Foswiki::Configure::Load::expandValue, avg 11µs/call |
250 | 3 | 14µs | return $log; | ||
251 | } | ||||
252 | |||||
253 | sub _time2month { | ||||
254 | 4 | 2µs | my $time = shift; | ||
255 | 4 | 15µs | my @t = gmtime($time); | ||
256 | 4 | 2µs | $t[5] += 1900; | ||
257 | 4 | 26µs | return sprintf( '%0.4d%0.2d', $t[5], $t[4] + 1 ); | ||
258 | } | ||||
259 | |||||
260 | # See if the log needs to be rotated. If the log was last modified | ||||
261 | # last month, we need to rotate it. | ||||
262 | # spent 1.81ms (96µs+1.72) within Foswiki::Logger::PlainFile::_rotate which was called 3 times, avg 605µs/call:
# 3 times (96µs+1.72ms) by Foswiki::Logger::PlainFile::log at line 77, avg 605µs/call | ||||
263 | 3 | 6µs | my ( $level, $log, $now ) = @_; | ||
264 | |||||
265 | 3 | 1µs | return if $dontRotate; | ||
266 | 3 | 300ns | return unless $level; | ||
267 | |||||
268 | # Don't bother checking if we have checked in this process already | ||||
269 | 3 | 7µs | return if ( $now < $nextCheckDue{$level} ); | ||
270 | |||||
271 | # Work out the current month | ||||
272 | 2 | 4µs | 2 | 25µs | my $curMonth = _time2month($now); # spent 25µs making 2 calls to Foswiki::Logger::PlainFile::_time2month, avg 12µs/call |
273 | |||||
274 | # After this check, don't check again for a month. | ||||
275 | 2 | 7µs | $curMonth =~ /(\d{4})(\d{2})/; | ||
276 | 2 | 10µs | my ( $y, $m ) = ( $1, $2 + 1 ); | ||
277 | 2 | 2µs | if ( $m > 12 ) { | ||
278 | $m = '01'; | ||||
279 | $y++; | ||||
280 | } | ||||
281 | else { | ||||
282 | 2 | 3µs | $m = sprintf( '%0.2d', $m ); | ||
283 | } | ||||
284 | 2 | 11µs | 2 | 1.67ms | $nextCheckDue{$level} = Foswiki::Time::parseTime("$y-$m-01"); # spent 1.67ms making 2 calls to Foswiki::Time::parseTime, avg 836µs/call |
285 | print STDERR "Next log check due $nextCheckDue{$level} for $level\n" | ||||
286 | if (TRACE); | ||||
287 | |||||
288 | # If there's no existing log, there's nothing to rotate | ||||
289 | 2 | 13µs | return unless -e $log; | ||
290 | |||||
291 | # Check when the log was last modified. If it was in the previous | ||||
292 | # month, if may need to be rotated. | ||||
293 | 2 | 8µs | 2 | 10µs | my @stat = _stat($log); # spent 10µs making 2 calls to Foswiki::Logger::PlainFile::_stat, avg 5µs/call |
294 | 2 | 5µs | 2 | 11µs | my $modMonth = _time2month( $stat[9] ); # spent 11µs making 2 calls to Foswiki::Logger::PlainFile::_time2month, avg 6µs/call |
295 | print STDERR "compare $modMonth, $curMonth\n" if (TRACE); | ||||
296 | 2 | 8µs | return if ( $modMonth == $curMonth ); | ||
297 | |||||
298 | # The log was last modified in a month that was not the current month. | ||||
299 | # Rotate older entries out into month-by-month logfiles. | ||||
300 | |||||
301 | # Open the current log | ||||
302 | my $lf; | ||||
303 | unless ( open( $lf, '<', $log ) ) { | ||||
304 | print STDERR | ||||
305 | "ERROR: PlainFile Logger could not open logfile $log for read: $! \n"; | ||||
306 | return; | ||||
307 | } | ||||
308 | |||||
309 | my %months; | ||||
310 | |||||
311 | local $/ = "\n"; | ||||
312 | my $line; | ||||
313 | my $linecount; | ||||
314 | my $stashline = ''; | ||||
315 | while ( $line = <$lf> ) { | ||||
316 | $stashline .= $line; | ||||
317 | my @event = split( /\s*\|\s*/, $line ); | ||||
318 | $linecount++; | ||||
319 | if ( scalar(@event) > 7 ) { | ||||
320 | print STDERR "Bad log " | ||||
321 | . join( ' | ', @event ) | ||||
322 | . " | - Skipped \n " | ||||
323 | if (TRACE); | ||||
324 | $stashline = ''; | ||||
325 | next; | ||||
326 | } | ||||
327 | |||||
328 | unless ( $event[1] ) { | ||||
329 | print STDERR | ||||
330 | "BAD LOGFILE LINE - skip $line - line $linecount in $log\n" | ||||
331 | if (TRACE); | ||||
332 | next; | ||||
333 | } | ||||
334 | |||||
335 | #Item12022: parseTime bogs the CPU down here, so try a dumb regex first | ||||
336 | # (assuming ISO8601 format Eg. 2000-01-31T23:59:00Z). Result: 4x speedup | ||||
337 | my $eventMonth; | ||||
338 | if ( $event[1] =~ /^(\d{4})-(\d{2})-\d{2}T[0-9:]+Z\b/ ) { | ||||
339 | $eventMonth = $1 . $2; | ||||
340 | } | ||||
341 | else { | ||||
342 | print STDERR ">> Non-ISO date string encountered\n" if (TRACE); | ||||
343 | $eventMonth = _time2month( Foswiki::Time::parseTime( $event[1] ) ); | ||||
344 | } | ||||
345 | |||||
346 | if ( !defined $eventMonth ) { | ||||
347 | |||||
348 | print STDERR | ||||
349 | ">> Bad time in log - skip: $line - line $linecount in $log\n" | ||||
350 | if (TRACE); | ||||
351 | next; | ||||
352 | } | ||||
353 | |||||
354 | if ( $eventMonth < $curMonth ) { | ||||
355 | push( @{ $months{$eventMonth} }, $stashline ); | ||||
356 | $stashline = ''; | ||||
357 | } | ||||
358 | else { | ||||
359 | |||||
360 | # Reached the start of log entries for this month | ||||
361 | print STDERR ">> Reached start of this month - count $linecount \n" | ||||
362 | if (TRACE); | ||||
363 | last; | ||||
364 | } | ||||
365 | } | ||||
366 | print STDERR " Months " | ||||
367 | . join( ' ', keys %months ) | ||||
368 | . " - processed $linecount records \n" | ||||
369 | if (TRACE); | ||||
370 | |||||
371 | if ( !scalar( keys %months ) ) { | ||||
372 | |||||
373 | # no old months, we're done. The modify time on the current | ||||
374 | # log will be touched by the next write, so we won't attempt | ||||
375 | # to rotate again until next month. | ||||
376 | print STDERR ">> No old months\n" if (TRACE); | ||||
377 | close($lf); | ||||
378 | return; | ||||
379 | } | ||||
380 | |||||
381 | # Sook up the rest of the current log | ||||
382 | $line ||= ''; | ||||
383 | $/ = undef; | ||||
384 | my $curLog = $line . <$lf>; | ||||
385 | close($lf); | ||||
386 | |||||
387 | foreach my $month ( keys %months ) { | ||||
388 | my $bf; | ||||
389 | my $backup = $log; | ||||
390 | $backup =~ s/log$/$month/; | ||||
391 | if ( -e $backup ) { | ||||
392 | print STDERR | ||||
393 | "ERROR: PlainFile Logger could not create $backup - file exists\n"; | ||||
394 | return; | ||||
395 | } | ||||
396 | unless ( open( $bf, '>', $backup ) ) { | ||||
397 | print STDERR | ||||
398 | "ERROR: PlainFile Logger could not create $backup - $! \n"; | ||||
399 | return; | ||||
400 | } | ||||
401 | print $bf join( '', @{ $months{$month} } ); | ||||
402 | close($bf); | ||||
403 | } | ||||
404 | |||||
405 | # Finally rewrite the shortened current log | ||||
406 | unless ( open( $lf, '>', $log ) ) { | ||||
407 | print STDERR | ||||
408 | "ERROR: PlainFile Logger could not open logfile $log for write: $! \n"; | ||||
409 | return; | ||||
410 | } | ||||
411 | print $lf $curLog; | ||||
412 | close($lf); | ||||
413 | } | ||||
414 | |||||
415 | 1 | 6µs | 1; | ||
416 | __END__ |