生命不止,继续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
时间: 2024-10-19 18:10:48