Skip to content

Instantly share code, notes, and snippets.

@netbrain
Last active September 14, 2020 08:33
Show Gist options
  • Save netbrain/b72d1fb81e77103d0b1f294a683bc5bc to your computer and use it in GitHub Desktop.
Save netbrain/b72d1fb81e77103d0b1f294a683bc5bc to your computer and use it in GitHub Desktop.
Capture CGO output, realtime.
package main
//#include "capture.h"
import "C"
import (
"bufio"
"fmt"
"log"
"os"
"sync"
"syscall"
)
func main() {
outc := CaptureCGOOutput(func() error {
_, err := C.hello()
return err
})
for out := range outc {
if out.Err != nil {
log.Fatal(out.Err)
}
fmt.Printf("%s\n",out.Read)
}
}
var redirectMu sync.Mutex
type RedirectedOutput struct {
Err error
Read []byte
}
func CaptureCGOOutput(call func() error) (outC chan *RedirectedOutput) {
outC = make(chan *RedirectedOutput)
stdout, err := syscall.Dup(syscall.Stdout)
if err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
stderr, err := syscall.Dup(syscall.Stderr)
if err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
r, w, err := os.Pipe()
if err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
go func() {
redirectMu.Lock()
defer redirectMu.Unlock()
defer func() {
C.fflush(nil)
if err := w.Close(); err != nil {
outC <- &RedirectedOutput{Err: err}
}
if err := r.Close(); err != nil {
outC <- &RedirectedOutput{Err: err}
}
}()
if err := syscall.Dup2(int(w.Fd()), syscall.Stdout); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
if err := syscall.Dup2(int(w.Fd()), syscall.Stderr); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
if err := call(); err != nil {
outC <- &RedirectedOutput{Err: err}
}
}()
if err := syscall.Dup2(stdout, syscall.Stdout); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
if err := syscall.Close(stdout); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
if err := syscall.Dup2(stderr, syscall.Stderr); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
if err := syscall.Close(stderr); err != nil {
outC <- &RedirectedOutput{Err: err}
return
}
wg.Wait()
}()
go func() {
br := bufio.NewScanner(r)
br.Split(bufio.ScanLines)
for br.Scan() {
outC<-&RedirectedOutput{Read: br.Bytes()}
}
close(outC)
}()
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment