Nachiketa
Nachiketa

Reputation: 29

In a tcl script how can i use puts to write a string to the console and to a file at the same time?

# Prints the string in a file
puts $chan stderr "$timestamp - Running test: $test"

# Prints the string on a console
puts "$timestamp - Running test: $test"

Is there a way I can send the output of puts to the screen and to a log file at the same time? Currently I have both the above two lines one after the other in my script to achieve this.

Or is there any other solution in tcl ?

Upvotes: 1

Views: 4131

Answers (2)

Peter Lewerin
Peter Lewerin

Reputation: 13252

This isn't something I've used extensively, but it seems to work (Tcl 8.6+ only):

You need the channel transform tcl::transform::observe package:

package require tcl::transform::observe

Open a log file for writing and set buffering to none:

set f [open log.txt w]
chan configure $f -buffering none

Register stdout as a receiver:

set c [::tcl::transform::observe $f stdout {}]

Anything written to the channel $c will now go to both the log file and stdout.

puts $c foobar

Note that it would seem to make more sense to have the channel transformation on top of stdout, with the channel to the log file as receiver, but I haven't been able to make that work.

Documentation: chan, open, package, puts, set, tcl::transform::observe (package)

Upvotes: 3

Leon
Leon

Reputation: 32484

Use the following proc instead of puts:

proc multiputs {args} {
    if { [llength $args] == 0 } {
        error "Usage: multiputs ?channel ...? string"
    } elseif { [llength $args] == 1 } {
        set channels stdout
    } else {
        set channels [lrange $args 0 end-1]
    }
    set str [lindex $args end]
    foreach ch $channels {
        puts $ch $str
    }
}

Examples:

# print on stdout only
multiputs "1"

# print on stderr only
multiputs stderr "2"

set brieflog [open brief.log w]
set fulllog [open detailed.log w]
# print on stdout and in the log files
multiputs stdout $brieflog $fulllog "3"

Upvotes: 3

Related Questions