The following code snippet allows you to tie a scalar to a logfile. You may choose which types of activities will be logged (default is ALL: TIESCALAR, STORE, FETCH, and DESTROY). A log file will be created (if it doesn't already exist), and any activity related to the tied scalar will be scribbled into the logfile for later review.
The scalar should behave just like any old normal scalar, but with the side effect that any use of the tied scalar will result in another line being written into the logfile.
From this starting framework, it shouldn't be too difficult to also create Tie::Hash::Logged, and Tie::Array::Logged.
Here is the code, along with a sample usage:
package Tie::Scalar::Logged; use IO::File; require Tie::Scalar; @ISA = qw/Tie::StdScalar/; use strict; use warnings; # TIESCALAR: Mostly self-explanatory, but just to be # thorough, $logfile is the filename of the output file. # $name is a single-quoted string naming the variable that # has been tied. This is for reporting purposes only. # $events is an optional array ref that should contain # the names of the methods you would like to track. Method # names will be case insensitive. They may include: # ALL, TIESCALAR, STORE, FETCH, DESTROY. sub TIESCALAR { my ( $class, $logfile, $name, $events ) = @_; my $self = {}; $self->{Name} = $name; $self->{LOG} = new IO::File ">> $logfile" or return undef; $self->{Value} = undef; if ( not defined ( $events ) or grep {/ALL/i} @$events ) { @$events = qw/TIESCALAR STORE FETCH DESTROY/; } $self->{uc($_)}=1 foreach @$events; print {$self->{LOG}} "$self->{Name} => TIESCALAR\tLogging to $logfile\n" if $self->{TIESCALAR}; bless $self, $class; } sub STORE { my ( $self, $value ) = @_; $self->{Value} = $value; print {$self->{LOG}} "$self->{Name} => STORE\t\tValue = $value\n" if $self->{STORE}; return $self->{Value}; } sub FETCH { my $self = shift; print {$self->{LOG}} "$self->{Name} => FETCH\t\tValue = $self->{Value}\n" if $self->{FETCH}; return $self->{Value}; } sub DESTROY { my $self = shift; print {$self->{LOG}} "$self->{Name} => DESTROY\t\tValue = $self->{Value}\n" if $self->{DESTROY}; $self->{LOG}->close; } 1; # ---------- Begin main ---------- package main; use strict; use warnings; # Simple test: Create a lexical variable and perform a few # operations on it. The logfile will then contain a log of # all activity affecting the variable. my $var; # When tieing a variable to Tie::Scalar::Logged, the parameter list # is as follows: Variable to tie, Package name, Logfile name, # Single-quoted string naming variable that is being tied, and # finally, an optional reference to an array containing one or # more of the following activities that can be logged: # ALL, TIESCALAR, FETCH, STORE, DESTROY. (Case/Order insensitive.) tie $var, "Tie::Scalar::Logged", 'log.txt', '$var', [qw/all/]; $var = 10; $var += 10; print $var, "\n";
I am interested in reading comments that might lead to improvement. One thing in particular is I would be interested in finding a way (if it is possible) of also logging the line-number where the activity being logged took place. Maybe if there's an interest in this module I can figure out what it takes to get it ready to be put on CPAN.
I should take a moment to thank those of you who, in the Chatterbox, helped me fumble my way through my first attempt at an OO module. I really appreciate the learning opportunities I gain from this site, and the teaching-moments I gain from so many of this site's regulars.
Update: Changed
$self->{LOG} = new IO::File ">> $logfile" or die "Can't open $logfile for append: $!\n";
to or return undef; for a more graceful reaction if the logfile is unable to be opened. Thanks duff and ysth for the suggestion.
Changed module name from Tie::Scalar::Log to Tie::Scalar::Logged per duff's recommendation.
Dave
In reply to Scalars tied to logfiles by davido
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |