File Coverage

blib/lib/DBIx/Class/QueryLog.pm
Criterion Covered Total %
statement 64 73 87.6
branch 13 18 72.2
condition n/a
subroutine 16 17 94.1
pod 10 10 100.0
total 103 118 87.2


line stmt bran cond sub pod time code
1             package DBIx::Class::QueryLog;
2             $DBIx::Class::QueryLog::VERSION = '1.005001';
3             # ABSTRACT: Log queries for later analysis.
4              
5 5     5   315181 use Moo;
  5         35777  
  5         22  
6 5     5   6962 use Types::Standard qw( Str Maybe ArrayRef Bool InstanceOf );
  5         301378  
  5         44  
7              
8             has bucket => (
9             is => 'rw',
10             isa => Str,
11             default => sub { 'default' }
12             );
13              
14             has current_query => (
15             is => 'rw',
16             isa => Maybe[InstanceOf['DBIx::Class::QueryLog::Query']]
17             );
18              
19             has current_transaction => (
20             is => 'rw',
21             isa => Maybe[InstanceOf['DBIx::Class::QueryLog::Transaction']]
22             );
23              
24             has log => (
25             traits => [qw(Array)],
26             is => 'rw',
27             isa => ArrayRef,
28             default => sub { [] },
29             );
30              
31             sub add_to_log { push @{shift->log}, @_ }
32 1     1 1 34 sub reset { shift->log([]) }
33              
34             has passthrough => (
35             is => 'rw',
36             isa => Bool,
37             default => 0
38             );
39              
40             has __time => (
41             is => 'ro',
42             default => sub { \&Time::HiRes::time },
43             );
44              
45 8036     8036   120007 sub _time { shift->__time->() }
46              
47             before 'add_to_log' => sub {
48             my ($self, $thing) = @_;
49              
50             $thing->bucket($self->bucket);
51             };
52              
53 5     5   6183 use base qw(DBIx::Class::Storage::Statistics);
  5         12  
  5         1919  
54              
55 5     5   279405 use Time::HiRes;
  5         5597  
  5         18  
56              
57 5     5   2426 use DBIx::Class::QueryLog::Query;
  5         39  
  5         138  
58 5     5   1776 use DBIx::Class::QueryLog::Transaction;
  5         14  
  5         2398  
59              
60             sub time_elapsed {
61 0     0 1 0 my $self = shift;
62              
63 0         0 my $total = 0;
64 0         0 foreach my $t (@{ $self->log }) {
  0         0  
65 0         0 $total += $t->time_elapsed;
66             }
67              
68 0         0 return $total;
69             }
70              
71             sub count {
72 2002     2002 1 2776 my $self = shift;
73              
74 2002         2297 my $total = 0;
75 2002         2226 foreach my $t (@{ $self->log }) {
  2002         26131  
76 1003002         1385767 $total += $t->count;
77             }
78              
79 2002         10138 return $total;
80             }
81              
82              
83             sub txn_begin {
84 5     5 1 2630 my $self = shift;
85              
86 5 100       81 $self->next::method(@_) if $self->passthrough;
87 5         137 $self->current_transaction(
88             $self->transaction_class()->new({
89             start_time => $self->_time,
90             })
91             );
92             }
93              
94              
95             sub txn_commit {
96 4     4 1 553 my $self = shift;
97              
98 4 50       62 $self->next::method(@_) if $self->passthrough;
99 4 50       73 if(defined($self->current_transaction)) {
100 4         70 my $txn = $self->current_transaction;
101 4         23 $txn->end_time($self->_time);
102 4         161 $txn->committed(1);
103 4         154 $txn->rolledback(0);
104 4         191 $self->add_to_log($txn);
105 4         69 $self->current_transaction(undef);
106             } else {
107 0         0 warn('Unknown transaction committed.')
108             }
109             }
110              
111              
112             sub txn_rollback {
113 1     1 1 20 my $self = shift;
114              
115 1 50       14 $self->next::method(@_) if $self->passthrough;
116 1 50       78 if(defined($self->current_transaction)) {
117 1         18 my $txn = $self->current_transaction;
118 1         7 $txn->end_time($self->_time);
119 1         34 $txn->committed(0);
120 1         32 $txn->rolledback(1);
121 1         33 $self->add_to_log($txn);
122 1         17 $self->current_transaction(undef);
123             } else {
124 0         0 warn('Unknown transaction committed.')
125             }
126             }
127              
128              
129             sub query_start {
130 4013     4013 1 16928 my $self = shift;
131 4013         5204 my $sql = shift;
132 4013         5829 my @params = @_;
133              
134 4013 100       61978 $self->next::method($sql, @params) if $self->passthrough;
135 4013         22991 $self->current_query(
136             $self->query_class()->new({
137             start_time => $self->_time,
138             sql => $sql,
139             params => \@params,
140             })
141             );
142             }
143              
144              
145             sub query_end {
146 4013     4013 1 41083 my $self = shift;
147              
148 4013 100       53928 $self->next::method(@_) if $self->passthrough;
149 4013 50       63975 if(defined($self->current_query)) {
150 4013         61363 my $q = $self->current_query;
151 4013         19133 $q->end_time($self->_time);
152 4013         121132 $q->bucket($self->bucket);
153 4013 100       183525 if(defined($self->current_transaction)) {
154 7         115 $self->current_transaction->add_to_queries($q);
155             } else {
156 4006         72426 $self->add_to_log($q)
157             }
158 4013         64585 $self->current_query(undef);
159             } else {
160 0         0 warn('Completed unknown query.');
161             }
162             }
163              
164              
165 4013     4013 1 7579 sub query_class { 'DBIx::Class::QueryLog::Query' }
166              
167 5     5 1 16 sub transaction_class { 'DBIx::Class::QueryLog::Transaction' }
168              
169              
170             1;
171              
172             __END__
173              
174             =pod
175              
176             =encoding UTF-8
177              
178             =head1 NAME
179              
180             DBIx::Class::QueryLog - Log queries for later analysis.
181              
182             =head1 VERSION
183              
184             version 1.005001
185              
186             =head1 SYNOPSIS
187              
188             DBIx::Class::QueryLog 'logs' each transaction and query executed so you can
189             analyze what happened in the 'session'. It must be installed as the debugobj
190             in DBIx::Class:
191              
192             use DBIx::Class::QueryLog::NotifyOnMax;
193             use DBIx::Class::QueryLog::Analyzer;
194              
195             my $schema = ... # Get your schema!
196             my $ql = DBIx::Class::QueryLog::NotifyOnMax->new(
197             max_count => 100,
198             );
199             $schema->storage->debugobj($ql);
200             $schema->storage->debug(1);
201             ... # do some stuff!
202             my $ana = DBIx::Class::QueryLog::Analyzer->new({ querylog => $ql });
203             my @queries = $ana->get_sorted_queries;
204              
205             Every transaction and query executed will have a corresponding Transaction
206             and Query object stored in order of execution, like so:
207              
208             Query
209             Query
210             Transaction
211             Query
212              
213             This array can be retrieved with the log method. Queries executed inside
214             a transaction are stored inside their Transaction object, not inside the
215             QueryLog directly.
216              
217             See L<DBIx::Class::QueryLog::Analyzer> for options on digesting the results
218             of a QueryLog session.
219              
220             If you wish to have the QueryLog collecting results, and the normal trace
221             output of SQL queries from DBIx::Class, then set C<passthrough> to 1
222              
223             $ql->passthrough(1);
224              
225             Note that above the example uses L<DBIx::Class::QueryLog::NotifyOnMax> instead
226             of the vanilla C<DBIx::Class::QueryLog>, this is simply to encourage users to
227             use that and hopefully avoid leaks.
228              
229             =head1 BUCKETS
230              
231             Sometimes you want to break your analysis down into stages. To segregate the
232             queries and transactions, simply set the bucket and run some queries:
233              
234             $ql->bucket('selects');
235             $schema->resultset('Foo')->find(..);
236             # Some queries
237             $ql->bucket('updates');
238             $foo->update({ name => 'Gorch' });
239             $ql->bucket('something else);
240             ...
241              
242             Any time a query or transaction is completed the QueryLog's current bucket
243             will be copied into it so that the Analyzer can later use it. See
244             the get_totaled_queries method and it's optional parameter.
245              
246             =head1 METHODS
247              
248             =head2 new
249              
250             Create a new DBIx::Class::QueryLog.
251              
252             =head2 bucket
253              
254             Set the current bucket for this QueryLog. This bucket will be copied to any
255             transactions or queries that finish.
256              
257             =head2 time_elapsed
258              
259             Returns the total time elapsed for ALL transactions and queries in this log.
260              
261             =head2 count
262              
263             Returns the number of queries executed in this QueryLog
264              
265             =head2 reset
266              
267             Reset this QueryLog by removing all transcations and queries.
268              
269             =head2 add_to_log
270              
271             Add this provided Transaction or Query to the log.
272              
273             =head2 txn_begin
274              
275             Called by DBIx::Class when a transaction is begun.
276              
277             =head2 txn_commit
278              
279             Called by DBIx::Class when a transaction is committed.
280              
281             =head2 txn_rollback
282              
283             Called by DBIx::Class when a transaction is rolled back.
284              
285             =head2 query_start
286              
287             Called by DBIx::Class when a query is begun.
288              
289             =head2 query_end
290              
291             Called by DBIx::Class when a query is completed.
292              
293             =head2 query_class
294              
295             Returns the name of the class to use for storing queries, by default
296             C<DBIx::Class::QueryLog::Query>. If you subclass C<DBIx::Class::QueryLog>,
297             you may wish to override this. Whatever you override it to must be a
298             subclass of DBIx::Class::QueryLog::Query.
299              
300             =head2 transaction_class
301              
302             As query_class but for the class for storing transactions. Defaults to
303             C<DBIx::Class::QueryLog::Transaction>.
304              
305             =head2 SEE ALSO
306              
307             =over
308              
309             =item * L<DBIx::Class::QueryLog::NotifyOnMax>
310              
311             =item * L<DBIx::Class::QueryLog::Tee>
312              
313             =item * L<DBIx::Class::QueryLog::Conditional>
314              
315             =back
316              
317             =head1 AUTHORS
318              
319             =over 4
320              
321             =item *
322              
323             Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
324              
325             =item *
326              
327             Cory G Watson <gphat at cpan.org>
328              
329             =back
330              
331             =head1 COPYRIGHT AND LICENSE
332              
333             This software is copyright (c) 2015 by Cory G Watson <gphat at cpan.org>.
334              
335             This is free software; you can redistribute it and/or modify it under
336             the same terms as the Perl 5 programming language system itself.
337              
338             =cut