2016-07-06 26 views
1

Ich möchte in einer Datei erfassen und speichern alle stdout und stderr, wie man richtig alle stdout/stderr erfassen

Zu Testzwecken ich nur den Druck, was ich mit diesem erfassen:

Paket Haupt

import (
    "bufio" 
    "bytes" 
    "fmt" 
    "io" 
    "os/exec" 
) 

func main() { 
    cmd := exec.Command("/tmp/stdout") 
    stdout := new(bytes.Buffer) 
    stderr := new(bytes.Buffer) 

    cmd.Stdout = stdout 
    cmd.Stderr = stderr 

    if err := cmd.Start(); err != nil { 
     panic(err) 
    } 

    if err := cmd.Wait(); err != nil { 
     panic(err) 
    } 

    in := bufio.NewScanner(io.MultiReader(stdout, stderr)) 
    for in.Scan() { 
     fmt.Println(in.Text()) 
    } 

} 

Die /tmp/stdout Befehl kann mit diesem Code sein bauen:

package main 

import (
    "fmt" 
    "os" 
    "time" 
) 

func main() { 

    for i := 1; i < 1000; i++ { 
     if i%3 == 0 { 
      fmt.Fprintf(os.Stderr, "STDERR i: %d\n", i) 
     } else { 
      fmt.Printf("STDOUT i: %d\n", i) 
     } 
     time.Sleep(1 * time.Second) 
    } 

} 

Aus irgendeinem Grund bin ich nicht verfügbar gewesen etwas von dem Ausgang zu erfassen, wenn ich die /tmp/stdout Befehl ausführen ich dieses:

$ /tmp/stdout 
STDOUT i: 1 
STDOUT i: 2 
STDERR i: 3 
STDOUT i: 4 
STDOUT i: 5 
STDERR i: 6 
STDOUT i: 7 

Ich erwartete verfügbar sein, um die gleiche Leistung zu erhalten, während sie telefonieren von dem vorherigen Code gehen, ist die seltsame Sache, dass, wenn ich zum Befehl, um so etwas wie id, whoamiuname bin ich bekomme das Ergebnis und kann gedruckt werden, daher wundernd, was könnte falsch sein.

Irgendwelche Ideen?

UPDATE

gefunden, dass ich das Programm warten müssen, um zu beenden, wie es in den Kommentaren, um die Ausgabe, aber im Falle vorgeschlagen zu bekommen würde Ich mag die Ausgabe in Echtzeit erhalten, wie konnte ich erreichen dies, was könnte der beste Weg, es zu tun, entweder io.Copy ein os.Pipe, etc?

+1

Haben Sie warten eigentlich die verwenden müssen 1000 Sekunden für '/ tmp/stdout' zu beenden? Beachten Sie, dass 'cmd.Wait()' Ihr Programm blockiert, bis der Befehl beendet ist. – helmbert

+0

Probieren Sie go-logging http://stackoverflow.com/questions/38208608/go-logging-to-multiple-output/38208892#38208892 –

+0

Versuchen Sie, "os.Stdout" mit "fmt.Fprintf" zu kombinieren, um es zu behalten Einfach, aber wenn Sie eine professionellere Lösung wünschen, verwenden Sie die Protokollierung wie bereits vorgeschlagen. –

Antwort

1

aber im Fall würde Ich mag die Ausgabe in Echtzeit erhalten

Eine Möglichkeit, das zu tun ist os.Stdout zu cmd.Stdout

oCmd := exec.Command(bin, cmdArgs...) 
oCmd.Stdout = os.Stdout 
oCmd.Stderr = os.Stderr 

err := oCmd.Run() 

Dann können Sie eine Datei stattdessen befestigen mit f,_ := os.Create("file").

Wenn Sie es sowohl in einer Datei und zum Terminal zur gleichen Zeit zu schreiben, ich vermute (ich habe das noch nicht getan), dass Sie

io.Mutiwriters
f, _ := os.Create("file") 
cmd.Stdout = io.MultiWriter(os.Stdout, f) 
+0

anriefen Danke, aber ich denke, dass ich gorutines verwenden muss, wenn ich ohne Notwendigkeit zu warten handhaben möchte, falls ich zum Beispiel die Ausgabe statt vor analysieren möchte Senden Sie es direkt in eine Datei, so etwas wie ein Logger. – nbari

+1

afaik, in go, musst du einen Autor erstellen und einen Schriftsteller schreiben. cmd.Stdout-> schreiben-> Parser-> schreiben-> os.Stdout. Was die Goroutines angeht, mach einfach ein 'go func (done chan) {}'. Dazu gibt es einige Muster. –