forked from TrueCloudLab/rclone
fshttp: add prometheus metrics for HTTP status code
This patch adds rclone_http_status_code counter vector labeled by * host, * method, * code. It allows to see HTTP errors, backoffs etc. The Metrics struct is designed for extensibility. Adding new metrics is a matter of adding them to Metrics struct and including them in the response handling. This feature has been discussed in the forum [1]. [1] https://forum.rclone.org/t/prometheus-metrics/14484
This commit is contained in:
parent
ba6730720d
commit
38dc3e93ee
3 changed files with 67 additions and 4 deletions
|
@ -136,12 +136,14 @@ func NewClient(ctx context.Context) *http.Client {
|
||||||
// Transport is our http Transport which wraps an http.Transport
|
// Transport is our http Transport which wraps an http.Transport
|
||||||
// * Sets the User Agent
|
// * Sets the User Agent
|
||||||
// * Does logging
|
// * Does logging
|
||||||
|
// * Updates metrics
|
||||||
type Transport struct {
|
type Transport struct {
|
||||||
*http.Transport
|
*http.Transport
|
||||||
dump fs.DumpFlags
|
dump fs.DumpFlags
|
||||||
filterRequest func(req *http.Request)
|
filterRequest func(req *http.Request)
|
||||||
userAgent string
|
userAgent string
|
||||||
headers []*fs.HTTPOption
|
headers []*fs.HTTPOption
|
||||||
|
metrics *Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTransport wraps the http.Transport passed in and logs all
|
// newTransport wraps the http.Transport passed in and logs all
|
||||||
|
@ -152,6 +154,7 @@ func newTransport(ci *fs.ConfigInfo, transport *http.Transport) *Transport {
|
||||||
dump: ci.Dump,
|
dump: ci.Dump,
|
||||||
userAgent: ci.UserAgent,
|
userAgent: ci.UserAgent,
|
||||||
headers: ci.Headers,
|
headers: ci.Headers,
|
||||||
|
metrics: DefaultMetrics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +286,9 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
|
||||||
fs.Debugf(nil, "%s", separatorResp)
|
fs.Debugf(nil, "%s", separatorResp)
|
||||||
logMutex.Unlock()
|
logMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
// Update metrics
|
||||||
|
t.metrics.onResponse(req, resp)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
checkServerTime(req, resp)
|
checkServerTime(req, resp)
|
||||||
}
|
}
|
||||||
|
|
51
fs/fshttp/prometheus.go
Normal file
51
fs/fshttp/prometheus.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package fshttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Metrics provide Transport HTTP level metrics.
|
||||||
|
type Metrics struct {
|
||||||
|
StatusCode *prometheus.CounterVec
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetrics creates a new metrics instance, the instance shall be assigned to
|
||||||
|
// DefaultMetrics before any processing takes place.
|
||||||
|
func NewMetrics(namespace string) *Metrics {
|
||||||
|
return &Metrics{
|
||||||
|
StatusCode: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: "http",
|
||||||
|
Name: "status_code",
|
||||||
|
}, []string{"host", "method", "code"}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultMetrics specifies metrics used for new Transports.
|
||||||
|
var DefaultMetrics = (*Metrics)(nil)
|
||||||
|
|
||||||
|
// Collectors returns all prometheus metrics as collectors for registration.
|
||||||
|
func (m *Metrics) Collectors() []prometheus.Collector {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []prometheus.Collector{
|
||||||
|
m.StatusCode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metrics) onResponse(req *http.Request, resp *http.Response) {
|
||||||
|
if m == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusCode = 0
|
||||||
|
if resp != nil {
|
||||||
|
statusCode = resp.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
m.StatusCode.WithLabelValues(req.Host, req.Method, fmt.Sprint(statusCode)).Inc()
|
||||||
|
}
|
|
@ -18,23 +18,22 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rclone/rclone/fs/rc/webgui"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/skratchdot/open-golang/open"
|
|
||||||
|
|
||||||
"github.com/rclone/rclone/cmd/serve/httplib"
|
"github.com/rclone/rclone/cmd/serve/httplib"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/fs/accounting"
|
"github.com/rclone/rclone/fs/accounting"
|
||||||
"github.com/rclone/rclone/fs/cache"
|
"github.com/rclone/rclone/fs/cache"
|
||||||
"github.com/rclone/rclone/fs/config"
|
"github.com/rclone/rclone/fs/config"
|
||||||
|
"github.com/rclone/rclone/fs/fshttp"
|
||||||
"github.com/rclone/rclone/fs/list"
|
"github.com/rclone/rclone/fs/list"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/fs/rc/jobs"
|
"github.com/rclone/rclone/fs/rc/jobs"
|
||||||
"github.com/rclone/rclone/fs/rc/rcflags"
|
"github.com/rclone/rclone/fs/rc/rcflags"
|
||||||
|
"github.com/rclone/rclone/fs/rc/webgui"
|
||||||
"github.com/rclone/rclone/lib/http/serve"
|
"github.com/rclone/rclone/lib/http/serve"
|
||||||
"github.com/rclone/rclone/lib/random"
|
"github.com/rclone/rclone/lib/random"
|
||||||
|
"github.com/skratchdot/open-golang/open"
|
||||||
)
|
)
|
||||||
|
|
||||||
var promHandler http.Handler
|
var promHandler http.Handler
|
||||||
|
@ -43,6 +42,13 @@ var onlyOnceWarningAllowOrigin sync.Once
|
||||||
func init() {
|
func init() {
|
||||||
rcloneCollector := accounting.NewRcloneCollector(context.Background())
|
rcloneCollector := accounting.NewRcloneCollector(context.Background())
|
||||||
prometheus.MustRegister(rcloneCollector)
|
prometheus.MustRegister(rcloneCollector)
|
||||||
|
|
||||||
|
m := fshttp.NewMetrics("rclone")
|
||||||
|
for _, c := range m.Collectors() {
|
||||||
|
prometheus.MustRegister(c)
|
||||||
|
}
|
||||||
|
fshttp.DefaultMetrics = m
|
||||||
|
|
||||||
promHandler = promhttp.Handler()
|
promHandler = promhttp.Handler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue