Skip to content

Commit

Permalink
bitswap/httpnet: collect metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
hsanjuan committed Jan 16, 2025
1 parent 54b1dbe commit 016a7e5
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
3 changes: 3 additions & 0 deletions bitswap/network/httpnet/httpnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ type httpnet struct {
supportsHave bool
insecureSkipVerify bool
allowlist map[string]struct{}

metrics *metrics
}

// New returns a BitSwapNetwork supported by underlying IPFS host.
Expand All @@ -143,6 +145,7 @@ func New(host host.Host, opts ...Option) *httpnet {
maxIdleConns: DefaultMaxIdleConns,
supportsHave: DefaultSupportsHave,
insecureSkipVerify: DefaultInsecureSkipVerify,
metrics: newMetrics(),
}

for _, opt := range opts {
Expand Down
131 changes: 131 additions & 0 deletions bitswap/network/httpnet/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package httpnet

import (
"context"

imetrics "github.com/ipfs/go-metrics-interface"
)

var durationHistogramBuckets = []float64{0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60, 120, 240, 480, 960, 1920}

type ctxKeyT string

var ctxKey ctxKeyT = ctxKeyT(imetrics.CtxScopeKey)

func requestsInFlight(ctx context.Context) imetrics.Gauge {
return imetrics.NewCtx(ctx, "httpnet_requests_in_flight", "Current number of in-flight requests").Gauge()
}

func requestsTotal(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_requests_total", "Total request count").Counter()
}

func requestsFailure(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_requests_failure", "Failed (no response, dial error etc) requests count").Counter()
}

func requestsBodyFailure(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_requests_body_failure", "Failure count when reading response body").Counter()
}

func statusNotFound(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_404", "Request count with NotFound status").Counter()
}

func statusGone(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_410", "Request count with Gone status").Counter()
}

func statusForbidden(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_403", "Request count with Forbidden status").Counter()
}

func statusUnavailableForLegalReasons(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_451", "Request count with Unavailable For Legal Reasons status").Counter()
}

func statusOK(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_200", "Request count with OK status").Counter()
}

func statusTooManyRequests(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_429", "Request count with Too Many Requests status").Counter()
}

func statusServiceUnavailable(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_503", "Request count with Service Unavailable status").Counter()
}

func statusInternalServerError(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_500", "Request count with Internal Server Error status").Counter()
}

func statusOthers(ctx context.Context) imetrics.Counter {
return imetrics.NewCtx(ctx, "httpnet_status_others", "Request count with other status codes").Counter()
}

func requestTime(ctx context.Context) imetrics.Histogram {
return imetrics.NewCtx(ctx, "httpnet_request_duration_seconds", "Histogram of request durations").Histogram(durationHistogramBuckets)
}

type metrics struct {
RequestsInFlight imetrics.Gauge
RequestsTotal imetrics.Counter
RequestsFailure imetrics.Counter
RequestsBodyFailure imetrics.Counter
StatusNotFound imetrics.Counter
StatusGone imetrics.Counter
StatusForbidden imetrics.Counter
StatusUnavailableForLegalReasons imetrics.Counter
StatusOK imetrics.Counter
StatusTooManyRequests imetrics.Counter
StatusServiceUnavailable imetrics.Counter
StatusInternalServerError imetrics.Counter
StatusOthers imetrics.Counter
RequestTime imetrics.Histogram
}

func newMetrics() *metrics {
ctx := context.WithValue(context.Background(), ctxKey, "exchange")

return &metrics{
RequestsInFlight: requestsInFlight(ctx),
RequestsTotal: requestsTotal(ctx),
RequestsFailure: requestsFailure(ctx),
RequestsBodyFailure: requestsBodyFailure(ctx),
StatusNotFound: statusNotFound(ctx),
StatusGone: statusGone(ctx),
StatusForbidden: statusForbidden(ctx),
StatusUnavailableForLegalReasons: statusUnavailableForLegalReasons(ctx),
StatusOK: statusOK(ctx),
StatusTooManyRequests: statusTooManyRequests(ctx),
StatusServiceUnavailable: statusServiceUnavailable(ctx),
StatusInternalServerError: statusInternalServerError(ctx),
StatusOthers: statusOthers(ctx),
RequestTime: requestTime(ctx),
}
}

func (m *metrics) updateStatusCounter(statusCode int) {
m.RequestsTotal.Inc()
switch statusCode {
case 404:
m.StatusNotFound.Inc()
case 410:
m.StatusGone.Inc()
case 403:
m.StatusForbidden.Inc()
case 451:
m.StatusUnavailableForLegalReasons.Inc()
case 200:
m.StatusOK.Inc()
case 429:
m.StatusTooManyRequests.Inc()
case 503:
m.StatusServiceUnavailable.Inc()
case 500:
m.StatusInternalServerError.Inc()
default:
m.StatusOthers.Inc()
}
}
13 changes: 13 additions & 0 deletions bitswap/network/httpnet/msg_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,13 @@ func (sender *httpMsgSender) tryURL(ctx context.Context, u *senderURL, entry bsm

log.Debugf("%s %q", method, req.URL)
atomic.AddUint64(&sender.ht.stats.MessagesSent, 1)
reqStart := time.Now()
sender.ht.metrics.RequestsInFlight.Inc()
resp, err := sender.ht.client.Do(req)
if err != nil {
err = fmt.Errorf("error making request to %q: %w", req.URL, err)
sender.ht.metrics.RequestsFailure.Inc()
sender.ht.metrics.RequestsInFlight.Dec()
log.Debug(err)
// Something prevents us from making a request. We cannot
// dial, or setup the connection perhaps. This counts as
Expand Down Expand Up @@ -241,13 +245,22 @@ func (sender *httpMsgSender) tryURL(ctx context.Context, u *senderURL, entry bsm
if err != nil {
// treat this as server error
err = fmt.Errorf("error reading body from %q: %w", req.URL, err)
sender.ht.metrics.RequestsBodyFailure.Inc()
sender.ht.metrics.RequestsInFlight.Dec()
log.Debug(err)
return &senderError{
Type: typeServer,
Err: err,
}
}
reqDuration := time.Since(reqStart)

sender.ht.metrics.RequestsInFlight.Dec()
sender.ht.metrics.RequestTime.Observe(float64(reqDuration) / float64(time.Second))
sender.ht.metrics.updateStatusCounter(resp.StatusCode)

sender.ht.connEvtMgr.OnMessage(sender.peer)

switch resp.StatusCode {
// Valid responses signaling unavailability of the
// content.
Expand Down

0 comments on commit 016a7e5

Please sign in to comment.