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 and add_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 and want_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 the owner 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 on owner 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:

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.