line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBIx::ProfileManager; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
592
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
82
|
|
4
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
93
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
7
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
7804
|
use DBI; |
|
2
|
|
|
|
|
30146
|
|
|
2
|
|
|
|
|
108
|
|
9
|
2
|
|
|
2
|
|
1134
|
use DBI::Profile; |
|
2
|
|
|
|
|
3076
|
|
|
2
|
|
|
|
|
172
|
|
10
|
2
|
|
|
2
|
|
12
|
use Scalar::Util qw(weaken); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
308
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our %ORIGINAL_METHODS; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
15
|
2
|
|
|
2
|
1
|
25
|
my ( $class, %args ) = @_; |
16
|
2
|
|
50
|
|
|
21
|
bless +{ |
17
|
|
|
|
|
|
|
config => $args{config} || '!Statement', |
18
|
|
|
|
|
|
|
data => +{}, |
19
|
|
|
|
|
|
|
path => [], |
20
|
|
|
|
|
|
|
is_started => 0, |
21
|
|
|
|
|
|
|
} => $class; |
22
|
|
|
|
|
|
|
} |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
{ |
25
|
2
|
|
|
2
|
|
9
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
482
|
|
26
|
|
|
|
|
|
|
for my $attr ( qw/config data path is_started/ ) { |
27
|
|
|
|
|
|
|
*{$attr} = sub { |
28
|
56
|
100
|
|
56
|
|
131
|
if ( @_ == 2 ) { |
29
|
8
|
|
|
|
|
32
|
$_[0]->{$attr} = $_[1]; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
else { |
32
|
48
|
|
|
|
|
183
|
return $_[0]->{$attr}; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
}; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub profile_start { |
39
|
2
|
|
|
2
|
1
|
13
|
my ( $self, @db_handles ) = @_; |
40
|
|
|
|
|
|
|
|
41
|
2
|
|
|
|
|
9
|
my $config = $self->config; |
42
|
|
|
|
|
|
|
|
43
|
2
|
50
|
|
|
|
7
|
unless ( @db_handles > 0 ) { |
44
|
2
|
|
|
|
|
9
|
@db_handles = $self->_active_db_handles; |
45
|
2
|
|
|
|
|
14
|
$ENV{DBI_PROFILE} = $config; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
2
|
50
|
|
|
|
8
|
if ( @db_handles > 0 ) { |
49
|
2
|
|
|
|
|
3
|
for my $dbh (@db_handles) { |
50
|
3
|
|
|
|
|
280
|
$dbh->{Profile} = $config; |
51
|
|
|
|
|
|
|
} |
52
|
2
|
50
|
|
|
|
86
|
if ( $db_handles[0] ) { |
53
|
2
|
|
|
|
|
21
|
$self->path($db_handles[0]->{Profile}{Path}); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
2
|
|
|
|
|
9
|
$self->data(+{}); |
58
|
2
|
50
|
|
|
|
4
|
$self->path( [ split(':', $config) ] ) if ( @{$self->path} == 0 ); |
|
2
|
|
|
|
|
6
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
{ |
61
|
2
|
|
|
2
|
|
15
|
no strict 'refs'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
71
|
|
|
2
|
|
|
|
|
4
|
|
62
|
2
|
|
|
2
|
|
10
|
no warnings 'redefine'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
529
|
|
63
|
|
|
|
|
|
|
|
64
|
2
|
|
|
|
|
3
|
my $pfm = $self; |
65
|
2
|
|
|
|
|
11
|
weaken( $pfm ); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my $cb = sub { |
68
|
0
|
|
|
0
|
|
0
|
my $dbh = shift; |
69
|
0
|
|
|
|
|
0
|
$pfm->_fetch_profile_data($dbh); |
70
|
2
|
|
|
|
|
17
|
}; |
71
|
|
|
|
|
|
|
|
72
|
2
|
50
|
|
|
|
10
|
unless ( exists $DBI::db::{DESTROY} ) { |
73
|
0
|
|
|
|
|
0
|
*DBI::db::DESTROY = $cb; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
2
|
|
|
|
|
8
|
$ORIGINAL_METHODS{disconnect} = \&DBI::db::disconnect; |
77
|
|
|
|
|
|
|
*DBI::db::disconnect = sub { |
78
|
0
|
|
|
0
|
|
0
|
my $dbh = shift; |
79
|
0
|
|
|
|
|
0
|
$cb->($dbh); |
80
|
0
|
|
|
|
|
0
|
$ORIGINAL_METHODS{disconnect}->($dbh); |
81
|
2
|
|
|
|
|
15
|
}; |
82
|
|
|
|
|
|
|
}; |
83
|
|
|
|
|
|
|
|
84
|
2
|
|
|
|
|
7
|
$self->is_started(1); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub profile_stop { |
88
|
2
|
|
|
2
|
1
|
24
|
my $self = shift; |
89
|
2
|
50
|
|
|
|
10
|
return unless ($self->is_started); |
90
|
2
|
|
|
|
|
11
|
my @db_handles = $self->_active_db_handles; |
91
|
|
|
|
|
|
|
|
92
|
2
|
|
|
|
|
17
|
delete $ENV{DBI_PROFILE}; |
93
|
2
|
|
|
|
|
10
|
delete $DBI::db::{DESTROY}; |
94
|
|
|
|
|
|
|
|
95
|
2
|
|
|
|
|
6
|
for my $dbh (@db_handles) { |
96
|
3
|
|
|
|
|
10
|
$self->_fetch_profile_data( $dbh ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
{ |
100
|
2
|
|
|
2
|
|
10
|
no warnings 'redefine'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1680
|
|
|
2
|
|
|
|
|
7
|
|
101
|
2
|
|
|
|
|
28
|
*DBI::db::disconnect = $ORIGINAL_METHODS{disconnect}; |
102
|
|
|
|
|
|
|
}; |
103
|
|
|
|
|
|
|
|
104
|
2
|
|
|
|
|
8
|
$self->is_started(0); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub data_formatted { |
108
|
2
|
|
|
2
|
1
|
54
|
my ($self, $format, @results) = @_; |
109
|
2
|
|
50
|
|
|
9
|
$format ||= '%{statement} : %{total}s / %{count} = %{avg}s avg (first %{first}s, min %{min}s, max %{max}s)'; |
110
|
2
|
100
|
|
|
|
12
|
@results = $self->data_structured unless ( @results > 0 ); |
111
|
2
|
|
|
|
|
4
|
my @formatted; |
112
|
|
|
|
|
|
|
|
113
|
2
|
|
|
|
|
5
|
for my $result ( @results ) { |
114
|
7
|
|
|
|
|
12
|
my $log = $format; |
115
|
7
|
50
|
|
|
|
46
|
$log =~ s/%\{?([\w_]+)\}?/(exists $result->{$1})?$result->{$1}:sprintf('%%{%s}',$1)/gex; |
|
7
|
|
|
|
|
45
|
|
116
|
7
|
|
|
|
|
21
|
push(@formatted, $log); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
2
|
50
|
|
|
|
21
|
return wantarray ? @formatted : join("\n", @formatted); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub data_structured { |
123
|
2
|
|
|
2
|
1
|
9
|
my $self = shift; |
124
|
2
|
|
|
|
|
29
|
my $data = $self->data; |
125
|
2
|
|
|
|
|
5
|
my @results; |
126
|
2
|
|
|
|
|
9
|
for my $dsn ( keys %$data ) { |
127
|
|
|
|
|
|
|
|
128
|
3
|
|
|
|
|
4
|
my $depth = 0; |
129
|
3
|
|
|
|
|
18
|
my $profile_data = $self->_data_structured_recursive( |
130
|
|
|
|
|
|
|
+{ dsn => $dsn }, $data->{$dsn}, \@results, $depth, |
131
|
|
|
|
|
|
|
); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
2
|
50
|
|
|
|
16
|
return wantarray ? @results : \@results; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub _fetch_profile_data { |
138
|
3
|
|
|
3
|
|
7
|
my ( $self, $dbh ) = @_; |
139
|
|
|
|
|
|
|
|
140
|
3
|
50
|
33
|
|
|
40
|
return unless ( exists $dbh->{Profile} && defined $dbh->{Profile}{Data} ); |
141
|
3
|
|
|
|
|
115
|
my $dsn = sprintf( 'dbi:%s:%s', $dbh->{Driver}{Name}, $dbh->{Name} ); |
142
|
3
|
50
|
|
|
|
14
|
return if ( exists $self->data->{$dsn} ); |
143
|
|
|
|
|
|
|
|
144
|
7
|
|
|
|
|
67
|
$self->data->{$dsn} |
145
|
|
|
|
|
|
|
= +{ |
146
|
10
|
|
|
|
|
16
|
map { $_ => $dbh->{Profile}{Data}{$_} } |
147
|
3
|
|
|
|
|
7
|
grep { length $_ } keys %{ $dbh->{Profile}{Data} } |
|
3
|
|
|
|
|
21
|
|
148
|
|
|
|
|
|
|
}; |
149
|
3
|
|
|
|
|
28
|
$dbh->{Profile}{Data} = undef; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub _active_db_handles { |
153
|
4
|
|
|
4
|
|
29
|
my %drhs = DBI->installed_drivers; |
154
|
4
|
|
|
|
|
33
|
my @handles; |
155
|
4
|
|
|
|
|
11
|
for my $drh ( values %drhs ) { |
156
|
4
|
|
|
|
|
6
|
for my $dbh ( grep { $_->{Active} } @{ $drh->{ChildHandles} } ) { |
|
8
|
|
|
|
|
87
|
|
|
4
|
|
|
|
|
44
|
|
157
|
6
|
|
|
|
|
95
|
push( @handles, $dbh ); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
4
|
50
|
|
|
|
22
|
wantarray ? @handles : \@handles; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub _data_structured_recursive { |
164
|
22
|
|
|
22
|
|
37
|
my ($self, $default, $data, $results, $depth) = @_; |
165
|
|
|
|
|
|
|
|
166
|
22
|
100
|
|
|
|
27
|
if ( @{$self->path} == $depth ) { |
|
22
|
|
|
|
|
42
|
|
167
|
14
|
|
|
|
|
51
|
my %profile_data = %$default; |
168
|
14
|
|
|
|
|
97
|
@profile_data{qw/count total first min max start end/} = @$data; |
169
|
14
|
|
|
|
|
45
|
$profile_data{avg} = $profile_data{total} / $profile_data{count}; |
170
|
|
|
|
|
|
|
|
171
|
14
|
|
|
|
|
27
|
push( @$results, \%profile_data ); |
172
|
14
|
|
|
|
|
60
|
return; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
8
|
|
|
|
|
34
|
my $sp_const = lcfirst(substr($self->path->[$depth], 1)); |
176
|
8
|
|
|
|
|
32
|
$sp_const =~ s/([A-Z])/'_'.lc($1)/gex; |
|
5
|
|
|
|
|
23
|
|
177
|
8
|
|
|
|
|
13
|
$sp_const =~ s/\~/_/g; |
178
|
|
|
|
|
|
|
|
179
|
8
|
|
|
|
|
25
|
for my $key ( keys %$data ) { |
180
|
19
|
|
|
|
|
34
|
$default->{$sp_const} = $key; |
181
|
19
|
|
|
|
|
55
|
$self->_data_structured_recursive( $default, $data->{$key}, $results, $depth + 1 ); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
1; |
186
|
|
|
|
|
|
|
__END__ |