Go实战--实现一个自己的网络请求日志httplogger(The way to go)

来源:互联网 发布:usb网络接口转换器 编辑:程序博客网 时间:2024/04/30 22:00

生命不止,继续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

这里写图片描述

2 0