package Lire::Program; use strict; use base qw/ Exporter /; use vars qw/ @EXPORT_OK %EXPORT_TAGS $LR_TAG $LR_ID $PROG $LR_SUPERSERVICE $LR_SERVICE $start $init_called /; use File::Basename qw/ basename /; # Make sure the all script which uses Lire::Program # also get Lire::Config inited use Lire::Config; use Lire::Error qw/ file_not_readable /; =pod =head1 NAME Lire::Program - Lire's programs common infrastructure. =head1 SYNOPSIS Any program: use Lire::Program qw/ :msg /; lr_info( "doing stuff " ); lr_debug( "debugging information" ); lr_warn( "encountered unexpected value: ", $value ); open( CFGFILE, "my.conf" ) or lr_err( "open error: ", $! ); =head1 DESCRIPTION This module should be used by all Lire programs (at least the Perl ones :-). It includes: =over =item 1. Common behavior for good integration in the Lire suite. (Output of performance information and other stuff). =item 2. Functions for portability. =item 3. Logging functions =back =head1 COMMON BEHAVIOR FOR LIRE PROGRAMS When you use the Lire::Program module, you make sure that your program will behave correctly in the Lire tool chain. This module will install BEGIN and END blocks to comply with Lire's policy. =over =item 1. Only messages in the proper logging format I I I I I I should be output. This module will install a __WARN__ signal handler that makes sure that all modules that use warn to output messages are rewritten in the proper format. See also lr_run(1). =item 2. All programs should start by a C message which logs their arguments. This module takes care of this. =item 3. All programs should end by printing C messages with performance statistics and the message 'ended'. Using this module takes care of this. At the end of your program the following will be output (stripped off the common information): memory stats: vsize=10688K rss=9380K majflt=406 elapsed time in seconds real=9 user=8.72 system=0.06 stopped The memory profiling information will only be output on platforms running the Linux kernel. =back =head2 COMMON VARIABLES As a convenience, you can import in your namespace using the :env tag some variables common to all Lire programs. (Note that you can also use those variables without importing them by prefixing the variables with the Lire::Program:: namespace.) =over =item $PROG The name of your program (that's the value of $0 without the directory path). =item $LR_SUPERSERVICE The superservice which you are processing, or C if this information isn't available. =item $LR_SERVICE The service which you are processing, or C if this information isn't specified. =item $LR_ID That's the job identifier. It should be shared by all commands in a Lire job. This is the value UNSET when none was specified. =item $LR_TAG That's the prefix to all log messages. Should correspond to $LR_SUPERSERVICE $LR_SERVICE $LR_ID $PROG =back =cut BEGIN { ($PROG) = basename( $0 ); $LR_SUPERSERVICE = $ENV{'LR_SUPERSERVICE'} || 'all'; $LR_SERVICE = $ENV{'LR_SERVICE'} || 'all'; $LR_ID = $ENV{'LR_ID'} || "UNSET"; $LR_TAG = "$LR_SUPERSERVICE $LR_SERVICE $LR_ID $PROG"; @EXPORT_OK = qw/ tempfile tempdir /; require Lire::Utils; *tempfile = \&Lire::Utils::tempfile; *tempdir = \&Lire::Utils::tempdir; require Lire::Logger; *lr_emerg = \&Lire::Logger::lr_emerg; *lr_crit = \&Lire::Logger::lr_emerg; *lr_err = \&Lire::Logger::lr_err; *lr_warn = \&Lire::Logger::lr_warn; *lr_notice = \&Lire::Logger::lr_notice; *lr_info= \&Lire::Logger::lr_info; *lr_debug= \&Lire::Logger::lr_debug; $SIG{'__WARN__'} = sub { Lire::Logger::lr_warn( @_ ); }; %EXPORT_TAGS = ( 'dlf' => [ qw/ init_dlf_converter end_dlf_converter lire_chomp / ], 'msg' => [qw/ lr_emerg lr_crit lr_err lr_warn lr_notice lr_info lr_debug/ ], 'env' => [ qw/ $PROG $LR_SUPERSERVICE $LR_SERVICE $LR_TAG $LR_ID / ], ); foreach my $tag ( keys %EXPORT_TAGS ) { Exporter::export_ok_tags( $tag ); } Lire::Config->lire_program_config_init; } =pod =head1 LOGGING FUNCTIONS The logging functions are now part of the Lire::Logger module. Consult Lire::Logger(3pm) for more information. The old names are still exported from this module by using the ':msg' tag. =head1 DLF CONVERTERS FUNCTIONS The DLF converter API is now defined in Lire::DlfConverter(3pm). The Lire::OldDlfAdapter(3pm) can be used to work with old-style DLF Converters. =cut sub init_dlf_converter { my ( $superservice ) = @_; # Empty for now $init_called = $superservice; } sub end_dlf_converter { my ( $lines, $dlflines, $errorlines ) = @_; $errorlines ||= 0; lr_err( "Lire::Program::init_dlf_converter wasn't called" ) unless $init_called; lr_info( "read $lines lines; output $dlflines DLF lines; $errorlines errors" ); $init_called = undef; } sub lire_chomp(;$) { if ( @_ == 1 ) { $_[0] =~ s/\r?\n?$//; } else { $_ =~ s/\r?\n?$//; } } # This is executed after the function were compiled BEGIN { $start = time; if ( @ARGV ) { lr_info ( "started with ", join " ", @ARGV ); } else { lr_info ( "started with no argument" ); } } # FIXME: Make this portable to other OS then Linux 2.X sub print_linux_memory_stats { my $stat_file = '/proc/self/stat'; open PROC, $stat_file or die file_not_readable( $stat_file ); my @stats = split /\s+/, ; close PROC; # Stat layout is in linux, from proc(5) # 0 pid 10 cminflt 20 itrealvalue 30 blocked # 1 comm 11 majflt 21 starttime 31 sigignore # 2 state 12 cmajflt 22 vsize 32 sigcatch # 3 ppid 13 utime 23 rss 33 wchan # 4 pgrp 14 stime 24 rlim # 5 session 15 cutime 25 startcode # 6 tty 16 cstime 26 endcode # 7 tpgid 17 counter 27 startstack # 8 flags 18 priority 28 kstkesp # 9 minflt 19 timeout 29 signal # Sanity check to see if we read the good structure die "layout of /proc/self/stat doesn't match we expect" unless $stats[0] == $$ && $stats[3] == getppid && $stats[4] == getpgrp 0; my $vsize = $stats[22] / 1024; my $rss = $stats[23] * 4; my $majflt = $stats[11]; lr_info( "memory stats: vsize=${'vsize'}K rss=${'rss'}K majflt=$majflt" ); } END { eval { print_linux_memory_stats() } if -e "/proc/self/stat"; my $real = time - $start; my ($user, $system ) = times; # Print performance data lr_info( "elapsed time in seconds real=$real user=$user system=$system" ); lr_info( "stopped" ); } 1; __END__ =pod =head1 SEE ALSO Lire::DlfSchema(3pm), lr_run(1) =head1 AUTHOR Francis J. Lacoste =head1 VERSION $Id: Program.pm,v 1.35 2006/07/23 13:16:29 vanbaal Exp $ =head1 COPYRIGHT Copyright (C) 2001 Stichting LogReport Foundation LogReport@LogReport.org This file is part of Lire. Lire is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see COPYING); if not, check with http://www.gnu.org/copyleft/gpl.html. =cut