httputil

package module
v0.0.0-...-e5278ee Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 27, 2026 License: MIT Imports: 12 Imported by: 47

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)
}

Documentation

Overview

Package httputil provides a small junk drawer of http client and server helpers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HTTPError

func HTTPError(res *http.Response) error

HTTPError converts an http response into an error.

Note that this reads the body, so only use it when the response exists and you don't believe it's valid for your needs.

func HTTPErrorf

func HTTPErrorf(res *http.Response, format string, args ...interface{}) error

HTTPErrorf converts an http response into an error.

This allows for standard printf-style formatting with the addition of %S for the http status (e.g. "404 Not Found") and %B for the body that was returned along with the error.

Note that this reads the body, so only use it when the response exists and you don't believe it's valid for your needs.

func IsHTTPStatus

func IsHTTPStatus(err error, status int) bool

IsHTTPStatus returns true if the given error is caused by an HTTP response with the given HTTP status.

Types

type HTTPTracker

type HTTPTracker struct {
	// Next is the RoundTripper being wrapped
	Next http.RoundTripper
	// TrackStacks will record user stacks if true.
	TrackStacks bool
	// contains filtered or unexported fields
}

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

The easiest way to use http tracker for a commandline tool is to just call InitHTTPTracker:

httputil.InitHTTPTracker(false)

This wraps the current http.DefaultTransport with a tracking transport and installs a SIGINFO handler to report the current state on demand.

If you have a web server that is also an HTTP client and uses expvar, you can publish an expvar version of the data with the following, similar invocation:

expvar.Publish("httpclients", httputil.InitHTTPTracker(false))

The boolean parameter in the above examples determines whether stacks are also tracked. See the docs for InitHTTPTracker for more details.

func InitHTTPTracker

func InitHTTPTracker(trackStacks bool) *HTTPTracker

InitHTTPTracker wraps http.DefaultTransport with a tracking DefaultTransport and installs a SIGINFO handler to report progress.

If trackStacks is true, the call stack will be included with tracking information and reports.

func InitHTTPTrackerOnly

func InitHTTPTrackerOnly(trackStacks bool) *HTTPTracker

InitHTTPTracker wraps http.DefaultTransport with a tracking DefaultTransport and does not install a SIGINFO wrapper.

If trackStacks is true, the call stack will be included with tracking information and reports.

func (*HTTPTracker) CancelRequest

func (t *HTTPTracker) CancelRequest(req *http.Request)

func (*HTTPTracker) Close

func (t *HTTPTracker) Close() error

Close shuts down this tracker.

func (*HTTPTracker) MarshalJSON

func (t *HTTPTracker) MarshalJSON() ([]byte, error)

MarshalJSON provides a JSON representation of the state of tracker.

func (*HTTPTracker) Report

func (t *HTTPTracker) Report(w io.Writer)

Report writes a textual report of the current state of HTTP clients to the given writer.

func (*HTTPTracker) ReportLoop

func (t *HTTPTracker) ReportLoop(w io.Writer, ch <-chan os.Signal)

ReportLoop will issue a report on the given Writer whenever it receives a signal on the given channel.

This primarily exists for signal handlers.

func (*HTTPTracker) RoundTrip

func (t *HTTPTracker) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip satisfies http.RoundTripper

func (*HTTPTracker) String

func (t *HTTPTracker) String() string

String produces a JSON formatted representation of the tracker state. This is directly useful to expvar.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL