Categorygithub.com/dustin/httputil
modulepackage
0.0.0-20231015075826-29cd04646b69
Repository: https://github.com/dustin/httputil.git
Documentation: pkg.go.dev

# README

HTTP Tracking

HTTP client usage tracking is useful when you have HTTP client activity and want to know more about them. Example:

In-flight HTTP requests:
  servicing GET "http://host1:8484/.cbfs/blob/[oid]" for 56.705274ms
  servicing GET "http://host1:8484/.cbfs/blob/[oid]" for 73.17592ms
  servicing GET "http://host2:8484/.cbfs/blob/[oid]" for 1.528276ms
  servicing GET "http://host3:8484/.cbfs/blob/[oid]" for 20.101718ms

You can also enable stack tracking on each one of those so you can know where they come from. Example:

In-flight HTTP requests:
  servicing GET "http://host1:8484/.cbfs/blob/[oid]" for 23.659896ms
    - net/http.send() - $GOROOT/src/pkg/net/http/client.go:139
    - net/http.(*Client).send() - $GOROOT/src/pkg/net/http/client.go:94
    - net/http.(*Client).doFollowingRedirects() - $GOROOT/src/pkg/net/http/client.go:251
    - net/http.(*Client).Get() - $GOROOT/src/pkg/net/http/client.go:243
    - net/http.Get() - $GOROOT/src/pkg/net/http/client.go:224
    - github.com/couchbaselabs/cbfs/client.fetchWorker.Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/fetch.go:64
    - github.com/couchbaselabs/cbfs/client.(*fetchWorker).Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/client.go:1
    - github.com/dustin/go-saturate.(*Saturator).destWorker() - $GOPATH/src/github.com/dustin/go-saturate/saturate.go:74
  servicing GET "http://host2:8484/.cbfs/blob/[oid]" for 414.055us
    - net/http.send() - $GOROOT/src/pkg/net/http/client.go:139
    - net/http.(*Client).send() - $GOROOT/src/pkg/net/http/client.go:94
    - net/http.(*Client).doFollowingRedirects() - $GOROOT/src/pkg/net/http/client.go:251
    - net/http.(*Client).Get() - $GOROOT/src/pkg/net/http/client.go:243
    - net/http.Get() - $GOROOT/src/pkg/net/http/client.go:224
    - github.com/couchbaselabs/cbfs/client.fetchWorker.Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/fetch.go:64
    - github.com/couchbaselabs/cbfs/client.(*fetchWorker).Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/client.go:1
    - github.com/dustin/go-saturate.(*Saturator).destWorker() - $GOPATH/src/github.com/dustin/go-saturate/saturate.go:74
  servicing GET "http://host1:8484/.cbfs/blob/[oid]" for 617.711758ms
    - net/http.send() - $GOROOT/src/pkg/net/http/client.go:139
    - net/http.(*Client).send() - $GOROOT/src/pkg/net/http/client.go:94
    - net/http.(*Client).doFollowingRedirects() - $GOROOT/src/pkg/net/http/client.go:251
    - net/http.(*Client).Get() - $GOROOT/src/pkg/net/http/client.go:243
    - net/http.Get() - $GOROOT/src/pkg/net/http/client.go:224
    - github.com/couchbaselabs/cbfs/client.fetchWorker.Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/fetch.go:64
    - github.com/couchbaselabs/cbfs/client.(*fetchWorker).Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/client.go:1
    - github.com/dustin/go-saturate.(*Saturator).destWorker() - $GOPATH/src/github.com/dustin/go-saturate/saturate.go:74
  servicing GET "http://host3:8484/.cbfs/blob/[oid]" for 19.561697ms
    - net/http.send() - $GOROOT/src/pkg/net/http/client.go:139
    - net/http.(*Client).send() - $GOROOT/src/pkg/net/http/client.go:94
    - net/http.(*Client).doFollowingRedirects() - $GOROOT/src/pkg/net/http/client.go:251
    - net/http.(*Client).Get() - $GOROOT/src/pkg/net/http/client.go:243
    - net/http.Get() - $GOROOT/src/pkg/net/http/client.go:224
    - github.com/couchbaselabs/cbfs/client.fetchWorker.Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/fetch.go:64
    - github.com/couchbaselabs/cbfs/client.(*fetchWorker).Work() - $GOPATH/src/github.com/couchbaselabs/cbfs/client/client.go:1
    - github.com/dustin/go-saturate.(*Saturator).destWorker() - $GOPATH/src/github.com/dustin/go-saturate/saturate.go:74

Error Reporting

I often find myself wanting to produce better errors out of http requests. It's very common that I want to build an error simply out of the response info. For that, I've created HTTPError:

req, err := http.Get(someUrl)
if err != nil {
    // request didn't work at all
}
defer req.Body.Close()
if req.StatusCode != expectedResponseValue {
    return httputil.HTTPError(res)
}

If you'd like to produce a more custom error message, you can use HTTPErrorf. It works just like *printf, but has two additional format strings:

  • %S - the HTTP status (e.g. 404 Not Found)
  • %B - the HTTP response body itself (up to 512 bytes)

The default error message (from HTTPError) above is "HTTP Error %S - %B". If you wanted to supply more context, you could do something like this:

req, err := http.Get(someUrl)
if err != nil {
    // request didn't work at all
}
defer req.Body.Close()
if req.StatusCode != expectedResponseValue {
    return httputil.HTTPErrorf(res,
        "OMG, something went wrong with %q - got a %S, body follows:\n%B",
        someUrl)
}

# Functions

HTTPError converts an http response into an error.
HTTPErrorf converts an http response into an error.
InitHTTPTracker wraps http.DefaultTransport with a tracking DefaultTransport and installs a SIGINFO handler to report progress.
InitHTTPTracker wraps http.DefaultTransport with a tracking DefaultTransport and does not install a SIGINFO wrapper.
IsHTTPStatus returns true if the given error is caused by an HTTP response with the given HTTP status.

# Structs

HTTPTracker is a http.RoundTripper wrapper that tracks usage of clients.