Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re^2: STDERR Restore after redirect

by tultalk (Monk)
on Apr 27, 2018 at 19:29 UTC ( [id://1213704]=note: print w/replies, xml ) Need Help??


in reply to Re: STDERR Restore after redirect
in thread STDERR Restore after redirect

Hi. I will take a look

As it now stands, code below works except for one quirk.

sub SendMemberMail { my ($subject,$from,$to,$port,$cc,$bcc,$heading,$body,$closing,$signi +ture,$auth) = @_; warn("In SendMemberMail before redirect of STDERR & STDOUT"); # Open log for recording during execution of SendMail my $sendMail_logfile = '/home/abcus/public_html/httpsdocs/cgi-bin/li +b/perl/Mail/mail.log'; open (my $fh, "+<", "$sendMail_logfile") or die "Opening: $!"; #Redirect STDERR & STDOUT to $fh for this sub open my $oldSTDOUT, ">&STDOUT"; open OLDERR, ">&",\*STDERR; open (STDERR, ">>&=", $fh) || die "can't redirect STDERR"; open (STDOUT, ">>&=", $fh) || die "can't redirect STDOUT"; $fh->autoflush(1); my $message = ($heading . "\n" . "\n" . $body . "\n" . "\n" . $closing . "\n" . "\n" . $signiture . "\n" ); if ($auth == 1) { $auth = {user=>'webmaster@abc.us', password=>'xx@33333XX', method= +>'PLAIN LOGIN', REQUIRED=>1} } elsif ($auth == 0) { $auth = ""; } my %mail = ( To => $to, From => $from, Cc => $cc, Bcc => $bcc, Auth => $auth, Port => $port, Subject => $subject, Message => $message, debug => 0 ); SendMail(%mail) or die $Mail::sendMail::error; $log .= "Sending eMail Succeded\n"; #Print the data from the $log. print $fh $log; #Test redirected handles print STDOUT "stdout 1\n"; warn("warn stderr 1\n"); close($fh); #restore the file standard handles open(STDOUT, ">&", $oldSTDOUT) or die "Can't dup \$oldout: $!"; open(STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; #Test original handles print STDOUT "stdout 2\n"; warn("warn stderr 2\n"); return 1; }

The mail is sent. The handles are restored as evidenced by stderr2 in my regular error log file and stderr/stdout in my pre-restore log file. What is gone in the nether world is the stdout2 and the printing of the HTML form to stdout back to client.

If I don't close the handle, the form (text) is printed to the sendMail logfile.

I put warns at beginning of the sub to print the html and at the end and both appear in the error log indicating execution of that block but no form returned to client.

As I posted earlier, if I bypass the call to sendMail(), the form prints as expected.

For some reason the call to print the form is not directed to the (opened)STDOUT nor to the (closed) $fh log handle. Perhaps lost in the mist of time and sitting at the earth moon L4 LaGrange point in a huge cloud of missing documents.

I can't see anything in sendMail that could have such an effect. I shut off the debugging in sendMail which writes to stderr and no effect (except less output to the log naturally)

I guess I have to just grunt my way through this until a revelation hits me.

Scoping are weird!

Replies are listed 'Best First'.
Re^3: STDERR Restore after redirect
by poj (Abbot) on Apr 27, 2018 at 19:50 UTC

    Just use local() within a block as tybalt89 suggested to save and then restore the filehandles.

    sub SendMemberMail { my ($subject,$from,$to,$port,$cc,$bcc,$heading,$body,$closing,$signi +ture,$auth) = @_; warn("In SendMemberMail before redirect of STDERR & STDOUT"); $Mail::sendMail::mailcfg{'debug'} = 6; $Mail::sendMail::mailcfg{'port'} = $port; my $message = "$heading\n\n$body\n\n$closing\n\n$signiture\n"; my %mail = ( To => $to, From => $from, Cc => $cc, Bcc => $bcc, Subject => $subject, Message => $message, ); if ($auth == 1) { $mail{'Auth'} = { user => '', password => '', method => 'PLAIN LOGIN', required => 1 }; }; my $logfile = '/home/abcus/public_html/httpsdocs/cgi-bin/lib/perl/Ma +il/mail.log'; open my $fh, '>>', $logfile or die "Error opening $logfile : $!"; SEND: { local *STDOUT = $fh; local *STDERR = $fh; if ( SendMail(%mail) ) { print $Mail::sendMail::log; } else { print $Mail::sendMail::error; } } close $fh; select STDOUT; # Test original handles print "stdout 2\n"; warn("warn stderr 2\n"); return 1; }
    Note: Using Mail::sendMail as described here
    poj

      Thanks

      I tried the local before and it did not work. Will try again

      I put some code in the sub that fails to print:

      sub CreateUserFeedbackForm { my ($message) = @_; if(!defined('STDOUT')){ warn("No STDOUT"); } elsif (defined('STDOUT')){ warn("STDOUT Defined"); } if(!defined('STDERR')) { warn("No STDOUT"); } elsif (defined('STDERR')) { warn("STDERR Defined"); }

      Result in my error log below:

      Fri Apr 27 16:43:31 2018 manage_users.cgi: STDOUT Defined at manage_users.cgi line 806. STDERR Defined at manage_users.cgi line 814. Fri Apr 27 16:43:31 2018 manage_users.cgi: STDERR Defined at manage_users.cgi line 814. At exit of sub CreateUserFeedbackForm at manage_users.cgi line 964. Fri Apr 27 16:43:31 2018 manage_users.cgi: At exit of sub CreateUserFeedbackForm at manage_users.cgi line 964.

      Since both returned "defined" my next question: Does that mean they are functional?

      I guess I could try writing to the handles to see but thought maybe some Monk could say "Yes defined means it is functional"

      Thanks

        if(!defined('STDOUT')){ ... }

        The strings  'STDOUT' and  'STDERR' are literal strings and not file handles. Strings are always defined. Even '' (the empty string) and '0', both of which are false, are both defined.

        I'm not sure of the best way to test if a file handle is functional, nor am I quite sure what "functional" means in this context.


        Give a man a fish:  <%-{-{-{-<

      <Hi>

      Thanks for input. As I stated before I already tried the local and the results were the same. So I tried again.

      Going through block of code and eliminating items step by step, commenting out #print "stdout 2\n"; and the program executed and printed html form as desired. Have no idea what effect that line could have to cause the failure. Ir was added for testing after some other problem.

      Bizarre/p>

      What is the SEND() for? What does it do?

        From poj's reply:   SEND: { ... }

        What is the SEND() for? What does it do?

        In this case, SEND is not a function call (as the () argument list operator you use would suggest), but is the label of a block that establishes a scope for the local-ization of changes to the global STDOUT and STDERR system file handles. (Update: See Compound Statements and Basic BLOCKs, both in perlsyn.)

        The label is not syntactically or semantically necessary for the establishment or operation of the scope in this case, but serves a purely documentary function: What's happening in the block? We're SENDing something. At the end of the block (or scope), the values of STDOUT and STDERR that existed before entering the block/scope are automatically restored.

        Update: If you haven't already, take a look at Coping with Scoping by Dominus, especially the discussions of local and package variables.


        Give a man a fish:  <%-{-{-{-<

        see BLOCKS

        SEND: is just an optional LABEL to make the block more visible. The block {} restricts the scope of the local().

        poj

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1213704]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-04-24 13:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found