redirect already running processes stdout

1,390 views
Skip to first unread message

ethanl...@gmail.com

unread,
Jul 1, 2016, 1:35:28 PM7/1/16
to golang-nuts
I am starting to look into intercepting a running processes output. I know how to do this manually by look at /proc/$PID/fd/1 or by using gdb etc. I do not want to use os.exec and then join the child processes output with the parent. I want to start Process A and capture the output of A in Process B.  Does anyone have any advice on where to start or an opinion on why I should just use os.exec ? Any advice/help would be great !  

example :

Process A
pid : 1234

output : Hello world 
output : Hello world 
output : Hello world 
output : Hello world 

Process B 
pid : 5678

reads from process A 

output : From B - Hello world 
output : From B - Hello world  
output : From B - Hello world 
output : From B - Hello world  

I don't want to have to exec the process from my go application like this : 
func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command("ls", "-l")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
}

C Banning

unread,
Jul 1, 2016, 2:12:54 PM7/1/16
to golang-nuts, ethanl...@gmail.com

Konstantin Khomoutov

unread,
Jul 1, 2016, 2:34:50 PM7/1/16
to ethanl...@gmail.com, golang-nuts
On Fri, 1 Jul 2016 10:28:59 -0700 (PDT)
ethanl...@gmail.com wrote:

> I am starting to look into intercepting a running processes output. I
> know how to do this manually by look at /proc/$PID/fd/1 or by using
> gdb etc. I do not want to use os.exec and then join the child
> processes output with the parent. I want to start Process A and
> capture the output of A in Process B. Does anyone have any advice on
> where to start or an opinion on why I should just use os.exec ? Any
> advice/help would be great !

I'm afraid that this would be inherently kludgy.

As C Banning hinted, the standard output (and input) streams of a
process are _already_ connected to somewhere when a process starts up
by an operating system. They can be opened to a file or something
resembling a file -- such as an OS pipe or a socket.

Hence what you want is "retargetting" an already opened and existing
file descriptor of a foreign process, which is not something available
in the "standard" set of system calls.

If, for some reason, you still dearly need to do something like this,
try looking at reptyr [1] which plays dirty unportable tricks with
ptrace().

In any case it would be interesting to hear _why_ would you need that.

1. https://github.com/nelhage/reptyr

ethanl...@gmail.com

unread,
Jul 1, 2016, 4:22:22 PM7/1/16
to golang-nuts, ethanl...@gmail.com
Thanks for the answers ! I will check reptyr out. I have looked at trying to rewrite https://github.com/jerome-pouiller/reredirect which seems to be similar to what I am looking for. I want this because I would like to write a application to catch stdout of another process for logging purposes. From the applications execution side I didn't want to make any changes. Just start the application that outputs to stdout and then start my application to capture the output. I have multiple applications that have a lot of command line flags and didn't want to have to worry about executing them threw os.exec. I thought it would be nice to be able to pass a PID and redirect any stdout to my application. After looking into it more I do understand that its a odd task haha. 

as....@gmail.com

unread,
Jul 1, 2016, 5:21:58 PM7/1/16
to golang-nuts
Most systems don't support this functionality without a kernel patch or debugger trick. You can manipulate the file descriptor before the process is born, everything afterwards is luck or system specific. In Go, you have a lot more power:

os.Stdout, os. Stderr = os.Stderr, os.Stdout

fmt.Println("?")

I recommend the os.Exec approach

Konstantin Khomoutov

unread,
Jul 4, 2016, 8:50:13 AM7/4/16
to ethanl...@gmail.com, golang-nuts
On Fri, 1 Jul 2016 13:22:09 -0700 (PDT)
ethanl...@gmail.com wrote:

[...]
> I have multiple applications that have a lot of command line flags and
> didn't want to have to worry about executing them threw os.exec.

But this is super-simple to have in fact.
In the simplest case just stick os.Args of your Go program into the
command line you're building with os/exec.Cmd() and then all the
command-line arguments you pass to your Go wrapper will be passed to
the program it will call.

If you want it to be more fancy and have your Go program understand its
own command-line arguments, then first scan os.Args for a special
argument "--", and then use whatever precedes it as a set of
command-line arguments for your Go program through flag.NewFlagSet()
and the FlagSet's Parse() method, which accepts a slice of strings to
parse, and use what follows that special argument "--" as the
command-line arguments for the program to call. That's a pretty
standard practice to handle such cases.

To reiterate, I think you're trying to approach your problem from the
wrong end. Messing with ptrace()-ing a running program is kewl, but
real-world programming is not really about kewl solutions but rather
simple and robust ones (and that which could be understood by reading
the code after six months).

[...]

Maksym

unread,
Mar 3, 2019, 11:24:23 AM3/3/19
to golang-nuts
Hello!
Did you achieved some progress in this project?
Reply all
Reply to author
Forward
0 new messages