This document is part of WebTools Help located at http://docs.proscriptum.com

Errors::Errors - Module for error/die/exit/abort proceeding.

  Errors module allows you to handle and proceed a large list of errors/signals

Complete list of methods are shown below:


attach :: content :: detach :: die :: error :: exit :: install :: header :: print :: uninstall


SYNOPSIS

use Errors::Errors;

use strict;

my $obj = Errors::Errors->new();

$obj->content(0);
$obj->header();
$obj->attach('xreader'); # Attach sub object (sobject) for error of type 'xreader'.
$obj->attach('myown'); # Attach sub object for error of type 'myown'.

my $hash = {
    name=>'July',
    born_year=>'81',
};

$obj->attach_object('xreader',$hash); # Hash ref or object

$obj->install('onTerm',\&custom); # Install sub for term event.
$obj->install('onError',\&anysub,'xreader');
# Install sub for xreader sobject which will be called when error occure.
$obj->install('onExit',\&leave); # Install sub for exit event.
$obj->install('onTerm',\&custom,'myown'); # Install additional term sub for 'myown' sobject.

$obj->error(7,'xreader'); # Set error '7' for 'xreader' sobject and force execution of error chain.

#my $h = $obj->fetch_object('xreader');  # Fetch attached object from xreader.
#$obj->print($h->{name}."\n");


$obj->uninstall('onError','xreader'); # Remove 'xreader' sub from 'error' chain.

$obj->detach_object('xreader'); # Remove attached object from xreader.
$obj->detach('xreader'); # Remove xreader (and attached objects).

$obj->install('onTimeOut',\&timeout); # Install timeout sub routine.
eval 'alarm(1);'; # Force alarm after 1s
sleep(2); # Wait 2 sec, so alarm will be activeted and 'timeout' chain will be turned.
#Note: Press CTRL+C to active 'INT' signal ('onTerm' event) before time to flow out.

#$obj->exit(); # Force exit of program.
#$obj->die(); # Force die of program.


#By default script close 'normally', so 'destroy' chain will be executed.
sub custom {
  my $obj = shift; # 'Errors' object
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'term'
  my $name = $in{'name'}; # Custom error name
  my $sig = $in{'signal'}; # Invoked signal (term,quit,pipe...)
  # ...blah...blah...
  print "Custom($name)\n";
}
sub leave {
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'exit','die','destroy'
  my $err = $in{'error'}; # Error value
  my $name = $in{'name'}; # Custom error name
  my $params = $in{'params'}; # Additional parameters (ref to @)
  my @params = @$params;
  # ...blah...blah...
  print "$type\n";
}
sub timeout
{
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'term'
  my $name = $in{'name'}; # Custom error name
  my $sig = $in{'signal'}; # Invoked signal: 'alrm'
  # ...blah...blah...
  print "Timeout\n";
}
sub anysub {
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'error'
  my $err = $in{'error'}; # Error message
  my $name = $in{'name'}; # Custom error name
  my $to = $in{'to'}; # Message is sent "to"
  my $params = $in{'params'}; # Additional parameters (ref to @)
  my @params = @$params;

  if($name eq $to && $to eq 'xreader')
  {
    $obj->print ("Error in Xreader!!!\n"); # If error is raised in 'xreader'
    my $h = $obj->fetch_object('xreader');
    $obj->print ($h->{born_year}."\n");
  }
 else
  {
   $obj->print ("Error in ... I don't know ;-)!!!\n");
  }
}

[Top]


Install

As any other 'CPAN' module you just have to do follow simple steps to complete installation:

tar -zxvf Errors-1.02.tar.gz
cd Errors-1.02
perl Makefile.PL
make
make test
make install
make clean


Note: In WebTools engine this module is already installed!

[Top]


Getting Started

  First question is: Why I have to use Errors module in my Perl program?
In large projects you have to use many libraries, modules and of course you have to catch all errors in, also in some cases you need to make some finalize procedures at the end of your scripts. To do that you may need to write subs for different errors, to write code for interrupts/events/signals but what structure you use? None? Huh! You just write code and grubby you program! It's a disgrace.
 This module offer to you and your scripts centralize errors handling and proceeding system.


Comprehensive example:
  Let guess, that we have to develop script (no matter whether it is Web based or a console application), which, as any professional script, needs to care about occurred errors.
In general case you have to implement a sub for showing an error messages; logging code and in extreme situations to send mails to your support team; code which will protect you from fatal errors; code which will protect your script from infinitive loops.
  Described example is really superficial, but good enough to have an idea about enormous requirement of error handling system like this.
  Solution for lyric problem above is shown bellow:

use
Errors::Errors;

use strict;

my $obj = Errors::Errors->new();

$obj->attach('display');  # Virtual 'display' object (sobject)
$obj->attach('logs');      # Virtual 'logs' object (sobject)

$obj->install('onExit',\&catch_exit); # Catch exit.
$obj->install('onError',\&event_handler,'display'); # Print error to display
$obj->install('onError',\&event_handler,'logs'); # Do same to your hdd
$obj->install('onTimeOut',\&timeout); # Handle overstep time limit.

eval 'alarm(100);'; # Give 100 seconds lifetime to your script.

eval q|
#... code which may fail with fatal error!
$obj->error('Error!','display'); # Force error
$obj->error('Error!','logs'); # Force error
$obj->exit();
# exit() and $obj->exit() will close you application NOT only the eval() block!
# however exit() will trigger 'destroy' event, but $obj->exit() will trigger 'exit' event!

|;

# Due 'eval' code above, following lines will not be executed!
while(1)
{
  # Any action which may bring application to infinitive loop.
  # After 100 sec this problem will be busted

}

sub event_handler
{
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'error'
  my $err = $in{'error'}; # Error message
  my $name = $in{'name'}; # Custom error name
  my $to = $in{'to'}; # Message is sent "to"
  my $params = $in{'params'}; # Additional parameters (ref to @)
  my @params = @$params;

  if($name eq $to && $to eq 'display')
  {
    # Print your error message...
    print "Error: $err (invoked for $name)\n";
  }

  if($name eq $to && $to eq 'logs')
   {
     # Log your error message to hdd...
     print "Error: $err (invoked for $name)\n";
   }
}

sub timeout
{
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'term'
  my $name = $in{'name'}; # Custom error name
  my $sig = $in{'signal'}; # Invoked signal: 'alrm'

  $obj->error('Timeout!', 'display');
  $obj->error('Timeout!', 'logs');
}

sub catch_exit
{
  my $obj = shift;
  my %in = @_;
  my $type = $in{'type'}; # Error type: 'exit','die','destroy'
  my $err = $in{'error'}; # Error value
  my $name = $in{'name'}; # Custom error name
  my $params = $in{'params'}; # Additional parameters (ref to @)
  my @params = @$params;

  if($type eq 'exit')
   {
     # Oops your code use 'exit' to abort script...
     $obj->error('Oops!','display');
     # ...
   }
}


[Top]



How It Works?

  First you must to create one object for your program:

use Errors::Errors;
$obj = Errors::Errors->new();

This object will contain pointers to your subs that handle occurred errors.

This module can handle follow base errors/events:

exit(onExit), die(onExit), TERM/STOP/PIPE/QUIT/HUP/INT(onTerm), ALRM(onTimeout), and custom errors(onError).

If you want to do something when your script ends, set your custom sub:

$obj->install('onExit',\&leave);

where \&leave is pointer to your sub 'leave'. When your script ends your sub program 'leave' will be executed before the end. That will be happened at the end of $obj scope i.e. in DESTROY section of module. Also you can provoke execution of 'leave' if you write follow line in program:

$obj->exit($code_error);
or
$obj->die($code_error);

If you want to handle ALRM signal write line like this:

$obj->install('onTimeout',\&custom);

where 'custom' is your custom sub that handle ALRM signal.

To handle TERM/STOP/PIPE/QUIT/HUP/INT signals use follow like:

$obj->install('onTerm',\&custom);

where 'custom' is your custom sub that handle listed signals.

If you want to initialize your custom errors write code bellow:

$obj->install('onError',\&anysub);

So when you call method bellow, somewhere in script, you will rise execution of 'anysub'!

$obj->error($code_error);

Of course all your subs will receive additional parameters so you will be able to find reason for errors (and respective error codes). See SYSNOPSIS above.

In single script these methods are strong enough, but if you have a complex program with lot of libraries/modules you may want to have a single 'errors' object for all your libraries/modules. But how you can handle TERM signal for all yours different libraries??? The idea is quite simple, we will still continue to use our global (single) object, but we will create "sub objects" for all additional libraries/modules!

To add new sub object do follow:

$obj->attach('some');

This will create sub object called 'some'. To install 'onTerm' signal for this sub object (SObject) do follow:

$obj->install('onTerm',\&custom,'some');

Also to catch 'exit' for SObject call:

$obj->install('onExit,',\&leave,'some');

To rise custom error for 'some' SObject, call:

$obj->error($code_error,'some',@additional_parameters);

To exit…:

$obj->exit($code_error,'some',@additional_parameters);

… and so on.

Note:
$obj->error($code_error,'some');
will rise error in 'some' sub object
$obj->error($code_error);
will rise error in 'main' object!!! (Think about that like parent object and respective children)!

Let imagine that we have a lot of children (SObjects) and one parent object. Also let for all these objects we have sub programs that catch exit event. And now let our program gone to the end of code, so program must quit and Perl must destroy and unload our program!
However Errors module have job to do, it must call all subs that are joined into 'exit' chain!
See follow block:

foreach $obj call {
| SObject 1 | -> onExit sub
| SObject 2 | -> onExit sub

| SObject n | -> onExit sub
| Main object | -> onExit sub
}


Note: "main" handling sub is called after all sobject subs, so if you catch onError event don't exit application in sobject routines, becase all calls to next subs in chain will fail.

All this will be happened with all other events/signals! So you have to check reason and decide whether you must do anything into respective sub! See simple example:

sub anysub {
my $obj = shift; # 'Errors' object
my $err = shift; # Error number/message
my $name = shift; # 'name' of error
if($name =~ m/some/si)
 {
   $obj->print ("Error in some!");
 }
else
 {
   $obj->print ("Error in ... I don't know :-)!!!");
 }
}

If name is 'some' we can do something, but when the error is somewhere else you may want to miss it! You have to decide!


To delete SObject call:

$obj->detach('some');

To uninstall event/signal:

$obj->uninstall('onError','some'); # for some SObject
or
$obj->uninstall('onError'); # for main object


At the end I would like to notice that this module was originally written for Web and more correct for WebTools Perl sub system (look at http://www.proscriptum.com/)

So to allow Errors object to let know, whether content type is sent use follow line:

$obj->content($state); # $state can be '1' - yes and '0' - is not sent yet!

If you want to send default content (HTTP) header use:

$obj->header();

Note: If $obj->content() is '1' then $obj->header() will return immediately without printing default header, but if you are not still sent header (or if you forgot to tell that to Error object via $obj->content(1) ) then $obj->header() will sent default header.

To overwrite default header function use statement bellow:

$obj->install('header',\&your_header_sub);

All this (header and content functions) is needful because if this script is WEB based and error occurred you may want to print some text into browser, but if you forgot to print content, error will occurred (Internal Error). And vice versa: If content is already sent and you print it again then second content header will appear in browser.

For more information, look at Errors::Errors module.

[Top]


www.proscriptum.com is property of Julian Lishev. All rights reserved, Sofia 2001-2003.