码迷,mamicode.com
首页 > Web开发 > 详细

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

时间:2017-04-19 10:26:10      阅读:328      评论:0      收藏:0      [点我收藏+]

标签:host   perl   struct   pack   记录   csdn   ring   tps   com   

生命不止,继续go go go~~~

之前我们简要介绍了go语言中的log package 和 net/http package,那么我们今天就干点实事儿,将二者结合,实现我们自己的日志记录网络请求。

另外,我们还没有跟你介绍time package,但是也可以看懂的。

首先,我默认你了解go语言的组织结构。

导入需要的package
我们需要 log net/http time三个包

package httplogger

import (
    "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 httplogger

import (
    "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 responses
func NewLoggedTransport(rt http.RoundTripper, log HTTPLogger) http.RoundTripper {
    return &loggedRoundTripper{rt: rt, log: log}
}

// HTTPLogger defines the interface to log http request and responses
type 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 responses
type DefaultLogger struct {
}

// LogRequest doens‘t do anything since we‘ll be logging replies only
func (dl DefaultLogger) LogRequest(*http.Request) {
}

// LogResponse logs path, host, status code and duration in milliseconds
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)
    }
}

// DefaultLoggedTransport wraps http.DefaultTransport to log using DefaultLogger
var 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 main

import (
    "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

技术分享

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

标签:host   perl   struct   pack   记录   csdn   ring   tps   com   

原文地址:http://blog.csdn.net/wangshubo1989/article/details/70234319

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!