2016-04-18 8 views
2

Ich frage mich, ob es eine Möglichkeit gibt, die Antworten zu protokollieren, wenn Sie ListenAndServe verwenden.Go HTTP ListenAndServe Protokollantwort

Soweit ich sagen kann, hat der Handler keinen Zugriff auf ein "Response" -Objekt. Nur ein ResponseWriter, also kann ich nicht httputil.DumpResponse aufrufen.

+0

Müssen Sie die gesamte Antwort protokollieren? Sind nur die Header OK? – elithrar

Antwort

0

http.ResponseWriter ist eine Schnittstelle. Sie können die Einbettung verwenden, um sie für die Protokollierung wie folgt zu erweitern.

package main 
import (
    "log" 
    "net/http" 
) 

func sampleHandler(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusOK) 
    response := []byte("Sample Response") 
    w.Write(response) 
} 

type loggingResponseWriter struct { 
    status int 
    body []byte 
    http.ResponseWriter 
} 

func (w *loggingResponseWriter) WriteHeader(code int) { 
    w.status = code 
    w.ResponseWriter.WriteHeader(code) 
} 

func (w *loggingResponseWriter) Write(body []byte) (int, error) { 
    w.body = body 
    return w.ResponseWriter.Write(body) 
} 

func responseLogger(h http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     loggingRW := &loggingResponseWriter{ 
      ResponseWriter: w, 
     } 
     h.ServeHTTP(loggingRW, r) 
     log.Println("Status : ", loggingRW.status, "Response : ", string(loggingRW.body)) 
    }) 
} 

func main() { 
    http.Handle("/", responseLogger(http.HandlerFunc(sampleHandler))) 
    http.ListenAndServe(":8080", nil) 
} 

Sie können die Handlerfunktionen, für die Sie Antworten protokollieren möchten, mit responseLogger umbrechen.

+1

Ehrfürchtig. Vielen Dank –

0

Sie können nicht, weil die Antwort technisch nicht existiert, bis Sie es in die ResponseWriter schreiben.

Aber im response ist nur die header, body und response code so in der Handler-Funktion Sie Methode Header() auf den ResponseWriter können den Header bekommen und dann können Sie die response code und die body anmelden, bevor Sie es an die ResponseWriter schreiben .

Wenn Sie ein Beispiel dafür angeben, was Sie zu tun versuchen, kann ich näher erläutern, wie Sie es tun können.

Dies ist, was ich dies für ein kleines Projekt zu beheben tat: Ich benutze dies in allen meinen Handler:

type transaction struct { 
    res Response // Create this type also 
    req Request // Create this type also 
} 

func NewTransaction(w http.ResponseWriter, req *http.Request) *transaction{} 

Log := make(chan transaction, 100) 
go func{ 
    // Read from channel and log the info however you want. 
}() 

func indexHandler(w http.ResponseWriter, req *http.Request) { 
    tx := NewTransaction(w, req) // Struct with the request and response 
    defer func() { 
     Log <- tx 
    }() 

    /* 
    Handle request here 
    */ 

    // Update request and response 
    Request.Body = body 
} 

Und am Ende der Behandlungsfunktion, nachdem die angeforderten Daten gedient hat, ich Aktualisieren Sie die Werte für die Anfrage und die Antwort.

Und eine Goroutine hören auf den Kanal Log und machen Sie alle Ihre Protokollierung.

Sie können auch eine Wrapper-Funktion schreiben, die die Datei bereitstellt und die Antwort zurückgibt.

+0

Das Problem mit diesem Ansatz ist, dass es nicht skaliert. Ich habe Hunderte von Handler-Funktionen, also möchte ich nicht immer dasselbe machen. Ich würde es lieber an einem zentralen Ort machen. –

+0

@SFO Sie haben Recht. Ich habe ein Beispiel hinzugefügt, wie ich dieses Problem zuvor gelöst habe. Ist nicht so gut wie es sein könnte, aber es ist ein Anfang. – Topo

0

Als Alternative kann man fasthttp verwenden.