Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
More Moose based logging and reporting
Perl Prolog
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
t
LICENSE
MANIFEST
META.json
META.yml
Makefile.PL
README.pod
dist.ini

README.pod

Log::Shiras

More Moose based logging and reporting

WARNING

Right now this package is kind of a hot mess, but since I am CPAN releasing other packages with debug code embedded in them using this I thought I would at least update it so that it supports the CPAN releases. I am going through and working on packages in this order; Spreadsheet-XLSX-Reader (this doesn't even pass minimal tests yet) the goal is to get this to a CPAN beta level, Log-Shiras - the API is still also under a lot of flux and will probably release to CPAN as a Beta - I want to do some self reporting here but I still haven't wrapped my head around the deep recursion problem yet, MooseX-ShortCut-BuildInstance - if I fix the Log-Shiras deep recursion I want to propagate the fix into this package too, Data-Walk-Extracted - this also shares the deep recursion problem - I would also like to switch this from a recursive parser to a stack trace parser so that it takes less memory.

SYNOPSIS

        #!perl
        use Modern::Perl; 
        use Log::Shiras::Switchboard 0.013;
        my      $operator = get_operator(
                {
                        reports => {# Can be replaced with a config file
                                log_file => [
                                        {
                                                roles => [
                                                   "Log::Shiras::Report::ShirasFormat",
                                                   "Log::Shiras::Report::TieFile"
                                                ],
                                                format_string => "%{date_time}P(m=>'ymd')s," .
                                                        "%{filename}Ps,%{inside_sub}Ps,%{line}Ps,%s,%s,%s",
                                                filename => "test.csv",
                                                superclasses => [
                                                   "Log::Shiras::Report"
                                                ],
                                                header => "Date,File,Subroutine,Line,Data1,Data2,Data3",
                                                package => "Log::File::Shiras"
                                        }
                                ],
                                phone_book => [
                                        {
                                                roles => [
                                                   "Log::Shiras::Report::ShirasFormat",
                                                   "Log::Shiras::Report::TieFile"
                                                ],
                                                format_string => "%s,%s,%s",
                                                filename => "phone.csv",
                                                superclasses => [
                                                   "Log::Shiras::Report"
                                                ],
                                                header => "Name,Area_Code,Number",
                                                package => "Phone::Report"
                                        }
                                ]
                        },
                        name_space_bounds => {
                                main => {
                                        UNBLOCK => {
                                                log_file => "warn"
                                        },
                                        test_sub => {
                                                UNBLOCK => {
                                                        log_file => "debug"
                                                }
                                        }
                                },
                                Activity => {
                                        call_someone => {
                                                UNBLOCK => {
                                                        log_file => "trace",
                                                        phone_book => "eleven"
                                                }
                                        }
                                }
                        },
                        buffering => {
                                log_file => 1
                        }
                }
        );
        my      $telephone = get_telephone;
                $telephone->talk( 
                        level => 'debug', report => 'log_file', 
                        message =>[ qw( humpty dumpty sat on a wall ) ] 
                );
                $telephone->talk( 
                        level => 'warn', report => 'log_file', 
                        message =>[ qw( humpty dumpty had a great fall ) ] 
                );
                $operator->send_buffer_to_output( 'log_file' );
                $telephone->talk( message =>['Dont', 'Save', 'This'] );
                $operator->clear_buffer( 'log_file' );
                test_sub( 'Scooby', 'Dooby', 'Do' );
                $telephone->talk( message =>['and', 'Scrappy', 'too!'] );
                Activity->call_someone( 'Jenny', '', '867-5309' );
                $operator->send_buffer_to_output( 'log_file' );
                
        sub test_sub{
                my @message = @_;
                my $phone = get_telephone;
                $phone->talk( level => 'debug', report => 'log_file', message =>[ @message ] );
        }

        package Activity;
        use Log::Shiras::Switchboard;

        sub call_someone{
                shift;
                my $phone = get_telephone;
                my $output;
                $output .= $phone->talk( report => 'phone_book', message => [ @_ ], );
                $output .= $phone->talk( 'calling', @_[0, 2] );
                return $output;
        }
        1;
        
        #####################################################################################
        #    Synopsis output in phone.csv
        # 01:Name,Area_Code,Number
        # 02:Jenny,,867-5309
        #
        #    Synopsis output in test.csv
        # 01:Date,File,Subroutine,Line,Data1,Data2,Data3
        # 02:DD/MM/YYYY,t\Log-Shiras-example.pl,main,69,humpty,dumpty,had
        # 03:DD/MM/YYYY,t\Log-Shiras-example.pl,main::test_sub,84,Scooby,Dooby,Do
        # 04:DD/MM/YYYY,t\Log-Shiras-example.pl,main,77,and,Scrappy,too!
        # 05:DD/MM/YYYY,t\Log-Shiras-example.pl,Activity::call_someone,95,calling,Jenny,867-5309
        #####################################################################################

DESCRIPTION

Shiras - A small subspecies of Moose found in the western United States (of America).

This is a Moose based logger with the ability to run lean or add functionality using a Moose object/role model. While no individual element of this logger is unique to the sea of logging modules on CPAN the combination of features and implementation is different. The goal is to provide a base (set) of Moose class(s) which can be used (and abused) for general input and output management. The base use-case for this package is to allow debug reporting and module output to be directed to multiple different locations and be able to manage these flows with centralized logger-style name-space definitions. This package is most related in concept to Log::Dispatch.

Since this package makes a few implementation choices differently from the traditional run of logging packages, I felt that it made sense to introduce some new terms to explain the differences. To do this I leveraged (loosely) the old telephone switchboard process. The new terms are switchboard, operator, phone, and talk. Ideas largely unchanged from the logging world include logging levels, logging name spaces, config file management of logging, and configurable output formatting.

The majority of the need for new terms springs from a core (and intentional) design decision to split the functions of traffic management, output handling, and input handling into separate classes. First, the traffic management class is called a "Switchboard". Second, the data retention class is called a "Report". Having a separate report class allows for multiple instances of the class to be recognized by the 'Switchboard'. Also, since it is a Moose class behaviour is modified just by adding roles. Finally, there is a third class called a "Telephone". As you might guess both the 'Telephone' and the 'Report' are built using the 'Switchboard' so that they are all connected for call routing and message clearance.

Overall, it is not clear that any individual detail of the implementation is new. The difference lies in the combination of these features.

NEW TERMS

Switchboard

Definition

This is the Moose Class that manages the traffic between "Telephone"s and "Report"s. Telephones and Reports are also created/connected through this class since ultimatly the class needs to know something about each one. This is also where routing configuration from a traditional logger would go. This is a MooseX::Singleton Class which seemed to be the best alternative to the global variable that I would have otherwise used for signal handling. Warning - Multiple connections to the Switchboard Singleton can be active and none of the namespace definitions from one connection are protected against meddling by other connections. So ... it would be entirely possible to for one connection to clobber some other connections name space definitions! One potential way to handle logging namespace collisions is to use custom class names in the content generation modules with MooseX::ShortCut::BuildInstance. Another way is to define custom reporting name-spaces for each telephone so that separate telphones will never appear to occupy the same space. This custom name-space can be defined as one of the %args when calling 'get_telephone'.

Operator

Definition

The operator is an instance that will allow code to interact with the Switchboard singleton. The switchboard routings can either be defined when the operator is created or updated by method calls against the operator over time. The initial call to create an operator will also accept a config file in YAML or JSON format.

Creation

        my $operator = get_operator( %args|filename );

Telephone

Definition

This is used in standalone code to place a call to a "Report". This is analogous to the '$logger' concept from Log::Log4perl. The phone is provided by the switchboard and comes from the switchboard pre-wired.

Creation

        my $telephone = get_telephone( %args );

Report

Definition

These are output objects or destinations for the 'talk' command used by telephones. Reports are assigned names by the switchboard with the possibility of having an array of reports assigned the same name. If a telephone makes a call to a report name then each report with that name receives the message passed from the telephone. All formatting is done by report instance allowing for variations in filtering and formatting differences between reports of the same name.

Use

        $report_instance->add_line( %message );#Generally managed by the switchboard

Place a call (talk)

Definition

This is the core action that a script or module would use to generate output for a report. There are several options for this call.

message: an array ref of content for the report
report: the name of the report destination (default is log_file)
level: this is the calling level of the message (default is the maximum)
other: the report can have a formatter attached that will use other keys from this message to either add content or manage output format of the message. The talk command will attempt to coerce this input to a hashref if it is not sent that way. Additionally the "Switchboard" will automatically add a certain amount of caller information for parsing by a formatter.

Use

        $telephone->talk( message =>[ 'Hello World!', ] );

Differentiation

Why choose this Logger over one of the other hundreds of options? I have listed some potential differentiatiors that you may find valuable. You may not find all or any of these unique in detail but in a group I think they represent something different.

Buffer behavior

This package has a report buffer (default off) for each report name. This allows for some messages to be discarded after they were collected based on branches in the code. A use case for this is when you are recursivly parsing some logic but only want to log the actions in the path that yeilded results.

Test::Log::Shiras

A dedicated test module for testing logged messages that will capture messages at the switchboard level rather than requiring a connection to the final destination of the report to review output. This leverages the buffering behavior above. The test methods include several ways of checking for output existence.

Headers

This module only adds the header to a file when it is new. If the file connection is dropped and then reconnected the header will not be added again. Log4perl doesn't do this.

Custom formatting

I wanted to be able to consume method calls and code references in the formatted output. The 'Log::Shiras::ShirasFormat' Role for the "Report" class does just that. While the API isn't as mature as Log4perl's 'PatternLayout' it does support full perl sprintf formatting. Since this is a Role if you don't like it you don't have to add it.

Moose

This package is Moose based. You probably already have an opinion on Moose so this may tip you one way or the other. I like Moose.

Multiple output paths

I wanted a one stop shop for file outputs. I mentally group file outputs from code into two categories. First is 'log_file' output. This is the way that code leaves tracks from the ongoing process that it follows. Second is 'report' output. This is when data is generated by code for consumption elsewhere. Like Log::Dispatch this allows me to do both through one interface.

Some things don't change

flexibility: General flexibility and ease of definition for configuration through either files or data structures.
Separation of concerns: Separation of output creation and collection definitions.
namespaces: Output level screening by namespace. This includes the possibility of custom level definitions by namespace.
sprintf: sprintf formtting

Install from Source

(for example git)

1. Download a compressed file with the code
2. Extract the code from the compressed file
3. cd into the extracted directory

(For Windows find what version of make was used to compile your perl)

        perl  -V:make

Then (adjusting make for your installation of perl)

        perl Makefile.PL
        make
        #~ make test #not passing!!!
        make install
        make clean
Something went wrong with that request. Please try again.