Skip to content

Commit

Permalink
Bake UserAgent into http.Clients (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbourgon authored Jan 19, 2022
1 parent 01211fb commit fa14e95
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 35 deletions.
11 changes: 8 additions & 3 deletions cmd/fastly-exporter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,16 @@ func main() {
apiLogger = log.With(logger, "component", "api.fastly.com")
}

var userAgent string
{
userAgent = `Fastly-Exporter (` + programVersion + `)`
}

var apiClient *http.Client
{
apiClient = &http.Client{
Timeout: apiTimeout,
Timeout: apiTimeout,
Transport: userAgentTransport(http.DefaultTransport, userAgent),
}
}

Expand Down Expand Up @@ -289,11 +295,10 @@ func main() {
{
var (
rtLogger = log.With(logger, "component", "rt.fastly.com")
rtClient = &http.Client{Timeout: rtTimeout}
rtClient = &http.Client{Timeout: rtTimeout, Transport: userAgentTransport(http.DefaultTransport, userAgent)}
subscriberOptions = []rt.SubscriberOption{
rt.WithLogger(rtLogger),
rt.WithMetadataProvider(serviceCache),
rt.WithUserAgent(`Fastly-Exporter (` + programVersion + `)`),
}
)
manager = rt.NewManager(serviceCache, rtClient, token, registry, subscriberOptions, rtLogger)
Expand Down
14 changes: 14 additions & 0 deletions cmd/fastly-exporter/transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "net/http"

type roundTripperFunc func(*http.Request) (*http.Response, error)

func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) }

func userAgentTransport(next http.RoundTripper, userAgent string) http.RoundTripper {
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
req.Header.Set("User-Agent", userAgent)
return next.RoundTrip(req)
})
}
25 changes: 25 additions & 0 deletions cmd/fastly-exporter/transport_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"net/http"
"net/http/httptest"
"testing"
)

func TestUserAgentTransport(t *testing.T) {
c := make(chan string, 1)
handler := func(_ http.ResponseWriter, r *http.Request) { c <- r.Header.Get("User-Agent") }
server := httptest.NewServer(http.HandlerFunc(handler))
defer server.Close()

userAgent := "something"
transport := userAgentTransport(http.DefaultTransport, userAgent)
client := &http.Client{Transport: transport}
if _, err := client.Get(server.URL); err != nil {
t.Fatal(err)
}

if want, have := userAgent, <-c; want != have {
t.Fatalf("want %q, have %q", want, have)
}
}
13 changes: 0 additions & 13 deletions pkg/rt/subscriber.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ type MetadataProvider interface {
// It emits the received real-time stats data to Prometheus.
type Subscriber struct {
client HTTPClient
userAgent string
token string
serviceID string
provider MetadataProvider
Expand All @@ -44,12 +43,6 @@ type Subscriber struct {
// SubscriberOption provides some additional behavior to a subscriber.
type SubscriberOption func(*Subscriber)

// WithUserAgent sets the User-Agent supplied to rt.fastly.com.
// By default, the DefaultUserAgent is used.
func WithUserAgent(ua string) SubscriberOption {
return func(s *Subscriber) { s.userAgent = ua }
}

// WithMetadataProvider sets the resolver used to look up service names and
// versions. By default, a no-op metadata resolver is used, which causes each
// service to have its name set to its service ID, and its version set to
Expand All @@ -71,16 +64,11 @@ func WithPostprocess(f func()) SubscriberOption {
return func(s *Subscriber) { s.postprocess = f }
}

// DefaultUserAgent passed to rt.fastly.com.
// To change, use the WithUserAgent option.
const DefaultUserAgent = "Fastly-Exporter (unknown version)"

// NewSubscriber returns a ready-to-use subscriber.
// Run must be called to update the metrics.
func NewSubscriber(client HTTPClient, token, serviceID string, metrics *gen.Metrics, options ...SubscriberOption) *Subscriber {
s := &Subscriber{
client: client,
userAgent: DefaultUserAgent,
token: token,
serviceID: serviceID,
metrics: metrics,
Expand Down Expand Up @@ -147,7 +135,6 @@ func (s *Subscriber) query(ctx context.Context, ts uint64) (currentName string,
return name, apiResultError, 0, ts, fmt.Errorf("error constructing real-time stats API request: %w", err)
}

req.Header.Set("User-Agent", s.userAgent)
req.Header.Set("Fastly-Key", s.token)
req.Header.Set("Accept", "application/json")
resp, err := s.client.Do(req.WithContext(ctx))
Expand Down
19 changes: 0 additions & 19 deletions pkg/rt/subscriber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,25 +79,6 @@ func TestSubscriberNoData(t *testing.T) {
assertMetricOutput(t, want, have)
}

func TestUserAgent(t *testing.T) {
var (
client = newMockRealtimeClient(`{}`)
userAgent = "Some user agent string"
metrics = gen.NewMetrics("ns", "ss", filter.Filter{}, prometheus.NewRegistry())
processed = make(chan struct{})
postprocess = func() { close(processed) }
options = []rt.SubscriberOption{rt.WithUserAgent(userAgent), rt.WithPostprocess(postprocess)}
subscriber = rt.NewSubscriber(client, "token", "service_id", metrics, options...)
)
go subscriber.Run(context.Background())

<-processed

if want, have := userAgent, client.lastUserAgent; want != have {
t.Errorf("User-Agent: want %q, have %q", want, have)
}
}

func TestBadTokenNoSpam(t *testing.T) {
var (
client = &countingRealtimeClient{code: 403, response: `{"Error": "unauthorized"}`}
Expand Down

0 comments on commit fa14e95

Please sign in to comment.