#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0

    Problem logging STDOUT in perl


    I have a program, which call a subroutine and logs the STDOUT to a different file for each subroutine called.


    foreach $test_run (keys(%test_hash)) {
    if ($test_hash{$test_run} == 1) {
    $test_execute = $test_run;
    $test_execute1 = $test_run."."."pm";
    my $logfile = $test_execute."_log.txt";
    print "the logfile is $logfile \n";
    open (STDOUT, "| tee $logfile");
    require "$test_execute1";
    my $op = $test_execute->$test_execute();
    }

    On executing my script with above code creates all the log files, but lets say foreach loop runs for 3 times; then first log file have output of all the 3 calls of test_execute,2nd log file have output of 2nd and 3rd calls of test_execute and last log file will have only last call of test_execute.
    Please help me get all the logg files which contains logs for every single test_execute call.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    929
    On each iteration of the loop, you're just adding to the pipeline so by the last iteration you have "Perl -> tee log_file_3 -> tee log_file_2 -> tee log_file_1". You can use "local" to save & restore STDOUT on each iteration:

    Code:
    C:\temp>cat test.pl
    for ( 1 .. 3 ) {
        local *STDOUT;
        open STDOUT, "| tee $_.log" or die $!;
        print "Iteration $_\n";
    }
    
    C:\temp>cat 1.log
    Iteration 1
    
    C:\temp>cat 2.log
    Iteration 2
    
    C:\temp>cat 3.log
    Iteration 3
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,947
    Rep Power
    1225
    Personally, I'd use either PerlIO::tee or File::Tee instead of your piped open.

    Is that a direct copy/paste of your actual code, or is it just an approximation of your real code? The reason I ask is that I see a problem with this line:
    Code:
    my $op = $test_execute->$test_execute();

    $test_execute is a copy of $test_run, which is the hash key and hash keys are strings. In this line of code you're using it as an object as well as the method being called. That does not make any sense.

    Here's how your loop would look if you used File::Tee. Note, I cleaned up some of the duplication but left in the issue noted above.

    Code:
    use File::Tee qw(tee);
    
    foreach my $test_run ( keys %test_hash ) {
    
        if ( $test_hash{$test_run} == 1 ) {
    
            my $test_execute = $test_run . '.pm';
            require $test_execute;
    
            my $logfile = $test_run . '_log.txt';
            open my $log_fh, '>', $logfile or die "failed to open '$logfile' $!";
    
            tee STDOUT, $log_fh;
            my $op = $test_run->$test_run();
    
           close $log_fh;
        }
    
    }
    Last edited by FishMonger; August 22nd, 2012 at 10:08 AM.
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0
    This code is more of less equivalent to what I currently have. Issue still persists.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0
    Originally Posted by OmegaZero
    On each iteration of the loop, you're just adding to the pipeline so by the last iteration you have "Perl -> tee log_file_3 -> tee log_file_2 -> tee log_file_1". You can use "local" to save & restore STDOUT on each iteration:

    Code:
    C:\temp>cat test.pl
    for ( 1 .. 3 ) {
        local *STDOUT;
        open STDOUT, "| tee $_.log" or die $!;
        print "Iteration $_\n";
    }
    
    C:\temp>cat 1.log
    Iteration 1
    
    C:\temp>cat 2.log
    Iteration 2
    
    C:\temp>cat 3.log
    Iteration 3
    I have tried this earlier and I am sure this will work. But there is a big hidden issue which I am not able to identify, when I use local *STDOUT in my scripts; device on which i running these scripts, device crashes. .. so I am looking for any other solution than this.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,947
    Rep Power
    1225
    It's difficult for us to provide possible solutions when you don't provide an accurate representation of your code or what you're needing to accomplish.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0
    Originally Posted by FishMonger
    It's difficult for us to provide possible solutions when you don't provide an accurate representation of your code or what you're needing to accomplish.
    Solution which I am looking is exactly what OmegaZero has provided. But I want to achieve same thing using some other trick.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,947
    Rep Power
    1225
    Did you try either of the modules I suggested?
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,947
    Rep Power
    1225
    Example:

    [root@099-91-RKB01 ~]# cat ./test.pl
    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Tee qw(tee);
    
    for ( 1 .. 3 ) {
        my $logfile = "file$_.log";
        open my $fh, '>', $logfile or die "failed to open '$logfile' $!";
    
        tee STDOUT, $fh;
        print "Iteration $_\n";
        close $fh;
    }
    output:
    [root@099-91-RKB01 ~]# ./test.pl
    Iteration 1
    Iteration 2
    Iteration 3

    =====

    [root@099-91-RKB01 ~]# cat 1.log
    Iteration 1
    [root@099-91-RKB01 ~]# cat 2.log
    Iteration 2
    [root@099-91-RKB01 ~]# cat 3.log
    Iteration 3
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0
    Originally Posted by FishMonger
    Example:

    [root@099-91-RKB01 ~]# cat ./test.pl
    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Tee qw(tee);
    
    for ( 1 .. 3 ) {
        my $logfile = "file$_.log";
        open my $fh, '>', $logfile or die "failed to open '$logfile' $!";
    
        tee STDOUT, $fh;
        print "Iteration $_\n";
        close $fh;
    }
    output:
    [root@099-91-RKB01 ~]# ./test.pl
    Iteration 1
    Iteration 2
    Iteration 3

    =====

    [root@099-91-RKB01 ~]# cat 1.log
    Iteration 1
    [root@099-91-RKB01 ~]# cat 2.log
    Iteration 2
    [root@099-91-RKB01 ~]# cat 3.log
    Iteration 3
    yes I tried it and got following output:

    automation@automation:~$ cat file1.log
    Iteration 1
    Iteration 2
    Iteration 3
    automation@automation:~$ cat file2.log
    Iteration 2
    Iteration 3
    automation@automation:~$ cat file3.log
    Iteration 3
    automation@automation:~$

    I tried following code:

    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Tee qw(tee);
    
    for ( 1 .. 3 ) {
        my $logfile = "file$_.log";
        open my $fh, '>', $logfile or die "failed to open '$logfile' $!";
    
        tee STDOUT, $fh;
        print "Iteration $_\n";
        close $fh;
    }
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,947
    Rep Power
    1225
    I am unable to duplicate your problem.

    Here's another example using PerlIO::tee
    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use PerlIO::tee;
    
    for ( 1 .. 3 ) {
        my $logfile = "file-IO-tee$_.log";
        open my $fh, '>', $logfile or die "failed to open '$logfile' $!";
    
        *STDOUT->push_layer(tee => $fh);
        print "Iteration $_\n";
    
        *STDOUT->pop_layer();
        close $fh;
    }
    [root@099-91-RKB01 ~]# cat file-IO-tee1.log
    Iteration 1
    [root@099-91-RKB01 ~]# cat file-IO-tee2.log
    Iteration 2
    [root@099-91-RKB01 ~]# cat file-IO-tee3.log
    Iteration 3
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    7
    Rep Power
    0
    Originally Posted by FishMonger
    I am unable to duplicate your problem.

    Here's another example using PerlIO::tee
    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use PerlIO::tee;
    
    for ( 1 .. 3 ) {
        my $logfile = "file-IO-tee$_.log";
        open my $fh, '>', $logfile or die "failed to open '$logfile' $!";
    
        *STDOUT->push_layer(tee => $fh);
        print "Iteration $_\n";
    
        *STDOUT->pop_layer();
        close $fh;
    }
    Thanks, using PerlIO::tee worked perfectly. Thanks a lot.

IMN logo majestic logo threadwatch logo seochat tools logo