生命不止,繼續go go go~~~
之前我們簡要介紹了go語言中的log package 和 net/http package,那麼我們今天就乾點實事兒,將二者結合,實現我們自己的日誌記錄網路請求。
另外,我們還沒有跟你介紹time package,但是也可以看懂的。
首先,我預設你瞭解go語言的組織結構。
匯入需要的package我們需要 log net/http time三個包
```package httploggerimport ( "log" "net/http" "time")```
實現一個結構體```type loggedRoundTripper struct { rt http.RoundTripper log HTTPLogger}```
其中http.RoudTripper:
RoundTripper is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request.
實現一個介面HTTPLogger```type HTTPLogger interface { LogRequest(*http.Request) LogResponse(*http.Request, *http.Response, error, time.Duration)}```
實現函式:
```type DefaultLogger struct {}func (dl DefaultLogger) LogRequest(*http.Request) {}func (dl DefaultLogger) LogResponse(req *http.Request, res *http.Response, err error, duration time.Duration) { duration /= time.Millisecond if err != nil { log.Printf("HTTP Request method=%s host=%s path=%s status=error durationMs=%d error=%q", req.Method, req.Host, req.URL.Path, duration, err.Error()) } else { log.Printf("HTTP Request method=%s host=%s path=%s status=%d durationMs=%d", req.Method, req.Host, req.URL.Path, res.StatusCode, duration) }}```
完整程式碼```package httploggerimport ( "log" "net/http" "time")type loggedRoundTripper struct { rt http.RoundTripper log HTTPLogger}func (c *loggedRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { c.log.LogRequest(request) startTime := time.Now() response, err := c.rt.RoundTrip(request) duration := time.Since(startTime) c.log.LogResponse(request, response, err, duration) return response, err}// NewLoggedTransport takes an http.RoundTripper and returns a new one that logs requests and responsesfunc NewLoggedTransport(rt http.RoundTripper, log HTTPLogger) http.RoundTripper { return &loggedRoundTripper{rt: rt, log: log}}// HTTPLogger defines the interface to log http request and responsestype HTTPLogger interface { LogRequest(*http.Request) LogResponse(*http.Request, *http.Response, error, time.Duration)}// DefaultLogger is an http logger that will use the standard logger in the log package to provide basic information about http responsestype DefaultLogger struct {}// LogRequest doens't do anything since we'll be logging replies onlyfunc (dl DefaultLogger) LogRequest(*http.Request) {}// LogResponse logs path, host, status code and duration in millisecondsfunc (dl DefaultLogger) LogResponse(req *http.Request, res *http.Response, err error, duration time.Duration) { duration /= time.Millisecond if err != nil { log.Printf("HTTP Request method=%s host=%s path=%s status=error durationMs=%d error=%q", req.Method, req.Host, req.URL.Path, duration, err.Error()) } else { log.Printf("HTTP Request method=%s host=%s path=%s status=%d durationMs=%d", req.Method, req.Host, req.URL.Path, res.StatusCode, duration) }}// DefaultLoggedTransport wraps http.DefaultTransport to log using DefaultLoggervar DefaultLoggedTransport = NewLoggedTransport(http.DefaultTransport, DefaultLogger{})```
使用實現介面:
```type httpLogger struct { log *log.Logger}func newLogger() *httpLogger { return &httpLogger{ log: log.New(os.Stderr, "log - ", log.LstdFlags), }}func (l *httpLogger) LogRequest(req *http.Request) { l.log.Printf( "Request %s %s", req.Method, req.URL.String(), )}func (l *httpLogger) LogResponse(req *http.Request, res *http.Response, err error, duration time.Duration) { duration /= time.Millisecond if err != nil { l.log.Println(err) } else { l.log.Printf( "Response method=%s status=%d durationMs=%d %s", req.Method, res.StatusCode, duration, req.URL.String(), ) }}```
完整程式碼:
```package mainimport ( "log" "net/http" "os" "time" "httplogger/httplogger")func main() { client := http.Client{ Transport: httplogger.NewLoggedTransport(http.DefaultTransport, newLogger()), } client.Get("https://www.baidu.com")}type httpLogger struct { log *log.Logger}func newLogger() *httpLogger { return &httpLogger{ log: log.New(os.Stderr, "log - ", log.LstdFlags), }}func (l *httpLogger) LogRequest(req *http.Request) { l.log.Printf( "Request %s %s", req.Method, req.URL.String(), )}func (l *httpLogger) LogResponse(req *http.Request, res *http.Response, err error, duration time.Duration) { duration /= time.Millisecond if err != nil { l.log.Println(err) } else { l.log.Printf( "Response method=%s status=%d durationMs=%d %s", req.Method, res.StatusCode, duration, req.URL.String(), ) }}```
結果:
log - 2017/04/18 23:39:41 Request GET https://www.baidu.com
log - 2017/04/18 23:39:42 Response method=GET status=200 durationMs=614 https://www.baidu.com
最新評論