line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MySQL::SlowLog::Filter;
|
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
61827
|
use warnings;
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
66
|
|
4
|
2
|
|
|
2
|
|
12
|
use strict;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
122
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.05';
|
7
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:FAYLAND';
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
11
|
use base 'Exporter';
|
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
178
|
|
10
|
2
|
|
|
2
|
|
10
|
use vars qw/@EXPORT_OK/;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
122
|
|
11
|
|
|
|
|
|
|
@EXPORT_OK = qw/ run parse_date_range parse_time /;
|
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
15
|
use Carp qw/croak/;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
92
|
|
14
|
2
|
|
|
2
|
|
2313
|
use Time::Local;
|
|
2
|
|
|
|
|
2241
|
|
|
2
|
|
|
|
|
184
|
|
15
|
|
|
|
|
|
|
#use DBI;
|
16
|
2
|
|
|
2
|
|
2250
|
use File::Slurp;
|
|
2
|
|
|
|
|
45208
|
|
|
2
|
|
|
|
|
3459
|
|
17
|
|
|
|
|
|
|
#use Data::Dumper;
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our @default_sorting = (
|
20
|
|
|
|
|
|
|
4, 'sum-query-time',
|
21
|
|
|
|
|
|
|
2, 'avg-query-time',
|
22
|
|
|
|
|
|
|
3, 'max-query-time',
|
23
|
|
|
|
|
|
|
7, 'sum-lock-time',
|
24
|
|
|
|
|
|
|
5, 'avg-lock-time',
|
25
|
|
|
|
|
|
|
6, 'max-lock-time',
|
26
|
|
|
|
|
|
|
13, 'sum-rows-examined',
|
27
|
|
|
|
|
|
|
11, 'avg-rows-examined',
|
28
|
|
|
|
|
|
|
12, 'max-rows-examined',
|
29
|
|
|
|
|
|
|
1, 'execution-count',
|
30
|
|
|
|
|
|
|
10, 'sum-rows-sent',
|
31
|
|
|
|
|
|
|
8, 'avg-rows-sent',
|
32
|
|
|
|
|
|
|
9, 'max-rows-sent'
|
33
|
|
|
|
|
|
|
);
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub run {
|
36
|
0
|
|
|
0
|
1
|
0
|
my $file = shift;
|
37
|
0
|
0
|
|
|
|
0
|
my ( $params ) = ( scalar @_ == 1 ) ? shift : { @_ };
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# check date range
|
40
|
0
|
|
|
|
|
0
|
my $date = $params->{date};
|
41
|
0
|
|
|
|
|
0
|
my ( $date_first, $date_last ) = parse_date_range( $date );
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# check settings
|
44
|
0
|
|
0
|
|
|
0
|
my $include_hosts = $params->{'include-host'} || $params->{ih} || [];
|
45
|
0
|
|
0
|
|
|
0
|
my $exclude_hosts = $params->{'exclude-host'} || $params->{eh} || [];
|
46
|
0
|
|
0
|
|
|
0
|
my $include_users = $params->{'include-user'} || $params->{iu} || [];
|
47
|
0
|
|
0
|
|
|
0
|
my $exclude_users = $params->{'exclude-user'} || $params->{eu} || [];
|
48
|
|
|
|
|
|
|
|
49
|
0
|
|
0
|
|
|
0
|
my $no_duplicates = $params->{no_duplicates} || 0;
|
50
|
0
|
|
0
|
|
|
0
|
my $no_output = $params->{no_output} || 0;
|
51
|
0
|
|
0
|
|
|
0
|
my $incremental = $params->{incremental} || 0;
|
52
|
|
|
|
|
|
|
|
53
|
0
|
|
0
|
|
|
0
|
my $min_query_time = $params->{min_query_time} || $params->{T} || -1;
|
54
|
0
|
|
0
|
|
|
0
|
my $min_rows_examined = $params->{min_rows_examined} || $params->{R} || -1;
|
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
0
|
my @lines = read_file( $file );
|
57
|
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
0
|
if ( $incremental ) {
|
59
|
|
|
|
|
|
|
# TODO
|
60
|
|
|
|
|
|
|
}
|
61
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
0
|
my ( $query, $timestamp, $user, $host, $in_query );
|
63
|
0
|
|
|
|
|
0
|
my @query_time;
|
64
|
0
|
|
|
|
|
0
|
my %queries;
|
65
|
0
|
|
|
|
|
0
|
foreach my $line ( @lines ) {
|
66
|
0
|
0
|
|
|
|
0
|
next unless $line;
|
67
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
0
|
if ( $line =~ /^\# / ) {
|
|
|
0
|
|
|
|
|
|
69
|
0
|
0
|
|
|
|
0
|
if ( $query ) {
|
70
|
0
|
0
|
|
|
|
0
|
if ( $in_query ) {
|
71
|
0
|
|
|
|
|
0
|
process_query( \%queries, $query, $no_duplicates, $user, $host,
|
72
|
|
|
|
|
|
|
$timestamp, \@query_time);
|
73
|
|
|
|
|
|
|
}
|
74
|
0
|
|
|
|
|
0
|
$query = '';
|
75
|
0
|
|
|
|
|
0
|
$in_query = 0;
|
76
|
|
|
|
|
|
|
}
|
77
|
|
|
|
|
|
|
|
78
|
0
|
0
|
0
|
|
|
0
|
if ( $line =~ /^\# T/ ) { # # Time: 070119 12:29:58
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
79
|
0
|
|
|
|
|
0
|
( $timestamp ) = ( $line =~ /(\d+(.*?))$/ );
|
80
|
0
|
|
|
|
|
0
|
my $t = get_log_timestamp($timestamp);
|
81
|
0
|
0
|
0
|
|
|
0
|
if ( $t < $date_first or $t > $date_last ) {
|
82
|
0
|
|
|
|
|
0
|
$timestamp = 0;
|
83
|
|
|
|
|
|
|
}
|
84
|
|
|
|
|
|
|
} elsif ( $timestamp and $line =~ /^\# U/ ) { # # User@Host: root[root] @ localhost []
|
85
|
0
|
|
|
|
|
0
|
chomp($line);
|
86
|
0
|
|
|
|
|
0
|
my $text = substr( $line, 13, length($line) - 13 );
|
87
|
0
|
|
|
|
|
0
|
( $user, $host ) = split(' @ ', $text, 2);
|
88
|
|
|
|
|
|
|
|
89
|
0
|
0
|
|
|
|
0
|
if (not scalar @$include_hosts) {
|
90
|
0
|
|
|
|
|
0
|
$in_query = 1;
|
91
|
0
|
|
|
|
|
0
|
foreach my $eh ( @$exclude_hosts ) {
|
92
|
0
|
0
|
|
|
|
0
|
if ( $host =~ /$eh/ ) {
|
93
|
0
|
|
|
|
|
0
|
$in_query = 0;
|
94
|
0
|
|
|
|
|
0
|
last;
|
95
|
|
|
|
|
|
|
}
|
96
|
|
|
|
|
|
|
}
|
97
|
|
|
|
|
|
|
} else {
|
98
|
0
|
|
|
|
|
0
|
$in_query = 0;
|
99
|
0
|
|
|
|
|
0
|
foreach my $ih ( @$include_hosts ) {
|
100
|
0
|
0
|
|
|
|
0
|
if ( $host =~ /$ih/ ) {
|
101
|
0
|
|
|
|
|
0
|
$in_query = 1;
|
102
|
0
|
|
|
|
|
0
|
last;
|
103
|
|
|
|
|
|
|
}
|
104
|
|
|
|
|
|
|
}
|
105
|
|
|
|
|
|
|
}
|
106
|
0
|
0
|
|
|
|
0
|
next if ( not $in_query );
|
107
|
|
|
|
|
|
|
|
108
|
0
|
0
|
|
|
|
0
|
if (not scalar @$include_users) {
|
109
|
0
|
|
|
|
|
0
|
$in_query = 1;
|
110
|
0
|
|
|
|
|
0
|
foreach my $eu ( @$exclude_users ) {
|
111
|
0
|
0
|
|
|
|
0
|
if ( $user =~ /$eu/ ) {
|
112
|
0
|
|
|
|
|
0
|
$in_query = 0;
|
113
|
0
|
|
|
|
|
0
|
last;
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
}
|
116
|
|
|
|
|
|
|
} else {
|
117
|
0
|
|
|
|
|
0
|
$in_query = 0;
|
118
|
0
|
|
|
|
|
0
|
foreach my $iu ( @$include_users ) {
|
119
|
0
|
0
|
|
|
|
0
|
if ( $user =~ /$iu/ ) {
|
120
|
0
|
|
|
|
|
0
|
$in_query = 1;
|
121
|
0
|
|
|
|
|
0
|
last;
|
122
|
|
|
|
|
|
|
}
|
123
|
|
|
|
|
|
|
}
|
124
|
|
|
|
|
|
|
}
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
# # Query_time: 0 Lock_time: 0 Rows_sent: 0 Rows_examined: 156
|
127
|
|
|
|
|
|
|
elsif ( $in_query and $line =~ /^\# Q/ ) {
|
128
|
0
|
|
|
|
|
0
|
my $text = substr( $line, 13, length($line) - 13 );
|
129
|
0
|
|
|
|
|
0
|
my @numbers = split(':', $text);
|
130
|
0
|
|
|
|
|
0
|
@query_time = ();
|
131
|
0
|
|
|
|
|
0
|
foreach (@numbers) {
|
132
|
0
|
0
|
|
|
|
0
|
push @query_time, $1 if (/(\d+)/);
|
133
|
|
|
|
|
|
|
}
|
134
|
0
|
0
|
0
|
|
|
0
|
$in_query = ( $query_time[0] >= $min_query_time or ($min_rows_examined and $query_time[3] >= $min_rows_examined) ) ? 1 : 0;
|
135
|
|
|
|
|
|
|
}
|
136
|
|
|
|
|
|
|
} elsif ( $in_query ) {
|
137
|
0
|
|
|
|
|
0
|
$query .= $line;
|
138
|
|
|
|
|
|
|
}
|
139
|
|
|
|
|
|
|
}
|
140
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
0
|
if ( $query ) {
|
142
|
0
|
|
|
|
|
0
|
process_query(\%queries, $query, $no_duplicates, $user, $host,
|
143
|
|
|
|
|
|
|
$timestamp, \@query_time);
|
144
|
|
|
|
|
|
|
}
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
}
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub process_query {
|
149
|
0
|
|
|
0
|
0
|
0
|
my ( $queries, $query, $no_duplicates, $user, $host, $timestamp, $query_time ) = @_;
|
150
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
0
|
my $user_host = $user . ' @ ' . $host;
|
152
|
0
|
0
|
|
|
|
0
|
if ( $no_duplicates ) {
|
153
|
|
|
|
|
|
|
# TODO
|
154
|
|
|
|
|
|
|
} else {
|
155
|
0
|
0
|
|
|
|
0
|
my $ls = ( $^O eq 'MSWin32' ) ? "\r\n" :
|
|
|
0
|
|
|
|
|
|
156
|
|
|
|
|
|
|
( $^O eq 'darwin' ) ? "\r" : "\n";
|
157
|
0
|
|
|
|
|
0
|
print sprintf("# Time: %s%s# User\@Host: %s%s# Query_time: %d Lock_time: %d Rows_sent: %d Rows_examined: %d%s%s", $timestamp, $ls, $user_host, $ls, $query_time->[0], $query_time->[1], $query_time->[2], $query_time->[3], $ls, $query);
|
158
|
|
|
|
|
|
|
}
|
159
|
|
|
|
|
|
|
}
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub parse_date_range {
|
162
|
9
|
|
|
9
|
1
|
9635
|
my $date = shift;
|
163
|
|
|
|
|
|
|
|
164
|
9
|
|
|
|
|
20
|
my ( $start, $end ) = ( 0, 9999999999 );
|
165
|
9
|
100
|
|
|
|
30
|
return ( $start, $end ) unless ( $date );
|
166
|
|
|
|
|
|
|
|
167
|
8
|
|
|
|
|
61
|
my @parts = ( $date =~ /
|
168
|
|
|
|
|
|
|
( # first date (don't match beginning of string)
|
169
|
|
|
|
|
|
|
(?:\d{4}|\d{1,2}) # first part can be 1-2 or 4 digits long (DD, MM, YYYY)
|
170
|
|
|
|
|
|
|
(?:[\.\-\/]?\d{1,2}[\.\-\/]?)? # middle part (1-2 digits), optionally separated
|
171
|
|
|
|
|
|
|
(?:\d{4}|\d{1,2})? # end part (1-2, 4 digits), optionally separated
|
172
|
|
|
|
|
|
|
) # end of first date
|
173
|
|
|
|
|
|
|
(?:-( # optional second date, separated by "-"
|
174
|
|
|
|
|
|
|
(?:\d{4}|\d{1,2}) # first part can be 1-2 or 4 digits long (DD, MM, YYYY)
|
175
|
|
|
|
|
|
|
(?:[\.\-\/]?\d{1,2})? # middle part (1-2 digits), optionally separated
|
176
|
|
|
|
|
|
|
(?:[\.\-\/]?(?:\d{4}|\d{1,2}))? # end part (1-2, 4 digits), optionally separated
|
177
|
|
|
|
|
|
|
))? # end of optional second date
|
178
|
|
|
|
|
|
|
/x );
|
179
|
|
|
|
|
|
|
|
180
|
8
|
|
|
|
|
17
|
@parts = grep { defined $_ } @parts;
|
|
16
|
|
|
|
|
47
|
|
181
|
8
|
50
|
|
|
|
27
|
return ( $start, $end ) unless ( scalar @parts );
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# for >13.11.2006 <13.11.2006 -13.11.2006
|
184
|
8
|
100
|
|
|
|
38
|
if ( $date =~ /^([\>\<\-])/ ) {
|
|
|
100
|
|
|
|
|
|
185
|
3
|
100
|
100
|
|
|
24
|
if ( $1 eq '<' or $1 eq '-' ) {
|
186
|
2
|
|
|
|
|
7
|
$end = parse_time( $parts[0] );
|
187
|
|
|
|
|
|
|
} else {
|
188
|
1
|
|
|
|
|
4
|
$start = parse_time( $parts[0] );
|
189
|
|
|
|
|
|
|
}
|
190
|
|
|
|
|
|
|
} elsif ( scalar @parts > 1 ) {
|
191
|
3
|
|
|
|
|
9
|
$start = parse_time( $parts[0] );
|
192
|
|
|
|
|
|
|
# for '13/11/2006-'
|
193
|
3
|
50
|
|
|
|
15
|
$end = parse_time( $parts[1] ) if ( $parts[1] ne '-' );
|
194
|
|
|
|
|
|
|
} else {
|
195
|
2
|
|
|
|
|
6
|
$start = parse_time( $parts[0] );
|
196
|
|
|
|
|
|
|
}
|
197
|
|
|
|
|
|
|
|
198
|
8
|
|
|
|
|
30
|
return ( $start, $end );
|
199
|
|
|
|
|
|
|
}
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub parse_time {
|
202
|
|
|
|
|
|
|
# Return a unix timestamp from the given date.
|
203
|
14
|
|
|
14
|
1
|
1728
|
my $date = shift;
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# for those '13.11.2006' '11/13/2006' '15-11-2006'
|
206
|
14
|
|
|
|
|
210
|
my @parts = ( $date =~ /(\d+)/g );
|
207
|
14
|
|
|
|
|
31
|
$parts[2] -= 1900;
|
208
|
14
|
|
|
|
|
19
|
$parts[1] -= 1;
|
209
|
|
|
|
|
|
|
|
210
|
14
|
|
|
|
|
16
|
my $r;
|
211
|
14
|
|
|
|
|
23
|
eval {
|
212
|
14
|
|
|
|
|
45
|
$r = timelocal(0, 0, 0, @parts);
|
213
|
|
|
|
|
|
|
};
|
214
|
14
|
50
|
|
|
|
881
|
croak "$date is not accepted\n" if ($@);
|
215
|
14
|
|
|
|
|
44
|
return $r;
|
216
|
|
|
|
|
|
|
}
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub get_log_timestamp {
|
219
|
0
|
|
|
0
|
1
|
|
my $date = shift;
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# 070119 12:29:58
|
222
|
0
|
|
|
|
|
|
my ( $year, $month, $day, $hour, $min, $secs ) = (
|
223
|
|
|
|
|
|
|
$date =~ /(\d\d)(\d\d)(\d\d)\s+(\d{1,2})\:(\d{1,2})\:(\d{1,2})/ );
|
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
$year += 100;
|
226
|
0
|
|
|
|
|
|
$month -= 1;
|
227
|
0
|
|
|
|
|
|
return timelocal($secs, $min, $hour, $day, $month, $year);
|
228
|
|
|
|
|
|
|
}
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
1;
|
231
|
|
|
|
|
|
|
__END__
|