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

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

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

Swift2.0:使用协议(Protocols)和闭包(Closures)封装一个简单的网络请求类

一,使用闭包封装 一, 验证 二,使用代理

自己动手写一个iOS 网络请求库的三部曲[转]

代码示例:https://github.com/johnlui/Swift-On-iOS/blob/master/BuildYourHTTPRequestLibrary 开源项目:Pitaya,适合大文件上传的 HTTP 请求库:https://github.com/johnlui/Pitaya 本系列文章中,我们将尝试使用 NSURLSession 技术构建一个自己的网络请求库. NSURLSession 简介 NSURLSession 是 iOS7 引入的新网络请求接口,在 WWDC2013

iOS_第3方网络请求_YTKNetwork

github地址:https://github.com/yuantiku/YTKNetwork/blob/master/ProGuide.md YTKNetwork 是什么 YTKNetwork 是猿题库 iOS 研发团队基于 AFNetworking 封装的 iOS 网络库,其实现了一套 High Level 的 API,提供了更高层次的网络访问抽象. YTKNetwork提供了哪些功能 相比 AFNetworking,YTKNetwork 提供了以下更高级的功能: 支持按时间缓存网络请求内容

NSMutableUrlRequest自定义封装网络请求

1.首先封装一个自己的网络请求的类 **这里表视图引入了第三方类库:MJRefresh 上拉刷新下拉加载 这是.h文件 #import <Foundation/Foundation.h> typedef void(^SuccessBlock)(NSData *data); typedef void(^ErrorBlock)(NSError *error); @interface RequestMethod : NSObject @property (nonatomic, copy) Succe

基于AFNetWorking搭建APP的网络请求框架[iOS]

自从AFNetWorking(下文简称AFN)更新2.0版本之后,AFN的许多的问题得到的有效的解决,写法也得到了完善.前期主流的第三方网络类库 ASI作者宣布不再维护,国内大多数的主流APP都逐步接受并开始采用AFN.出于各自公司项目的不同需要,大家都会在AFN的基础上加一层不尽相同的封 装.很多新APP在选择方式时也会非常纠结.如何封装才可以让AFN更有效率更方便的应用于项目呢,对于这个问题,各人有各人的看法.基于做过以及读过的 几个项目,也来谈一下如何搭建一个APP的网络请求框架.由于本人

iOS原生态网络请求

1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 2 3 4 NSString *urlString=@“网址·······”; 5 NSURL *url=[[NSURL alloc] initWithString:urlString]; 6 NSURLRequest *request=[[NSURLRequest all

iOS 开发 把握AFNet网络请求完成的正确时机

前言 对于iOS开发中的网络请求模块,AFNet的使用应该是最熟悉不过了,但你是否把握了网络请求正确的完成时机?本篇文章涉及线程同步.线程依赖.线程组等专用名词的含义,若对上述名词认识模糊,可先进行查阅理解后阅读本文.如果你也纠结于文中所述问题,可进行阅读希望对你有所帮助.大神无视勿喷. 在真实开发中,我们通常会遇到如下问题: 一.某界面存在多个请求,希望所有请求均结束才进行某操作. 对于这一问题的解决方案很容易想到通过线程组进行实现.代码如下: 1 2 3 4 5 6 7 8 9 10 11

Android探索之基于okHttp打造自己的网络请求&lt;Retrofit+Okhttp&gt;(五)

前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少收有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下Retrofit+Okhttp的搭配使用. Retrofit介绍: Retrofit和okHttp师出同门,也是Square的开源库,它是一个类型安全的网络请求库,Retrofit简化了网络请求流程,基于OkHtttp做了封装,解耦的更彻底:比方说通过注解来配置请求参数,通过工厂来生成CallAdap

Android 网络请求json数据,解析json数据,生成对应的java bean类一步到位,快速开发

Android 网络请求一般都涉及到图片和JSON数据,怎样快速的请求网络JSON数据,解析JSON数据,并且一步生成自己想要的Java bean实体类?这个涉及到Android 开发效率的问题.由于接触Android 网络这方面比较多,自然就找到一些好的方法来快速开发Android 网络模块的相关内容,接下来就为大家揭晓 一步快速请求,解析JSON 数据生成对应的Java bean实体类的方法. 注:我们先把思路讲解下吧: 1.网络请求JSON数据代码可以自己写,当然我还是推荐使用网络上开源的