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三个包
实现一个结构体
其中http.RoudTripper:
RoundTripper is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request.
实现一个接口HTTPLogger
实现函数:
完整代码
使用
实现接口:
完整代码:
结果:
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语言中的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实战--实现一个简单的tcp服务端和客户端(The way to go)
- Go实战--实现一个并发时钟服务器(The way to go)
- Go实战--实现一个简单聊天室chatroom(The way to go)
- Go实战--实现一个单向链表(The way to go)
- Go实战--实现简单的restful api(The way to go)
- Go实战--net/http中JSON的使用(The way to go)
- Go实战--xml与json相互转换(The way to go)
- Go实战--go中编码转换(The way to go)
- Go实战--golang新手入门常见错误(The way to go)
- Go实战--go中函数递归(recursion)的使用(The way to go)
- Go实战--go中使用cookie(The way to go)
- Go语言学习之net/http包(The way to go)
- Go实战--go语言中执行shell脚本(The way to go)
- Go实战--go中使用base64加密(The way to go)
- Go实战--go中使用google/protobuf(The way to go)
- Go实战--go中使用libphonenumber(The way to go)
- Go实战--go中函数(function)和方法(method)的使用(The way to go)
- Go实战--go中使用rpc(The way to go)
- Go实战--go中使用hmac sha256(The way to go)
- Go实战--压缩zip和解压缩unzip的应用(The way to go)