[Jifty-commit] r4133 - in jifty/trunk: lib/Jifty lib/Jifty/Plugin
lib/Jifty/Plugin/LeakDetector
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Tue Sep 18 16:07:19 EDT 2007
Author: sartak
Date: Tue Sep 18 16:07:18 2007
New Revision: 4133
Added:
jifty/trunk/lib/Jifty/Plugin/LeakDetector/
jifty/trunk/lib/Jifty/Plugin/LeakDetector.pm
jifty/trunk/lib/Jifty/Plugin/LeakDetector/Dispatcher.pm
jifty/trunk/lib/Jifty/Plugin/LeakDetector/View.pm
Modified:
jifty/trunk/ (props changed)
jifty/trunk/lib/Jifty/Handler.pm
Log:
r42785 at onn: sartak | 2007-09-18 16:06:26 -0400
Add new LeakDetector plugin. It kinda sorta works :)
Modified: jifty/trunk/lib/Jifty/Handler.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Handler.pm (original)
+++ jifty/trunk/lib/Jifty/Handler.pm Tue Sep 18 16:07:18 2007
@@ -27,6 +27,7 @@
use base qw/Class::Accessor::Fast/;
use Module::Refresh ();
use Jifty::View::Declare::Handler ();
+use Class::Trigger;
BEGIN {
# Creating a new CGI object breaks FastCGI in all sorts of painful
@@ -191,35 +192,44 @@
@_
);
- # Build a new stash for the life of this request
- $self->stash( {} );
- local $Jifty::WEB = Jifty::Web->new();
-
- if ( Jifty->config->framework('DevelMode') ) {
- Module::Refresh->refresh;
- Jifty::I18N->refresh;
- }
+ $self->call_trigger('before_request', $args{cgi});
- Jifty::I18N->get_language_handle;
+ # this is scoped deeper because we want to make sure everything is cleaned
+ # up for the LeakDetector plugin. I tried putting the triggers in the
+ # method (Jifty::Server::handle_request) that calls this, but Jifty::Server
+ # isn't being loaded in time
+ {
+ # Build a new stash for the life of this request
+ $self->stash( {} );
+ local $Jifty::WEB = Jifty::Web->new();
+
+ if ( Jifty->config->framework('DevelMode') ) {
+ Module::Refresh->refresh;
+ Jifty::I18N->refresh;
+ }
- $self->cgi( $args{cgi} );
- $self->apache( HTML::Mason::FakeApache->new( cgi => $self->cgi ) );
+ Jifty::I18N->get_language_handle;
- Jifty->web->request( Jifty::Request->new()->fill( $self->cgi ) );
- Jifty->web->response( Jifty::Response->new );
- Jifty->api->reset;
- for ( Jifty->plugins ) {
- $_->new_request;
- }
- Jifty->log->debug( "Received request for " . Jifty->web->request->path );
- Jifty->web->setup_session;
+ $self->cgi( $args{cgi} );
+ $self->apache( HTML::Mason::FakeApache->new( cgi => $self->cgi ) );
- # Return from the continuation if need be
- Jifty->web->request->return_from_continuation;
- Jifty->web->session->set_cookie;
- $self->dispatcher->handle_request();
- $self->cleanup_request();
+ Jifty->web->request( Jifty::Request->new()->fill( $self->cgi ) );
+ Jifty->web->response( Jifty::Response->new );
+ Jifty->api->reset;
+ for ( Jifty->plugins ) {
+ $_->new_request;
+ }
+ Jifty->log->debug( "Received request for " . Jifty->web->request->path );
+ Jifty->web->setup_session;
+
+ # Return from the continuation if need be
+ Jifty->web->request->return_from_continuation;
+ Jifty->web->session->set_cookie;
+ $self->dispatcher->handle_request();
+ $self->cleanup_request();
+ }
+ $self->call_trigger('after_request', $args{cgi});
}
=head2 cleanup_request
Added: jifty/trunk/lib/Jifty/Plugin/LeakDetector.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/LeakDetector.pm Tue Sep 18 16:07:18 2007
@@ -0,0 +1,101 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::LeakDetector;
+use base qw/Jifty::Plugin Class::Data::Inheritable/;
+use Data::Dumper;
+use Devel::Events::Handler::ObjectTracker;
+use Devel::Events::Generator::Objects;
+use Devel::Size 'total_size';
+
+our $VERSION = 0.01;
+
+__PACKAGE__->mk_accessors(qw(tracker generator));
+our @requests;
+
+my $empty_array = total_size([]);
+
+sub init {
+ my $self = shift;
+ return if $self->_pre_init;
+
+ Jifty::Handler->add_trigger(
+ before_request => sub { $self->before_request(@_) }
+ );
+
+ Jifty::Handler->add_trigger(
+ after_request => sub { $self->after_request(@_) }
+ );
+}
+
+sub before_request
+{
+ my $self = shift;
+ $self->tracker(Devel::Events::Handler::ObjectTracker->new());
+ $self->generator(
+ Devel::Events::Generator::Objects->new(handler => $self->tracker)
+ );
+
+ $self->generator->enable();
+}
+
+sub after_request
+{
+ my $self = shift;
+ my $handler = shift;
+ my $cgi = shift;
+
+ $self->generator->disable();
+
+ my $leaked = $self->tracker->live_objects;
+ my $leaks = keys %$leaked;
+
+ # XXX: Devel::Size seems to segfault Jifty at END time
+ my $size = total_size([ keys %$leaked ]) - $empty_array;
+
+ push @requests, {
+ url => $cgi->url(-absolute=>1,-path_info=>1),
+ size => $size,
+ objects => Dumper($leaked),
+ time => scalar gmtime,
+ leaks => $leaks,
+ };
+
+ $self->generator(undef);
+ $self->tracker(undef);
+}
+
+=head1 NAME
+
+Jifty::Plugin::LeakDetector
+
+=head1 DESCRIPTION
+
+Memory leak detection and reporting for your Jifty app
+
+=head1 USAGE
+
+Add the following to your site_config.yml
+
+ framework:
+ Plugins:
+ - LeakDetector: {}
+
+This makes the following URLs available:
+
+View any URL of your app and catch any leaked objects
+
+ http://your.app/leak/user/12
+
+View the top-level leak report (how much each request has leaked)
+
+ http://your.app/leaks
+
+View an individual request's detailed leak report (which objects were leaked)
+
+ http://your.app/leaks/3
+
+=cut
+
+1;
+
Added: jifty/trunk/lib/Jifty/Plugin/LeakDetector/Dispatcher.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/LeakDetector/Dispatcher.pm Tue Sep 18 16:07:18 2007
@@ -0,0 +1,22 @@
+package Jifty::Plugin::LeakDetector::Dispatcher;
+use warnings;
+use strict;
+
+use Jifty::Dispatcher -base;
+
+# http://your.app/leaks -- display full leak report
+on 'leaks' => run {
+ show "leaks/all";
+};
+
+# http://your.app/leaks/xxx -- display leak report for request ID xxx
+on 'leaks/#' => run {
+ my $leak = $Jifty::Plugin::LeakDetector::requests[$1]
+ or abort(404);
+ set leak => $leak;
+ set leakid => $1;
+ show "leaks/one";
+};
+
+1;
+
Added: jifty/trunk/lib/Jifty/Plugin/LeakDetector/View.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin/LeakDetector/View.pm Tue Sep 18 16:07:18 2007
@@ -0,0 +1,82 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::LeakDetector::View;
+use Jifty::View::Declare -base;
+
+=head1 NAME
+
+Jifty::Plugin::LeakDetector::View - Views for memory leak detection
+
+=head1 TEMPLATES
+
+=head2 leaks/chart
+
+This shows a chart using L<Chart>. It expects to find the arguments in the C<args> parameter, which is setup for it in L<Jifty::Plugin::Chart::Dispatcher>.
+
+This will output a PNG file unless there is an error building the chart.
+
+=cut
+
+template 'leaks/all' => sub {
+ html {
+ body {
+ table {
+ row {
+ th { "ID" }
+ th { "Leaks" }
+ th { "Bytes leaked" }
+ th { "Time" }
+ th { "URL" }
+ };
+
+ my $id = 0;
+ for (@Jifty::Plugin::LeakDetector::requests)
+ {
+ row {
+ cell { a { attr { href => "leaks/$id" } $id } }
+ cell { $_->{leaks} }
+ cell { $_->{size} }
+ cell { $_->{time} }
+ cell { $_->{url} }
+ };
+ ++$id;
+ }
+ }
+ }
+ }
+};
+
+template 'leaks/one' => sub {
+ my $leak = get 'leak';
+ my $id = get 'leakid';
+
+ html {
+ body {
+ h1 { "Leaks from Request $id" }
+ ul {
+ li { "URL: $leak->{url}" }
+ li { "Time: $leak->{time}" }
+ li { "Objects leaked: $leak->{leaks}" }
+ li { "Total memory leaked: $leak->{size}" }
+ }
+ p { a { attr { href => "/leaks" } "Table of Contents" } }
+ hr {}
+ pre { $leak->{objects} }
+ }
+ }
+};
+
+=head1 SEE ALSO
+
+L<Jifty::Plugin::LeakDetector::Dispatcher>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2007 Best Practical Solutions
+
+This is free software and may be modified and distributed under the same terms as Perl itself.
+
+=cut
+
+1;
More information about the Jifty-commit
mailing list