2016-07-28 9 views
1

Ich möchte eine Situation erstellen, in der alles auf einen bestimmten log.Logger wird auch an eine bestimmte Variable Array von Strings angehängt.io.MultiWriter vs. Golangs Pass-by-Wert

Der Typ der Variablen implementiert die io.Writer-Schnittstelle, daher sollte es einfach sein, diese über io.MultiWriter zu log.New() hinzuzufügen, aber ich habe anscheinend ein unlösbares Problem: Die io.Writer-Schnittstelle ist behoben und es ist unmöglich für die Variable, sich auf den gegebenen Wert von Golan zu beziehen.

Vielleicht wird es mehr Sinn, mit einem Beispiel machen:

package main 

import "fmt" 
import "io" 
import "log" 
import "os" 
import "strings" 

var Log *log.Logger 

type Job_Result struct { 
    Job_ID int64 
    // other stuff 
    Log_Lines []string 
} 

// satisfies io.Writer interface 
func (jr Job_Result) Write (p []byte) (n int, err error) { 
    s := strings.TrimRight(string(p),"\n ") 
    jr.Log_Lines= append(jr.Log_Lines,s) 
    return len(s), nil 
} 

func (jr Job_Result) Dump() { 
    fmt.Println("\nHere is a dump of the job result log lines:") 
    for n, s := range jr.Log_Lines{ 
     fmt.Printf("\tline %d: %s\n",n,s) 
    } 
} 

func main() { 

    // make a Job_Result 

    var jr Job_Result 
    jr.Job_ID = 123 
    jr.Log_Lines = make([]string,0) 

    // create an io.MultiWriter that points to both stdout 
    // and that Job_Result var 

    var writers io.Writer 
    writers = io.MultiWriter(os.Stdout,jr) 

    Log = log.New(writers, 
     "", 
     log.Ldate|log.Ltime|log.Lshortfile) 

    // send some stuff to the log 

    Log.Println("program starting") 
    Log.Println("something happened") 
    Log.Printf("last thing that happened, should be %drd line\n",3) 

    jr.Dump() 

} 

Dies ist die Ausgabe, was nicht verwunderlich ist:

2016/07/28 07:20:07 testjob.go:43: program starting 
2016/07/28 07:20:07 testjob.go:44: something happened 
2016/07/28 07:20:07 testjob.go:45: last thing that happened, should be 3rd line 

Here is a dump of the job result log lines: 

Ich verstehe das Problem - Write() wird immer eine Kopie der Job_Result-Variable, so dass es pflichtgemäß angehängt wird und dann verschwindet die Kopie, da sie lokal ist. Ich sollte ihm einen Zeiger auf den Job_Result übergeben ... aber ich bin nicht der, der Write() aufruft, es wird vom Logger gemacht, und ich kann das nicht ändern.

Ich dachte, dies wäre eine einfache Lösung für die Erfassung von Protokollausgaben in ein Array (und es gibt andere Subscribe/Unsubscribe Zeug, die ich nicht angezeigt habe), aber es kommt alles auf diese problematische io.Write() Schnittstelle.

Pilotfehler? Schlechtes Design? Etwas, das ich nicht groke? Danke für jeden Hinweis.

Antwort

2

die Schreibfunktion neu zu definieren (wird nun Empfänger Zeiger)

// satisfies io.Writer interface 
func (jr *Job_Result) Write (p []byte) (n int, err error) { 
    s := strings.TrimRight(string(p),"\n ") 
    jr.Log_Lines= append(jr.Log_Lines,s) 
    return len(s), nil 
} 

initialisieren

jr := new(Job_Result) // makes a pointer. 

Rest wie bleibt. Auf diese Weise implementiert *Job_Result weiterhin io.Writer, verliert jedoch nicht den Status.

Das Go-Tutorial bereits gesagt, wenn eine Methode den Empfänger ändert, sollten Sie wahrscheinlich einen Zeiger Empfänger verwenden, oder die Änderungen verloren gehen. Das Arbeiten mit einem Zeiger anstelle des eigentlichen Objekts hat wenig Nachteil, wenn Sie sicherstellen wollen, dass es genau ein Objekt gibt. (Und ja, es ist technisch kein Objekt).

+0

Einfach und elegant. Ich habe mich zu sehr darauf konzentriert, dafür zu sorgen, dass die Write() -Signatur übereinstimmt, dass ich den Rest vergessen habe. Vielen Dank! – raindog308

Verwandte Themen