The revert 8494142c incorrectly killed 4d93345c, reinstating
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / Statistics.pm
1 package DBIx::Class::Storage::Statistics;
2
3 use strict;
4 use warnings;
5
6 use DBIx::Class::_Util qw(sigwarn_silencer qsub);
7 use IO::Handle ();
8
9 # DO NOT edit away without talking to riba first, he will just put it back
10 # BEGIN pre-Moo2 import block
11 BEGIN {
12   my $initial_fatal_bits = (${^WARNING_BITS}||'') & $warnings::DeadBits{all};
13
14   local $ENV{PERL_STRICTURES_EXTRA} = 0;
15   # load all of these now, so that lazy-loading does not escape
16   # the current PERL_STRICTURES_EXTRA setting
17   require Sub::Quote;
18   require Sub::Defer;
19   require Moo;
20   require Moo::Object;
21   require Method::Generate::Accessor;
22   require Method::Generate::Constructor;
23
24   Moo->import;
25   ${^WARNING_BITS} &= ( $initial_fatal_bits | ~ $warnings::DeadBits{all} );
26 }
27 # END pre-Moo2 import block
28
29 extends 'DBIx::Class';
30 use namespace::clean;
31
32 =head1 NAME
33
34 DBIx::Class::Storage::Statistics - SQL Statistics
35
36 =head1 SYNOPSIS
37
38 =head1 DESCRIPTION
39
40 This class is called by DBIx::Class::Storage::DBI as a means of collecting
41 statistics on its actions.  Using this class alone merely prints the SQL
42 executed, the fact that it completes and begin/end notification for
43 transactions.
44
45 To really use this class you should subclass it and create your own method
46 for collecting the statistics as discussed in L<DBIx::Class::Manual::Cookbook>.
47
48 =head1 METHODS
49
50 =head2 new
51
52 Returns a new L<DBIx::Class::Storage::Statistics> object.
53
54 =head2 debugfh
55
56 Sets or retrieves the filehandle used for trace/debug output.  This should
57 be an L<IO::Handle> compatible object (only the
58 L<< print|IO::Handle/METHODS >> method is used). By
59 default it is initially set to STDERR - although see discussion of the
60 L<DBIC_TRACE|DBIx::Class::Storage/DBIC_TRACE> environment variable.
61
62 Invoked as a getter it will lazily open a filehandle and set it to
63 L<< autoflush|perlvar/HANDLE->autoflush( EXPR ) >> (if one is not
64 already set).
65
66 =cut
67
68 # FIXME - there ought to be a way to fold this into _debugfh itself
69 # having the undef re-trigger the builder (or better yet a default
70 # which can be folded in as a qsub)
71 sub debugfh {
72   my $self = shift;
73
74   return $self->_debugfh(@_) if @_;
75   $self->_debugfh || $self->_build_debugfh;
76 }
77
78 has _debugfh => (
79   is => 'rw',
80   lazy => 1,
81   trigger => qsub '$_[0]->_defaulted_to_stderr(undef)',
82   builder => '_build_debugfh',
83 );
84
85 sub _build_debugfh {
86   my $fh;
87
88   my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} || $ENV{DBIC_TRACE};
89
90   if (defined($debug_env) and ($debug_env =~ /=(.+)$/)) {
91     open ($fh, '>>', $1)
92       or die("Cannot open trace file $1: $!\n");
93   }
94   else {
95     open ($fh, '>&STDERR')
96       or die("Duplication of STDERR for debug output failed (perhaps your STDERR is closed?): $!\n");
97     $_[0]->_defaulted_to_stderr(1);
98   }
99
100   $fh->autoflush(1);
101
102   $fh;
103 }
104
105 has [qw(_defaulted_to_stderr silence callback)] => (
106   is => 'rw',
107 );
108
109 =head2 print
110
111 Prints the specified string to our debugging filehandle.  Provided to save our
112 methods the worry of how to display the message.
113
114 =cut
115 sub print {
116   my ($self, $msg) = @_;
117
118   return if $self->silence;
119
120   my $fh = $self->debugfh;
121
122   # not using 'no warnings' here because all of this can change at runtime
123   local $SIG{__WARN__} = sigwarn_silencer(qr/^Wide character in print/)
124     if $self->_defaulted_to_stderr;
125
126   $fh->print($msg);
127 }
128
129 =head2 silence
130
131 Turn off all output if set to true.
132
133 =head2 txn_begin
134
135 Called when a transaction begins.
136
137 =cut
138 sub txn_begin {
139   my $self = shift;
140
141   return if $self->callback;
142
143   $self->print("BEGIN WORK\n");
144 }
145
146 =head2 txn_rollback
147
148 Called when a transaction is rolled back.
149
150 =cut
151 sub txn_rollback {
152   my $self = shift;
153
154   return if $self->callback;
155
156   $self->print("ROLLBACK\n");
157 }
158
159 =head2 txn_commit
160
161 Called when a transaction is committed.
162
163 =cut
164 sub txn_commit {
165   my $self = shift;
166
167   return if $self->callback;
168
169   $self->print("COMMIT\n");
170 }
171
172 =head2 svp_begin
173
174 Called when a savepoint is created.
175
176 =cut
177 sub svp_begin {
178   my ($self, $name) = @_;
179
180   return if $self->callback;
181
182   $self->print("SAVEPOINT $name\n");
183 }
184
185 =head2 svp_release
186
187 Called when a savepoint is released.
188
189 =cut
190 sub svp_release {
191   my ($self, $name) = @_;
192
193   return if $self->callback;
194
195   $self->print("RELEASE SAVEPOINT $name\n");
196 }
197
198 =head2 svp_rollback
199
200 Called when rolling back to a savepoint.
201
202 =cut
203 sub svp_rollback {
204   my ($self, $name) = @_;
205
206   return if $self->callback;
207
208   $self->print("ROLLBACK TO SAVEPOINT $name\n");
209 }
210
211 =head2 query_start
212
213 Called before a query is executed.  The first argument is the SQL string being
214 executed and subsequent arguments are the parameters used for the query.
215
216 =cut
217 sub query_start {
218   my ($self, $string, @bind) = @_;
219
220   my $message = "$string: ".join(', ', @bind)."\n";
221
222   if(defined($self->callback)) {
223     $string =~ m/^(\w+)/;
224     $self->callback->($1, $message);
225     return;
226   }
227
228   $self->print($message);
229 }
230
231 =head2 query_end
232
233 Called when a query finishes executing.  Has the same arguments as query_start.
234
235 =cut
236 sub query_end {
237   my ($self, $string) = @_;
238 }
239
240 1;
241
242 =head1 AUTHOR AND CONTRIBUTORS
243
244 See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
245
246 =head1 LICENSE
247
248 You may distribute this code under the same terms as Perl itself.
249
250 =cut