Unix Programming - how to split STDOUT into 2 or more output streams

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > August 2005 > how to split STDOUT into 2 or more output streams





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author how to split STDOUT into 2 or more output streams
Liang

2005-08-10, 5:55 pm

I want to log a process and its children's output into a log file, while
printing the output on STDOUT.

By the way, there's no 'tee' available in the target environment.

One approach is to 'printf' twice the output, one for STDOUT, another for
the log file. But this makes the program ugly.

Another approach is to 'fork' the process, and let the parent act as the
'tee'.

If I don't want to use 'fork', is there any other way to implement the
requirement?

Thanks,
Liang


Gordon Burditt

2005-08-10, 5:55 pm

>I want to log a process and its children's output into a log file, while
>printing the output on STDOUT.
>
>By the way, there's no 'tee' available in the target environment.
>
>One approach is to 'printf' twice the output, one for STDOUT, another for
>the log file. But this makes the program ugly.


It is possible to change all the printf() calls (unless some of them
are hidden in the C library) and other output to call printf2(),
which is a varargs function you write that calls vfprintf(), twice.
That limits the ugliness to a small piece of code.

>Another approach is to 'fork' the process, and let the parent act as the
>'tee'.


Assuming you DO have pipes available, is there any reason you can't
write your own version of tee?

Assuming you DO NOT have pipes available, how does fork()ing the
process accomplish what you want? Run it twice to get two sets
of output?

>If I don't want to use 'fork', is there any other way to implement the
>requirement?


Is it OK for the shell to use fork()?

program | my_own_version_of_tee logfile

Gordon L. Burditt
Bill Marcum

2005-08-10, 5:55 pm

On Wed, 10 Aug 2005 22:54:47 +0800, Liang
<leo2002chen@hotmail.com> wrote:
> I want to log a process and its children's output into a log file, while
> printing the output on STDOUT.
>
> By the way, there's no 'tee' available in the target environment.
>

What OS is it, and why are you asking in comp.unix.programmer?


--
Tonight you will pay the wages of sin; Don't forget to leave a tip.
Vikram

2005-08-11, 3:13 am

The simplest way of doing on most of the unix systems is to use "tee"
command which can replicate the standard output.

tee command can be used in the following way

# unixcmd | tee logile

-Vikram

Pascal Bourguignon

2005-08-11, 3:13 am

"Liang" <leo2002chen@hotmail.com> writes:
> I want to log a process and its children's output into a log file, while
> printing the output on STDOUT.
>
> By the way, there's no 'tee' available in the target environment.
>
> One approach is to 'printf' twice the output, one for STDOUT, another for
> the log file. But this makes the program ugly.
>
> Another approach is to 'fork' the process, and let the parent act as the
> 'tee'.
>
> If I don't want to use 'fork', is there any other way to implement the
> requirement?


Why would you not want to fork?
pgm | tee
forks a tee process anyways.

So you don't have tee on this computer? Why don't you write one? It's trivial.

What would be ugly? Didn't you learn about functional abstraction
when you learned programming?


FILE* file=fopen("/var/log/file","a");
FILE* remote=fdopen(socket,"a");

log_add_output(stdout);
log_add_output(file);
log_add_output(remote);

/* and then you just write: */

logf("Message to be logged with data %s",data);

/* and logf takes care of logging out to all the log streams. */


--
__Pascal Bourguignon__ http://www.informatimago.com/
Litter box not here.
You must have moved it again.
I'll poop in the sink.
Vitale Ferruccio

2005-08-11, 3:13 am

Hi Liang,

according to me, first thing you should consider is avoiding a race condition
between main process and the children, while they're trying to write into the
log file.
You could:
- open a file, share its file descriptor between forks and associate a
semaphore
to it, so that every process could write in this file if the
semaphore is released
- the second type of output could be redirected to syslog or stdout via
a printf

Pseudo-code example:
#define LOG_INIT() { INIT_THE_SEMAPHORE; OPEN_SYSLOG }
#define LOG_STR(fmt, str...) { LOCK_SEMAPHORE; LOG_IT; \
WRITE_TO_SYSLOG; UNLOCK_SEMAPHORE };

I hope this could help you.

Regards,
Ferruccio

On 2005-08-10 16:54:47 +0200, "Liang" <leo2002chen@hotmail.com> said:

> I want to log a process and its children's output into a log file, while
> printing the output on STDOUT.
>
> By the way, there's no 'tee' available in the target environment.
>
> One approach is to 'printf' twice the output, one for STDOUT, another for
> the log file. But this makes the program ugly.
>
> Another approach is to 'fork' the process, and let the parent act as the
> 'tee'.
>
> If I don't want to use 'fork', is there any other way to implement the
> requirement?
>
> Thanks,
> Liang



--
/dev/zero
Unix Power @ Your Service
http://www.devzero.it

Liang

2005-08-11, 7:50 am

it's POSIX UNIX.

> What OS is it, and why are you asking in comp.unix.programmer?
>
>
> --
> Tonight you will pay the wages of sin; Don't forget to leave a tip.



Liang

2005-08-11, 7:50 am


"Gordon Burditt" <gordonb.d18ae@burditt.org> wrote in message
news:11fk9f5jia27j08@corp.supernews.com...
>
> It is possible to change all the printf() calls (unless some of them
> are hidden in the C library) and other output to call printf2(),
> which is a varargs function you write that calls vfprintf(), twice.
> That limits the ugliness to a small piece of code.


oh, not applicable. Because it will start other programs.

>
>
> Assuming you DO have pipes available, is there any reason you can't
> write your own version of tee?
>
> Assuming you DO NOT have pipes available, how does fork()ing the
> process accomplish what you want? Run it twice to get two sets
> of output?


oh, no, don't want to run it twice. Just want to run once, but split the
output to 2 streams.
One implementation may look like:


create pipe;
if(0==fork()){
# children
close STDOUT and STDERR
dup STDOUT and STDERR from pipe;
exec();
}
# parent
close STDIN
dup STDIN from pipe
while( getchar STDIN ){
put char;
}

But, I want to know if there's other solution that does not need 'fork'?



>
>
> Is it OK for the shell to use fork()?
>
> program | my_own_version_of_tee logfile







>
> Gordon L. Burditt



Liang

2005-08-11, 5:55 pm

thank Ferruccio, you reminded me.

BRs,
Liang


"Vitale Ferruccio" <ferruccio@devzero.it> wrote in message
news:2005081109575616807%ferruccio@devze
roit...
> Hi Liang,
>
> according to me, first thing you should consider is avoiding a race

condition
> between main process and the children, while they're trying to write into

the
> log file.
> You could:
> - open a file, share its file descriptor between forks and associate a
> semaphore
> to it, so that every process could write in this file if the
> semaphore is released
> - the second type of output could be redirected to syslog or stdout via
> a printf
>
> Pseudo-code example:
> #define LOG_INIT() { INIT_THE_SEMAPHORE; OPEN_SYSLOG }
> #define LOG_STR(fmt, str...) { LOCK_SEMAPHORE; LOG_IT; \
> WRITE_TO_SYSLOG; UNLOCK_SEMAPHORE };
>
> I hope this could help you.
>
> Regards,
> Ferruccio
>
> On 2005-08-10 16:54:47 +0200, "Liang" <leo2002chen@hotmail.com> said:
>
for[vbcol=seagreen]
>
>
> --
> /dev/zero
> Unix Power @ Your Service
> http://www.devzero.it
>



Gordon Burditt

2005-08-11, 5:55 pm

>> Assuming you DO have pipes available, is there any reason you can't
>
>oh, no, don't want to run it twice. Just want to run once, but split the
>output to 2 streams.
>One implementation may look like:
>
>
>create pipe;
>if(0==fork()){
> # children
> close STDOUT and STDERR
> dup STDOUT and STDERR from pipe;
> exec();
>}
># parent
>close STDIN
>dup STDIN from pipe
>while( getchar STDIN ){
> put char;
>}


Explain to me why this outputs on two streams. It seems to me obvious
that it doesn't, unless "put char;" refers to TWO calls to fputc() or
some other output function, one on stdout and one to a log file.

>But, I want to know if there's other solution that does not need 'fork'?


I want to know WHY you don't want to use fork()?

If you can't modify the programs doing the output, you're stuck doing
it in another process. Starting that process is going to involve SOME
process doing a fork().


I want to remove some screws, but I don't want to use a screwdriver,
because that's too slow, and I've got a pipe wrench, and I don't
care that removing screws with a pipe wrench is 100 times slower
than using a screwdriver.

Gordon L. Burditt
Liang

2005-08-12, 2:54 am


"Gordon Burditt" <gordonb.m5abw@burditt.org> wrote in message
news:11fn6jlqk2a5l5b@corp.supernews.com...
>
> Explain to me why this outputs on two streams. It seems to me obvious
> that it doesn't, unless "put char;" refers to TWO calls to fputc() or
> some other output function, one on stdout and one to a log file.


ah, you're right. Need to update above pseudo code, and call 'putc' twice
for STDOUT and LOG.

>
>
> I want to know WHY you don't want to use fork()?
>
> If you can't modify the programs doing the output, you're stuck doing
> it in another process. Starting that process is going to involve SOME
> process doing a fork().
>


thank Gordon for let me know the reason.

>
> I want to remove some screws, but I don't want to use a screwdriver,
> because that's too slow, and I've got a pipe wrench, and I don't
> care that removing screws with a pipe wrench is 100 times slower
> than using a screwdriver.
>
> Gordon L. Burditt



Stefaan A Eeckels

2005-08-15, 5:54 pm

On Thu, 11 Aug 2005 07:57:55 GMT
Vitale Ferruccio <ferruccio@devzero.it> wrote:

> according to me, first thing you should consider is avoiding a race condition
> between main process and the children, while they're trying to write into the
> log file.


I wouldn't call several processes writing to the same file a race
condition. The worst that can happen is that the output of the
processes gets jumbled up.

No need to mess with semaphores, simply ensure that the file is opened
with O_APPEND | O_DSYNC, collect the information to be written in a
buffer, and use a single write() call to write the buffer to the file.

Take care,

--
Stefaan
--
As complexity rises, precise statements lose meaning,
and meaningful statements lose precision. -- Lotfi Zadeh
David Schwartz

2005-08-16, 2:50 am


"Stefaan A Eeckels" <tengo@DELETEMEecc.lu> wrote in message
news:20050816004230.302e79ff.tengo@DELETEMEecc.lu...

> I wouldn't call several processes writing to the same file a race
> condition. The worst that can happen is that the output of the
> processes gets jumbled up.
>
> No need to mess with semaphores, simply ensure that the file is opened
> with O_APPEND | O_DSYNC, collect the information to be written in a
> buffer, and use a single write() call to write the buffer to the file.


Are you sure that guarantees that data won't interleave?

DS


Stefaan A Eeckels

2005-08-16, 7:51 am

On Mon, 15 Aug 2005 19:55:13 -0700
"David Schwartz" <davids@webmaster.com> wrote:

> "Stefaan A Eeckels" <tengo@DELETEMEecc.lu> wrote in message
> news:20050816004230.302e79ff.tengo@DELETEMEecc.lu...
>
>
> Are you sure that guarantees that data won't interleave?


AFAIK, for disk files and processes, yes. For threads, pwrite() should
be used, and when writing to pipes, the size of the write() should not
exceed PIPE_BUF. If it's not the case, I'd like to be enlightened :-)

--
Stefaan
--
As complexity rises, precise statements lose meaning,
and meaningful statements lose precision. -- Lotfi Zadeh
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com