NAME
Guard::Stats - Create guard objects and gather averall usage statistics from them.
SYNOPSIS
Suppose we have a long-running application making heavy use of closures, and need to monitor the number of executed, not executed, and gone subrefs.
So we put a guard into each closure to update the statistics:
# in initial section
use Guard::Stats;
my $stat = Guard::Stats->new;
# when running
my $guard = $stat->guard;
my $callback = sub {
$guard->finish("taken route 1");
# now do useful stuff
};
# ... do whatever we need and call $callback eventually
# in diagnostic procedures triggered by an external event
my $data = $stat->get_stat;
warn "$data->{running} callbacks still waiting to be executed";
Of course, alive/dead counts of any objects (not only sub refs) may be monitored in a similar way.
DESCRIPTION
A guard is a special object that does something useful in destructor, typically freeing a resource or lock. These guards however don't free anything. Instead, they call home to keep their master (YOU) informed.
The classes
Guard::Stats is a long-lived object that spawns guards and gathers statistical information.
Its public methods are guard() and various statistic getters.
Guard::Stats::Instance is the guard. When it is DESTROYed, it signals the stat object which created it.
Its public methods are end( [$result] ) and is_done().
The counters
When a guard is created, the total
counter increases. When it's detroyed, dead
counter increases. alive
= total
- dead
is the number of guards that still exist.
Additionally, guards implement a end()
method which indicates that the action associates with the guard is complete. Typically a guard should be destroyed soon afterwards. The guards for which neither DESTROY nor end were called are considered running
(this is used in on_level
).
The full matrix or DESTROY()/end() combinations is as follows:
DESTROY: * 0 1
end:* total+ alive dead
end:0 ? running broken+
end:1 done+ zombie complete+
A "+" marks values directly measured by Guard::Stats. They all happen to be monotonous. Other statistics are derived from these.
Note that counter showing end() NOT called regardless of DESTROY() does not have a meaningful name (yet?).
Running count callback
Whenever number of guards in the running
state passes given level, a function may be called. This can be used to monitor load, prevent uncontrolled memory usage growth, etc.
See on_level
below.
METHODS
new (%options)
%options may include:
time_stat - an object or class to store time statistics. The class should support
new
andadd_data( $number )
operations for this to work. Suitable candidates are Statistics::Descriptive::Sparse and Statistics::Descriptive::LogScale (both have sublinear memory usage).guard_class - packge name to override default guard class. See "overriding guard class" below.
Creating and using guards
guard( %options )
Create a guard object. All options will be forwarded to the guard's new() "as is", except for owner
and want_time
which are reserved.
As of current, the built-in guard class supports no other options, so supplying a hash is useless unless the guard class is redefined. See "overriding guard class" below. See also Guard::Stats::Instance for the detailed description of default guard class.
$guard->end( [ $result ] )
Signal that action associated with the guard is over. If $result is provided, it is saved in a special hash (see get_stat_result() below). This can be used e.g. to measure the number of successful/unsuccessful actions.
Calling end() a second time on the same guard will result in a warning, and change no counters.
$guard->is_done
Tell whether end() was ever called on the guard.
undef $guard
The guard's DESTROY() method will signal stats object that guard is gone, and whether it was finished before destruction.
Statistics
The following getters represent numbers of guards in respective states:
total() - all guards ever created;
dead() - DESTROY was called;
alive() - DESTROY was NOT called;
done() - end() was called;
complete() - both end() and DESTROY were called;
zombie() - end() was called, but not DESTROY;
running() - neither end() nor DESTROY called;
broken() - number of guards for which DESTROY was called, but NOT end().
Growing broken and/or zombie counts usually indicate something went wrong.
get_stat
Get all statistics as a single hashref.
get_stat_result
Provide statistics on agruments provided to end() method.
get_stat_time
Return time statistics object, if any.
on_level( $n, CODEREF )
Set on_level callback. If $n is positive, run CODEREF->($n) when number of running guard instances is increased to $n.
If $n is negative or 0, run CODEREF->($n) when it is decreased to $n.
CAVEAT: Normally, CODEREF should not die as it may be called within a destructor.
Overriding guard class
Custom guard classes may be used with Guard::Stats.
A guard_class supplied to new() must exhibit the following properties:
It must have a new() method, accepting a hash.
owner
=object andwant_time
=0|1 parameters MUST be acceptable.The object returned by new() MUST have end(), is_done() and DESTROY() methods.
end() method MUST accept one or zero parameters.
end() method MUST call
add_stat_end()
with one or zero parameters on theowner
object discussed above when called for the first time.end() method MUST do nothing and emit a warning if called more than once. It MAY die then.
is_done() method MUST return true if end() was ever called, and false otherwise.
DESTROY() method MUST call
add_stat_destroy
method onowner
object with one boolean parameter equivalent to is_done() return value.end() and DESTROY() methods MAY call add_stat_time() method on the
owner
object with one numeric parameter. Each guard object MUST call add_stat_time only once.
See example/check_my_guard_class.t
.
Guard instance callbacks
The following methods are called by the guard object in different stages of its life. They should NOT be called directly (unless there's a need to fool the stats object) and are only described for people who want to extend the guard object class.
add_stat_end( [ $result ] )
add_stat_destroy( $end_was_called )
add_stat_time( $time )
AUTHOR
Konstantin S. Uvarin, <khedin at gmail.com>
BUGS
Please report any bugs or feature requests to bug-guard-stat at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Guard-Stats. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Guard::Stats
You can also look for information at:
Github:
RT: CPAN's request tracker (report bugs here)
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
ACKNOWLEDGEMENTS
This module was initially written as part of my day job at http://sms-online.com.
Vadim Vlasov was the first user of this package, and proposed the zombie
counter.
SEE ALSO
AnyEvent - This module was created for monitoring callback usage in AnyEvent-driven application. However, it allows for a broadeer usage.
Twiggy - A single-threaded web-server handling multiple simultaneous requests is probably the most natural environment for callback counting. See example/under_twiggy.psgi
in this distribution.
Devel::Leak::Cb - Another module for finding leaked callbacks.
LICENSE AND COPYRIGHT
Copyright 2013 Konstantin S. Uvarin.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.