line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
DPKG::Log - Parse the dpkg log |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 VERSION |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
version 1.20 |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use DPKG::Log; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $dpkg_log = DPKG::Log->new('filename' => 'dpkg.log', 'parse' => 1); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 DESCRIPTION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
This module is used to parse a logfile and store each line |
18
|
|
|
|
|
|
|
as a DPKG::Log::Entry object. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 METHODS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=over 4 |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=cut |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
package DPKG::Log; |
27
|
|
|
|
|
|
|
BEGIN { |
28
|
6
|
|
|
6
|
|
122335
|
$DPKG::Log::VERSION = '1.20'; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
6
|
|
|
6
|
|
49
|
use strict; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
167
|
|
32
|
6
|
|
|
6
|
|
29
|
use warnings; |
|
6
|
|
|
|
|
8
|
|
|
6
|
|
|
|
|
161
|
|
33
|
6
|
|
|
6
|
|
141
|
use 5.010; |
|
6
|
|
|
|
|
29
|
|
|
6
|
|
|
|
|
272
|
|
34
|
|
|
|
|
|
|
|
35
|
6
|
|
|
6
|
|
34
|
use Carp; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
496
|
|
36
|
6
|
|
|
6
|
|
2536
|
use DPKG::Log::Entry; |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
648
|
|
37
|
6
|
|
|
6
|
|
6656
|
use DateTime::Format::Strptime; |
|
6
|
|
|
|
|
1313644
|
|
|
6
|
|
|
|
|
453
|
|
38
|
6
|
|
|
6
|
|
75
|
use DateTime::TimeZone; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
135
|
|
39
|
6
|
|
|
6
|
|
31
|
use Params::Validate qw(:all); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
1370
|
|
40
|
6
|
|
|
6
|
|
7043
|
use Data::Dumper; |
|
6
|
|
|
|
|
57568
|
|
|
6
|
|
|
|
|
13261
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item $dpkg_log = DPKG::Log->new() |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item $dpkg_log = DPKG::Log->new('filename' => 'dpkg.log') |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=item $dpkg_log = DPKG::Log->new('filename' => 'dpkg.log', 'parse' => 1 ) |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Returns a new DPKG::Log object. If parse is set to a true value the logfile |
49
|
|
|
|
|
|
|
specified by filename is parsed at the end of the object initialisation. |
50
|
|
|
|
|
|
|
Otherwise the parse routine has to be called. |
51
|
|
|
|
|
|
|
Filename parameter can be ommitted, it defaults to /var/log/dpkg.log. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Optionally its possible to specify B or B arguments as timestamps |
54
|
|
|
|
|
|
|
in the standard dpkg.log format or as DateTime objects. |
55
|
|
|
|
|
|
|
This will limit the entries which will be stored in the object to entries in the |
56
|
|
|
|
|
|
|
given timerange. |
57
|
|
|
|
|
|
|
Note that, if this is not what you want, you may ommit these attributes and |
58
|
|
|
|
|
|
|
can use B instead. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
By default the module will assume that those timestamps are in the local timezone |
61
|
|
|
|
|
|
|
as determined by DateTime::TimeZone. This can be overriden by giving the |
62
|
|
|
|
|
|
|
argument B which takes a timezone string (e.g. 'Europe/Berlin') |
63
|
|
|
|
|
|
|
or a DateTime::TimeZone object. |
64
|
|
|
|
|
|
|
Additionally its possible to override the timestamp_pattern by specifying |
65
|
|
|
|
|
|
|
B. This has to be a valid pattern for DateTime::Format::Strptime. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=cut |
68
|
|
|
|
|
|
|
sub new { |
69
|
7
|
|
|
7
|
1
|
2445
|
my $package = shift; |
70
|
7
|
100
|
|
|
|
32
|
$package = ref($package) if ref($package); |
71
|
|
|
|
|
|
|
|
72
|
7
|
|
|
|
|
304
|
my %params = validate(@_, |
73
|
|
|
|
|
|
|
{ |
74
|
|
|
|
|
|
|
'filename' => { 'type' => SCALAR, 'default' => '/var/log/dpkg.log' }, |
75
|
|
|
|
|
|
|
'parse' => 0, |
76
|
|
|
|
|
|
|
'time_zone' => { 'type' => SCALAR, 'default' => 'local' }, |
77
|
|
|
|
|
|
|
'timestamp_pattern' => { 'type' => SCALAR, 'default' => '%F %T' }, |
78
|
|
|
|
|
|
|
'from' => 0, |
79
|
|
|
|
|
|
|
'to' => 0 |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
); |
82
|
7
|
|
|
|
|
118
|
my $self = { |
83
|
|
|
|
|
|
|
entries => [], |
84
|
|
|
|
|
|
|
invalid_lines => [], |
85
|
|
|
|
|
|
|
time_zone => undef, |
86
|
|
|
|
|
|
|
from => undef, |
87
|
|
|
|
|
|
|
to => undef, |
88
|
|
|
|
|
|
|
offset => 0, |
89
|
|
|
|
|
|
|
%params |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
}; |
92
|
|
|
|
|
|
|
|
93
|
7
|
|
|
|
|
25
|
bless($self, $package); |
94
|
|
|
|
|
|
|
|
95
|
7
|
100
|
|
|
|
32
|
$self->parse if $params{'parse'}; |
96
|
|
|
|
|
|
|
|
97
|
7
|
|
|
|
|
56
|
return $self; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item $dpkg_log->filename |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=item $dpkg_log->filename('newfilename.log') |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Get or set the filename of the dpkg logfile. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=cut |
107
|
|
|
|
|
|
|
sub filename { |
108
|
4
|
|
|
4
|
1
|
7
|
my ($self, $filename) = @_; |
109
|
4
|
100
|
|
|
|
10
|
if ($filename) { |
110
|
2
|
|
|
|
|
4
|
$self->{filename} = $filename; |
111
|
|
|
|
|
|
|
} else { |
112
|
2
|
|
|
|
|
30
|
$filename = $self->{filename}; |
113
|
|
|
|
|
|
|
} |
114
|
4
|
|
|
|
|
16
|
return $filename; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item $dpkg_log->parse |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item $dpkg_log->parse('time_zone' => 'Europe/Berlin') |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item $dpkg_log->parse('time_zone' => $dt_tz ) |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Call the parser. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
The B parameter is optional and specifies in which time zone |
126
|
|
|
|
|
|
|
the dpkg log timestamps are. If its omitted it will use the default |
127
|
|
|
|
|
|
|
local time zone. |
128
|
|
|
|
|
|
|
Its possible to specify either a DateTime::TimeZone object or a string. |
129
|
|
|
|
|
|
|
=cut |
130
|
|
|
|
|
|
|
sub parse { |
131
|
6
|
|
|
6
|
1
|
26
|
my $self = shift; |
132
|
6
|
50
|
|
|
|
503
|
open(my $log_fh, "<", $self->{filename}) |
133
|
|
|
|
|
|
|
or croak("unable to open logfile for reading: $!"); |
134
|
|
|
|
|
|
|
|
135
|
6
|
|
|
|
|
237
|
my %params = validate( |
136
|
|
|
|
|
|
|
@_, { |
137
|
|
|
|
|
|
|
'from' => { default => $self->{from} }, |
138
|
|
|
|
|
|
|
'to' => { default => $self->{to} }, |
139
|
|
|
|
|
|
|
'time_zone' => { default => $self->{time_zone} }, |
140
|
|
|
|
|
|
|
'timestamp_pattern' => { default => $self->{timestamp_pattern} }, |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Determine system timezone |
145
|
6
|
|
|
|
|
43
|
my $tz; |
146
|
6
|
50
|
33
|
|
|
47
|
if (ref($params{time_zone}) and (ref($params{time_zone}) eq "DateTime::TimeZone")) { |
|
|
50
|
|
|
|
|
|
147
|
0
|
|
|
|
|
0
|
$tz = $params{time_zone}; |
148
|
|
|
|
|
|
|
} elsif (ref($params{time_zone})) { |
149
|
0
|
|
|
|
|
0
|
croak "time_zone argument has to be a string or a DateTime::TimeZone object"; |
150
|
|
|
|
|
|
|
} else { |
151
|
6
|
|
|
|
|
76
|
$tz = DateTime::TimeZone->new( 'name' => $params{time_zone} ); |
152
|
|
|
|
|
|
|
} |
153
|
6
|
|
|
|
|
54816
|
my $ts_parser = DateTime::Format::Strptime->new( |
154
|
|
|
|
|
|
|
pattern => $params{timestamp_pattern}, |
155
|
|
|
|
|
|
|
time_zone => $params{time_zone} |
156
|
|
|
|
|
|
|
); |
157
|
|
|
|
|
|
|
|
158
|
6
|
|
|
|
|
34923
|
my $lineno = 0; |
159
|
6
|
|
|
|
|
168
|
while (my $line = <$log_fh>) { |
160
|
2832
|
|
|
|
|
3455
|
$lineno++; |
161
|
2832
|
|
|
|
|
3144
|
chomp $line; |
162
|
2832
|
100
|
|
|
|
7457
|
next if $line =~ /^$/; |
163
|
|
|
|
|
|
|
|
164
|
2831
|
|
|
|
|
2652
|
my $timestamp; |
165
|
|
|
|
|
|
|
|
166
|
2831
|
|
|
|
|
15703
|
my @entry = split(/\s/, $line); |
167
|
2831
|
0
|
33
|
|
|
6123
|
if (not $entry[0] and not $entry[1]) { |
168
|
0
|
|
|
|
|
0
|
push(@{$self->{invalid_lines}}, $line); |
|
0
|
|
|
|
|
0
|
|
169
|
0
|
|
|
|
|
0
|
next; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
2831
|
|
|
|
|
6767
|
my ($year, $month, $day) = split('-', $entry[0]); |
173
|
2831
|
|
|
|
|
6553
|
my ($hour, $minute, $second) = split(':', $entry[1]); |
174
|
|
|
|
|
|
|
|
175
|
2831
|
50
|
33
|
|
|
28528
|
if ($year and $month and $day and $hour and $minute and $second) { |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
176
|
2831
|
|
|
|
|
9788
|
$timestamp = DateTime->new( |
177
|
|
|
|
|
|
|
year => $year, |
178
|
|
|
|
|
|
|
month => $month, |
179
|
|
|
|
|
|
|
day => $day, |
180
|
|
|
|
|
|
|
hour => $hour, |
181
|
|
|
|
|
|
|
minute => $minute, |
182
|
|
|
|
|
|
|
second => $second, |
183
|
|
|
|
|
|
|
time_zone => $tz |
184
|
|
|
|
|
|
|
); |
185
|
|
|
|
|
|
|
} else { |
186
|
0
|
|
|
|
|
0
|
push(@{$self->{invalid_lines}}, $line); |
|
0
|
|
|
|
|
0
|
|
187
|
0
|
|
|
|
|
0
|
next; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
2831
|
|
|
|
|
532741
|
my $entry_obj; |
191
|
2831
|
50
|
|
|
|
9490
|
if ($entry[2] eq "update-alternatives:") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
next; |
193
|
|
|
|
|
|
|
} elsif ($entry[2] eq "startup") { |
194
|
176
|
|
|
|
|
807
|
$entry_obj = { line => $line, |
195
|
|
|
|
|
|
|
lineno => $lineno, |
196
|
|
|
|
|
|
|
timestamp => $timestamp, |
197
|
|
|
|
|
|
|
type => 'startup', |
198
|
|
|
|
|
|
|
subject => $entry[3], |
199
|
|
|
|
|
|
|
action => $entry[4] |
200
|
|
|
|
|
|
|
}; |
201
|
|
|
|
|
|
|
} elsif ($entry[2] eq "status") { |
202
|
2073
|
|
|
|
|
12879
|
$entry_obj = { line => $line, |
203
|
|
|
|
|
|
|
lineno => $lineno, |
204
|
|
|
|
|
|
|
timestamp => $timestamp, |
205
|
|
|
|
|
|
|
type => 'status', |
206
|
|
|
|
|
|
|
subject => 'package', |
207
|
|
|
|
|
|
|
status => $entry[3], |
208
|
|
|
|
|
|
|
associated_package => $entry[4], |
209
|
|
|
|
|
|
|
installed_version => $entry[5] |
210
|
|
|
|
|
|
|
}; |
211
|
|
|
|
|
|
|
} elsif (defined($valid_actions->{$entry[2]}) ) { |
212
|
582
|
|
|
|
|
3644
|
$entry_obj = { line => $line, |
213
|
|
|
|
|
|
|
lineno => $lineno, |
214
|
|
|
|
|
|
|
timestamp => $timestamp, |
215
|
|
|
|
|
|
|
subject => 'package', |
216
|
|
|
|
|
|
|
type => 'action', |
217
|
|
|
|
|
|
|
action => $entry[2], |
218
|
|
|
|
|
|
|
associated_package => $entry[3], |
219
|
|
|
|
|
|
|
installed_version => $entry[4], |
220
|
|
|
|
|
|
|
available_version => $entry[5] |
221
|
|
|
|
|
|
|
}; |
222
|
|
|
|
|
|
|
} elsif ($entry[2] eq "conffile") { |
223
|
0
|
|
|
|
|
0
|
$entry_obj = { line => $line, |
224
|
|
|
|
|
|
|
lineno => $lineno, |
225
|
|
|
|
|
|
|
timestamp => $timestamp, |
226
|
|
|
|
|
|
|
subject => 'conffile', |
227
|
|
|
|
|
|
|
type => 'conffile_action', |
228
|
|
|
|
|
|
|
conffile => $entry[3], |
229
|
|
|
|
|
|
|
decision => $entry[4] |
230
|
|
|
|
|
|
|
}; |
231
|
|
|
|
|
|
|
} else { |
232
|
0
|
|
|
|
|
0
|
print $line . " invalid\n"; |
233
|
0
|
|
|
|
|
0
|
push(@{$self->{invalid_lines}}, $line); |
|
0
|
|
|
|
|
0
|
|
234
|
0
|
|
|
|
|
0
|
next; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
2831
|
|
|
|
|
3712
|
push(@{$self->{entries}}, $entry_obj); |
|
2831
|
|
|
|
|
17508
|
|
238
|
|
|
|
|
|
|
} |
239
|
6
|
|
|
|
|
229
|
close($log_fh); |
240
|
|
|
|
|
|
|
|
241
|
6
|
100
|
66
|
|
|
52
|
if ($self->{from} or $self->{to}) { |
242
|
2
|
|
|
|
|
26
|
@{$self->{entries}} = $self->filter_by_time( entry_ref => $self->{entries}, %params); |
|
2
|
|
|
|
|
4320
|
|
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
6
|
|
|
|
|
25
|
return scalar(@{$self->{entries}}); |
|
6
|
|
|
|
|
144
|
|
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item @entries = $dpkg_log->entries; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item @entries = $dpkg_log->entries('from' => '2010-01-01.10:00:00', to => '2010-01-02 24:00:00') |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Return all entries or all entries in a given timerange. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
B and B are optional arguments, specifying a date before (from) and after (to) which |
255
|
|
|
|
|
|
|
entries aren't returned. |
256
|
|
|
|
|
|
|
If only B is specified all entries from the beginning of the log are read. |
257
|
|
|
|
|
|
|
If only B is specified all entries till the end of the log are read. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=cut |
260
|
|
|
|
|
|
|
sub entries { |
261
|
4
|
|
|
4
|
1
|
14
|
my $self = shift; |
262
|
|
|
|
|
|
|
|
263
|
4
|
|
|
|
|
114
|
my %params = validate( |
264
|
|
|
|
|
|
|
@_, { |
265
|
|
|
|
|
|
|
from => 0, |
266
|
|
|
|
|
|
|
to => 0, |
267
|
|
|
|
|
|
|
time_zone => { type => SCALAR, default => $self->{time_zone} } |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
); |
270
|
4
|
50
|
|
|
|
20
|
croak "Object does not store entries. Eventually parse function were not run or log is empty. " if (not @{$self->{entries}}); |
|
4
|
|
|
|
|
23
|
|
271
|
|
|
|
|
|
|
|
272
|
4
|
100
|
66
|
|
|
37
|
if (not ($params{from} or $params{to})) { |
273
|
3
|
|
|
|
|
7
|
return map { DPKG::Log::Entry->new($_) } @{$self->{entries}}; |
|
721
|
|
|
|
|
1802
|
|
|
3
|
|
|
|
|
14
|
|
274
|
|
|
|
|
|
|
} else { |
275
|
1
|
|
|
|
|
7
|
return $self->filter_by_time(%params); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=item $entry = $dpkg_log->next_entry; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Return the next entry. |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=cut |
284
|
|
|
|
|
|
|
sub next_entry { |
285
|
7
|
|
|
7
|
1
|
19
|
my $self = shift; |
286
|
7
|
|
|
|
|
23
|
my $offset = $self->{offset}++; |
287
|
7
|
|
|
|
|
14
|
return DPKG::Log::Entry->new(@{$self->{entries}}[$offset]); |
|
7
|
|
|
|
|
65
|
|
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=item @entries = $dpkg_log->filter_by_time(from => ts, to => ts) |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=item @entries = $dpkg_log->filter_by_time(from => ts) |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=item @entries = $dpkg_log->filter_by_time(to => ts) |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item @entries = $dpkg_log->filter_by_time(from => ts, to => ts, entry_ref => $entry_ref) |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Filter entries by given B - B range. See the explanations for |
299
|
|
|
|
|
|
|
the new sub for the arguments. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
If entry_ref is given and an array reference its used instead of $self->{entries} |
302
|
|
|
|
|
|
|
as input source for the entries which are to be filtered. |
303
|
|
|
|
|
|
|
=cut |
304
|
|
|
|
|
|
|
sub filter_by_time { |
305
|
3
|
|
|
3
|
1
|
5
|
my $self = shift; |
306
|
3
|
|
|
|
|
101
|
my %params = validate( |
307
|
|
|
|
|
|
|
@_, { |
308
|
|
|
|
|
|
|
from => 0, |
309
|
|
|
|
|
|
|
to => 0, |
310
|
|
|
|
|
|
|
time_zone => { default => $self->{time_zone} }, |
311
|
|
|
|
|
|
|
timestamp_pattern => { default => $self->{timestamp_pattern} }, |
312
|
|
|
|
|
|
|
entry_ref => { default => $self->{entries} }, |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
); |
315
|
|
|
|
|
|
|
|
316
|
3
|
|
|
|
|
21
|
my @entries = @{$params{entry_ref}}; |
|
3
|
|
|
|
|
481
|
|
317
|
3
|
50
|
|
|
|
11
|
if (not @entries) { |
318
|
0
|
|
|
|
|
0
|
croak "Object does not store entries. Eventually parse function were not run or log is empty."; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
3
|
|
|
|
|
20
|
$self->__eval_datetime_info(%params); |
322
|
|
|
|
|
|
|
|
323
|
3
|
50
|
|
|
|
17
|
@entries = grep { (DPKG::Log::Entry->new($_)->timestamp >= $self->{from}) and (DPKG::Log::Entry->new($_)->timestamp <= $self->{to}) } @entries; |
|
1695
|
|
|
|
|
116306
|
|
324
|
3
|
|
|
|
|
483
|
return map { DPKG::Log::Entry->new($_) } @entries; |
|
234
|
|
|
|
|
554
|
|
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=item ($from, $to) = $dpkg_log->get_datetime_info() |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Returns the from and to timestamps of the logfile or (if from/to values are set) the |
330
|
|
|
|
|
|
|
values set during object initialisation. |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
sub get_datetime_info { |
334
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
335
|
|
|
|
|
|
|
|
336
|
1
|
|
|
|
|
2
|
my $from; |
337
|
|
|
|
|
|
|
my $to; |
338
|
1
|
50
|
|
|
|
4
|
if ($self->{from}) { |
339
|
0
|
|
|
|
|
0
|
$from = $self->{from}; |
340
|
|
|
|
|
|
|
} else { |
341
|
1
|
|
|
|
|
2
|
$from = DPKG::Log::Entry->new(%{$self->{entries}->[0]})->timestamp; |
|
1
|
|
|
|
|
7
|
|
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
1
|
50
|
|
|
|
21
|
if ($self->{to}) { |
345
|
0
|
|
|
|
|
0
|
$to = $self->{to}; |
346
|
|
|
|
|
|
|
} else { |
347
|
1
|
|
|
|
|
3
|
$to = DPKG::Log::Entry->new(%{$self->{entries}->[-1]})->timestamp; |
|
1
|
|
|
|
|
8
|
|
348
|
|
|
|
|
|
|
} |
349
|
1
|
|
|
|
|
7
|
return ($from, $to); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
## Internal methods |
353
|
|
|
|
|
|
|
sub __eval_datetime_info { |
354
|
3
|
|
|
3
|
|
5
|
my $self = shift; |
355
|
|
|
|
|
|
|
|
356
|
3
|
|
|
|
|
120
|
my %params = validate( |
357
|
|
|
|
|
|
|
@_, { |
358
|
|
|
|
|
|
|
from => { default => $self->{from} }, |
359
|
|
|
|
|
|
|
to => { default => $self->{to} }, |
360
|
|
|
|
|
|
|
time_zone => { default => $self->{time_zone} }, |
361
|
|
|
|
|
|
|
timestamp_pattern => { default => $self->{timestamp_pattern} }, |
362
|
|
|
|
|
|
|
entry_ref => { default => $self->{entries} }, |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
); |
365
|
|
|
|
|
|
|
|
366
|
3
|
|
|
|
|
28
|
my $entry_ref = $params{entry_ref}; |
367
|
3
|
|
|
|
|
5
|
my $from = $params{from}; |
368
|
3
|
|
|
|
|
6
|
my $to = $params{to}; |
369
|
|
|
|
|
|
|
|
370
|
3
|
|
|
|
|
119
|
my $ts_parser = DateTime::Format::Strptime->new( |
371
|
|
|
|
|
|
|
pattern => $params{timestamp_pattern}, |
372
|
|
|
|
|
|
|
time_zone => $params{time_zone} |
373
|
|
|
|
|
|
|
); |
374
|
|
|
|
|
|
|
|
375
|
3
|
50
|
|
|
|
24471
|
if (not $from) { |
376
|
0
|
|
|
|
|
0
|
$from = DPKG::Log::Entry->new($entry_ref->[0])->timestamp; |
377
|
|
|
|
|
|
|
} |
378
|
3
|
50
|
|
|
|
20
|
if (not $to) { |
379
|
0
|
|
|
|
|
0
|
$to = DPKG::Log::Entry->new($entry_ref->[-1])->timestamp; |
380
|
|
|
|
|
|
|
} |
381
|
3
|
50
|
|
|
|
13
|
if (ref($from) ne "DateTime") { |
382
|
3
|
|
|
|
|
17
|
$from = $ts_parser->parse_datetime($from); |
383
|
|
|
|
|
|
|
} |
384
|
3
|
50
|
|
|
|
2649
|
if (ref($to) ne "DateTime") { |
385
|
3
|
|
|
|
|
13
|
$to = $ts_parser->parse_datetime($to); |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
3
|
|
|
|
|
2129
|
$self->{from} = $from; |
389
|
3
|
|
|
|
|
11
|
$self->{to} = $to; |
390
|
3
|
|
|
|
|
25
|
return; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=back |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=head1 SEE ALSO |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
L, L, L |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head1 AUTHOR |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Patrick Schoenfeld . |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Copyright (C) 2011 Patrick Schoenfeld |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
This library is free software. |
409
|
|
|
|
|
|
|
You can redistribute it and/or modify it under the same terms as perl itself. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=cut |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
1; |
414
|
|
|
|
|
|
|
# vim: expandtab:ts=4:sw=4 |