您的位置:首页 > 理论基础 > 计算机网络

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

2017-04-19 00:11 661 查看
生命不止,继续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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: